feat: implement core Go application with web server
- Add Go modules with required dependencies (Gin, UUID, JWT, etc.) - Implement main web server with landing page endpoint - Add comprehensive API endpoints for health and status - Include proper error handling and request validation - Set up CORS middleware and security headers
This commit is contained in:
278
output/internal/services/email_service.go
Normal file
278
output/internal/services/email_service.go
Normal file
@@ -0,0 +1,278 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net/smtp"
|
||||
"time"
|
||||
|
||||
"github.com/ydn/yourdreamnamehere/internal/config"
|
||||
)
|
||||
|
||||
type EmailService struct {
|
||||
config *config.Config
|
||||
auth smtp.Auth
|
||||
}
|
||||
|
||||
func NewEmailService(config *config.Config) *EmailService {
|
||||
auth := smtp.PlainAuth("", config.Email.SMTPUser, config.Email.SMTPPassword, config.Email.SMTPHost)
|
||||
|
||||
return &EmailService{
|
||||
config: config,
|
||||
auth: auth,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *EmailService) SendWelcomeEmail(to, firstName string) error {
|
||||
subject := "Welcome to YourDreamNameHere!"
|
||||
body := fmt.Sprintf(`
|
||||
Dear %s,
|
||||
|
||||
Welcome to YourDreamNameHere! Your sovereign data hosting journey begins now.
|
||||
|
||||
What happens next:
|
||||
1. Your domain will be registered through our OVH partner
|
||||
2. A VPS will be provisioned and configured for you
|
||||
3. Cloudron will be installed on your VPS
|
||||
4. You'll receive an email invitation to complete your Cloudron setup
|
||||
|
||||
This entire process typically takes 30-60 minutes. You'll receive updates at each step.
|
||||
|
||||
If you have any questions, please don't hesitate to contact our support team.
|
||||
|
||||
Best regards,
|
||||
The YourDreamNameHere Team
|
||||
`, firstName)
|
||||
|
||||
return s.sendEmail(to, subject, body)
|
||||
}
|
||||
|
||||
func (s *EmailService) SendAdminInvitation(to, domainName, cloudronURL, token string) error {
|
||||
subject := "Complete Your Cloudron Setup"
|
||||
body := fmt.Sprintf(`
|
||||
Your Cloudron instance is ready!
|
||||
|
||||
Domain: %s
|
||||
Cloudron URL: %s
|
||||
|
||||
To complete your setup, please click the link below:
|
||||
https://yourdreamnamehere.com/invitation/%s
|
||||
|
||||
This link will expire in 7 days.
|
||||
|
||||
What you'll need to do:
|
||||
1. Set your administrator password
|
||||
2. Configure your organization details
|
||||
3. Choose your initial applications
|
||||
|
||||
If you have any questions or need assistance, please contact our support team.
|
||||
|
||||
Best regards,
|
||||
The YourDreamNameHere Team
|
||||
`, domainName, cloudronURL, token)
|
||||
|
||||
return s.sendEmail(to, subject, body)
|
||||
}
|
||||
|
||||
func (s *EmailService) SendDeploymentUpdate(to, domainName, step, status string) error {
|
||||
subject := fmt.Sprintf("Deployment Update for %s", domainName)
|
||||
|
||||
var statusMessage string
|
||||
switch status {
|
||||
case "completed":
|
||||
statusMessage = "✅ Completed successfully"
|
||||
case "failed":
|
||||
statusMessage = "❌ Failed"
|
||||
case "in_progress":
|
||||
statusMessage = "🔄 In progress"
|
||||
default:
|
||||
statusMessage = "ℹ️ " + status
|
||||
}
|
||||
|
||||
body := fmt.Sprintf(`
|
||||
Deployment Update for %s
|
||||
|
||||
Current Step: %s
|
||||
Status: %s
|
||||
|
||||
`, domainName, step, statusMessage)
|
||||
|
||||
switch step {
|
||||
case "domain_registration":
|
||||
body += `
|
||||
Your domain registration is being processed. This typically takes a few minutes to complete.
|
||||
`
|
||||
case "vps_provisioning":
|
||||
body += `
|
||||
Your Virtual Private Server is being provisioned. This includes setting up the base operating system and security configurations.
|
||||
`
|
||||
case "cloudron_install":
|
||||
body += `
|
||||
Cloudron is being installed on your VPS. This is the most time-consuming step and can take 20-30 minutes.
|
||||
`
|
||||
case "deployment_complete":
|
||||
body += `
|
||||
🎉 Congratulations! Your sovereign data hosting environment is now ready!
|
||||
|
||||
You should receive a separate email with your administrator invitation to complete the Cloudron setup.
|
||||
`
|
||||
}
|
||||
|
||||
body += `
|
||||
|
||||
You can track the progress of your deployment by logging into your account at:
|
||||
https://yourdreamnamehere.com/dashboard
|
||||
|
||||
Best regards,
|
||||
The YourDreamNameHere Team
|
||||
`
|
||||
|
||||
return s.sendEmail(to, subject, body)
|
||||
}
|
||||
|
||||
func (s *EmailService) SendPaymentConfirmation(to, domainName string) error {
|
||||
subject := "Payment Confirmation - YourDreamNameHere"
|
||||
body := fmt.Sprintf(`
|
||||
Payment Confirmation
|
||||
|
||||
Thank you for your payment! Your subscription for %s is now active.
|
||||
|
||||
Subscription Details:
|
||||
- Domain: %s
|
||||
- Plan: Sovereign Data Hosting
|
||||
- Amount: $250.00 USD
|
||||
- Billing: Monthly
|
||||
|
||||
What's Next:
|
||||
Your deployment process will begin immediately. You'll receive email updates as each step completes.
|
||||
|
||||
If you have any questions, please contact our support team.
|
||||
|
||||
Best regards,
|
||||
The YourDreamNameHere Team
|
||||
`, domainName, domainName)
|
||||
|
||||
return s.sendEmail(to, subject, body)
|
||||
}
|
||||
|
||||
func (s *EmailService) SendSubscriptionRenewalNotice(to, domainName string) error {
|
||||
subject := "Subscription Renewal Notice - YourDreamNameHere"
|
||||
body := fmt.Sprintf(`
|
||||
Subscription Renewal Notice
|
||||
|
||||
This is a friendly reminder that your subscription for %s will be renewed soon.
|
||||
|
||||
Subscription Details:
|
||||
- Domain: %s
|
||||
- Plan: Sovereign Data Hosting
|
||||
- Amount: $250.00 USD
|
||||
- Next Billing Date: %s
|
||||
|
||||
Your subscription will be automatically renewed using your payment method on file.
|
||||
|
||||
If you need to update your payment information or have any questions, please contact our support team.
|
||||
|
||||
Best regards,
|
||||
The YourDreamNameHere Team
|
||||
`, domainName, domainName, getNextBillingDate())
|
||||
|
||||
return s.sendEmail(to, subject, body)
|
||||
}
|
||||
|
||||
func (s *EmailService) SendPasswordReset(to, resetToken string) error {
|
||||
subject := "Password Reset - YourDreamNameHere"
|
||||
body := fmt.Sprintf(`
|
||||
Password Reset Request
|
||||
|
||||
You requested a password reset for your YourDreamNameHere account.
|
||||
|
||||
Click the link below to reset your password:
|
||||
https://yourdreamnamehere.com/reset-password?token=%s
|
||||
|
||||
This link will expire in 1 hour.
|
||||
|
||||
If you didn't request this password reset, please ignore this email or contact our support team.
|
||||
|
||||
Best regards,
|
||||
The YourDreamNameHere Team
|
||||
`, resetToken)
|
||||
|
||||
return s.sendEmail(to, subject, body)
|
||||
}
|
||||
|
||||
func (s *EmailService) sendEmail(to, subject, body string) error {
|
||||
headers := make(map[string]string)
|
||||
headers["From"] = s.config.Email.From
|
||||
headers["To"] = to
|
||||
headers["Subject"] = subject
|
||||
headers["MIME-Version"] = "1.0"
|
||||
headers["Content-Type"] = "text/plain; charset=\"utf-8\""
|
||||
|
||||
message := ""
|
||||
for k, v := range headers {
|
||||
message += fmt.Sprintf("%s: %s\r\n", k, v)
|
||||
}
|
||||
message += "\r\n" + body
|
||||
|
||||
// Create SMTP connection with TLS
|
||||
client, err := s.createSMTPClient()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create SMTP client: %w", err)
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
// Set the sender and recipient
|
||||
if err := client.Mail(s.config.Email.From); err != nil {
|
||||
return fmt.Errorf("failed to set sender: %w", err)
|
||||
}
|
||||
|
||||
if err := client.Rcpt(to); err != nil {
|
||||
return fmt.Errorf("failed to set recipient: %w", err)
|
||||
}
|
||||
|
||||
// Send the email body
|
||||
w, err := client.Data()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create data writer: %w", err)
|
||||
}
|
||||
|
||||
_, err = w.Write([]byte(message))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to write email body: %w", err)
|
||||
}
|
||||
|
||||
if err := w.Close(); err != nil {
|
||||
return fmt.Errorf("failed to close data writer: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *EmailService) createSMTPClient() (*smtp.Client, error) {
|
||||
// Connect to SMTP server with TLS
|
||||
conn, err := tls.Dial("tcp", fmt.Sprintf("%s:%s", s.config.Email.SMTPHost, s.config.Email.SMTPPort), &tls.Config{
|
||||
ServerName: s.config.Email.SMTPHost,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to connect to SMTP server: %w", err)
|
||||
}
|
||||
|
||||
client, err := smtp.NewClient(conn, s.config.Email.SMTPHost)
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, fmt.Errorf("failed to create SMTP client: %w", err)
|
||||
}
|
||||
|
||||
// Authenticate
|
||||
if err := client.Auth(s.auth); err != nil {
|
||||
client.Close()
|
||||
return nil, fmt.Errorf("failed to authenticate: %w", err)
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func getNextBillingDate() string {
|
||||
// Return next month's date in a readable format
|
||||
return time.Now().AddDate(0, 1, 0).Format("January 2, 2006")
|
||||
}
|
||||
Reference in New Issue
Block a user