package services import ( "bytes" "fmt" "html/template" "time" "github.com/rs/zerolog/log" "gopkg.in/gomail.v2" "github.com/treytartt/mycrib-api/internal/config" ) // EmailService handles sending emails type EmailService struct { cfg *config.EmailConfig dialer *gomail.Dialer } // NewEmailService creates a new email service func NewEmailService(cfg *config.EmailConfig) *EmailService { dialer := gomail.NewDialer(cfg.Host, cfg.Port, cfg.User, cfg.Password) return &EmailService{ cfg: cfg, dialer: dialer, } } // SendEmail sends an email func (s *EmailService) SendEmail(to, subject, htmlBody, textBody string) error { m := gomail.NewMessage() m.SetHeader("From", s.cfg.From) m.SetHeader("To", to) m.SetHeader("Subject", subject) m.SetBody("text/plain", textBody) m.AddAlternative("text/html", htmlBody) if err := s.dialer.DialAndSend(m); err != nil { log.Error().Err(err).Str("to", to).Str("subject", subject).Msg("Failed to send email") return fmt.Errorf("failed to send email: %w", err) } log.Info().Str("to", to).Str("subject", subject).Msg("Email sent successfully") return nil } // SendWelcomeEmail sends a welcome email with verification code func (s *EmailService) SendWelcomeEmail(to, firstName, code string) error { subject := "Welcome to MyCrib - Verify Your Email" name := firstName if name == "" { name = "there" } htmlBody := fmt.Sprintf(`

Welcome to MyCrib!

Hi %s,

Thank you for creating a MyCrib account. To complete your registration, please verify your email address by entering the following code:

%s

This code will expire in 24 hours.

If you didn't create a MyCrib account, you can safely ignore this email.

Best regards,
The MyCrib Team

`, name, code, time.Now().Year()) textBody := fmt.Sprintf(` Welcome to MyCrib! Hi %s, Thank you for creating a MyCrib account. To complete your registration, please verify your email address by entering the following code: %s This code will expire in 24 hours. If you didn't create a MyCrib account, you can safely ignore this email. Best regards, The MyCrib Team `, name, code) return s.SendEmail(to, subject, htmlBody, textBody) } // SendVerificationEmail sends an email verification code func (s *EmailService) SendVerificationEmail(to, firstName, code string) error { subject := "MyCrib - Verify Your Email" name := firstName if name == "" { name = "there" } htmlBody := fmt.Sprintf(`

Verify Your Email

Hi %s,

Please use the following code to verify your email address:

%s

This code will expire in 24 hours.

If you didn't request this, you can safely ignore this email.

Best regards,
The MyCrib Team

`, name, code, time.Now().Year()) textBody := fmt.Sprintf(` Verify Your Email Hi %s, Please use the following code to verify your email address: %s This code will expire in 24 hours. If you didn't request this, you can safely ignore this email. Best regards, The MyCrib Team `, name, code) return s.SendEmail(to, subject, htmlBody, textBody) } // SendPasswordResetEmail sends a password reset email func (s *EmailService) SendPasswordResetEmail(to, firstName, code string) error { subject := "MyCrib - Password Reset Request" name := firstName if name == "" { name = "there" } htmlBody := fmt.Sprintf(`

Password Reset Request

Hi %s,

We received a request to reset your password. Use the following code to complete the reset:

%s

This code will expire in 15 minutes.

Security Notice: If you didn't request a password reset, please ignore this email. Your password will remain unchanged.

Best regards,
The MyCrib Team

`, name, code, time.Now().Year()) textBody := fmt.Sprintf(` Password Reset Request Hi %s, We received a request to reset your password. Use the following code to complete the reset: %s This code will expire in 15 minutes. SECURITY NOTICE: If you didn't request a password reset, please ignore this email. Your password will remain unchanged. Best regards, The MyCrib Team `, name, code) return s.SendEmail(to, subject, htmlBody, textBody) } // SendPasswordChangedEmail sends a password changed confirmation email func (s *EmailService) SendPasswordChangedEmail(to, firstName string) error { subject := "MyCrib - Your Password Has Been Changed" name := firstName if name == "" { name = "there" } htmlBody := fmt.Sprintf(`

Password Changed

Hi %s,

Your MyCrib password was successfully changed on %s.

Didn't make this change? If you didn't change your password, please contact us immediately at support@mycrib.com or reset your password.

Best regards,
The MyCrib Team

`, name, time.Now().UTC().Format("January 2, 2006 at 3:04 PM UTC"), time.Now().Year()) textBody := fmt.Sprintf(` Password Changed Hi %s, Your MyCrib password was successfully changed on %s. DIDN'T MAKE THIS CHANGE? If you didn't change your password, please contact us immediately at support@mycrib.com or reset your password. Best regards, The MyCrib Team `, name, time.Now().UTC().Format("January 2, 2006 at 3:04 PM UTC")) return s.SendEmail(to, subject, htmlBody, textBody) } // EmailTemplate represents an email template type EmailTemplate struct { name string template *template.Template } // ParseTemplate parses an email template from a string func ParseTemplate(name, tmpl string) (*EmailTemplate, error) { t, err := template.New(name).Parse(tmpl) if err != nil { return nil, err } return &EmailTemplate{name: name, template: t}, nil } // Execute executes the template with the given data func (t *EmailTemplate) Execute(data interface{}) (string, error) { var buf bytes.Buffer if err := t.template.Execute(&buf, data); err != nil { return "", err } return buf.String(), nil }