// Package mail - SMTP email sender. package mail import ( "crypto/tls" "fmt" "net/smtp" ) type SMTPConfig struct { Host string // e.g., "smtp.gmail.com" Port int // e.g., 587 for TLS, 465 for SSL Username string // SMTP auth username Password string // SMTP auth password From string // From address for emails } type SMTPSender struct { config SMTPConfig } func NewSMTPSender(config SMTPConfig) *SMTPSender { return &SMTPSender{config: config} } func (s *SMTPSender) Send(email, subject, body string) error { message := fmt.Sprintf("From: %s\r\nTo: %s\r\nSubject: %s\r\n\r\n%s", s.config.From, email, subject, body) addr := fmt.Sprintf("%s:%d", s.config.Host, s.config.Port) auth := smtp.PlainAuth("", s.config.Username, s.config.Password, s.config.Host) // Use TLS tlsConfig := &tls.Config{ ServerName: s.config.Host, } conn, err := tls.Dial("tcp", addr, tlsConfig) if err != nil { return fmt.Errorf("dial: %w", err) } defer conn.Close() client, err := smtp.NewClient(conn, s.config.Host) if err != nil { return fmt.Errorf("create client: %w", err) } defer client.Quit() if err := client.Auth(auth); err != nil { return fmt.Errorf("auth: %w", err) } if err := client.Mail(s.config.From); err != nil { return fmt.Errorf("mail from: %w", err) } if err := client.Rcpt(email); err != nil { return fmt.Errorf("rcpt to: %w", err) } w, err := client.Data() if err != nil { return fmt.Errorf("data: %w", err) } _, err = w.Write([]byte(message)) if err != nil { return fmt.Errorf("write: %w", err) } if err := w.Close(); err != nil { return fmt.Errorf("close: %w", err) } return nil }