package email import ( "fmt" "net/smtp" "git.dustin.coffee/hobokenchicken/dumpsterChat/internal/config" ) type Mailer struct { cfg config.SMTPConfig } func NewMailer(cfg config.SMTPConfig) *Mailer { return &Mailer{cfg: cfg} } func (m *Mailer) Send(to, subject, body string) error { if m.cfg.Host == "" || m.cfg.Port == "" { return fmt.Errorf("SMTP is not configured") } auth := smtp.PlainAuth("", m.cfg.Username, m.cfg.Password, m.cfg.Host) msg := []byte("To: " + to + "\r\n" + "Subject: " + subject + "\r\n" + "Content-Type: text/html; charset=UTF-8\r\n" + "\r\n" + body + "\r\n") addr := m.cfg.Host + ":" + m.cfg.Port // Some servers (like STARTTLS on 587) require standard Dial, then StartTLS // We'll use smtp.SendMail which does STARTTLS automatically if the server supports it err := smtp.SendMail(addr, auth, m.cfg.Username, []string{to}, msg) if err != nil { // If standard SendMail fails due to TLS issues, fallback to manual TLS/STARTTLS if needed // But smtp.SendMail is usually sufficient for standard STARTTLS on port 587. return fmt.Errorf("failed to send email: %w", err) } return nil } func (m *Mailer) SendVerificationEmail(to, username, token, appURL string) error { subject := "Verify your dumpsterChat email" link := fmt.Sprintf("%s/verify-email?token=%s", appURL, token) body := fmt.Sprintf(`
Please verify your email address by clicking the link below:
If you did not sign up for this account, you can safely ignore this email.
`, username, link, link) return m.Send(to, subject, body) } func (m *Mailer) SendPasswordResetEmail(to, username, token, appURL string) error { subject := "Reset your dumpsterChat password" link := fmt.Sprintf("%s/reset-password?token=%s", appURL, token) body := fmt.Sprintf(`Hi %s,
We received a request to reset your password. Click the link below to set a new password:
If you did not request this, please ignore this email.
`, username, link, link) return m.Send(to, subject, body) } func (m *Mailer) SendAnnouncement(to, subject, body string) error { return m.Send(to, subject, body) }