package clients import ( "fmt" "net/smtp" "crypto/tls" "github.com/spf13/viper" "github.com/rs/zerolog/log" ) type SMTPSettings struct { Host string Port int Username string Password string Encryption string // "tls", "ssl", "none" FromAddress string FromName string } var smtpSettings SMTPSettings func InitSMTPSettings() { smtpSettings = SMTPSettings{ Host: viper.GetString("smtp.host"), Port: viper.GetInt("smtp.port"), Username: viper.GetString("smtp.username"), Password: viper.GetString("smtp.password"), Encryption: viper.GetString("smtp.encryption"), FromAddress: viper.GetString("smtp.from_address"), FromName: viper.GetString("smtp.from_name"), } if smtpSettings.Host == "" || smtpSettings.Port == 0 || smtpSettings.FromAddress == "" { log.Warn().Msg("SMTP configuration incomplete. Email sending may not work.") } else { log.Info().Msgf("SMTP client initialized for %s:%d", smtpSettings.Host, smtpSettings.Port) } } func GetSMTPSettings() SMTPSettings { return smtpSettings } // SendEmail sends an email using the configured SMTP settings. func SendEmail(toAddress, subject, body string) error { if smtpSettings.Host == "" { return fmt.Errorf("SMTP client not initialized or host is empty") } addr := fmt.Sprintf("%s:%d", smtpSettings.Host, smtpSettings.Port) // Setup authentication auth := smtp.PlainAuth("", smtpSettings.Username, smtpSettings.Password, smtpSettings.Host) // Construct the email message mime := "MIME-version: 1.0;\nContent-Type: text/html; charset=\"UTF-8\";\n" msg := []byte("From: " + smtpSettings.FromName + " <" + smtpSettings.FromAddress + ">\r\n" + "To: " + toAddress + "\r\n" + "Subject: " + subject + "\r\n" + mime + "\r\n" + body + "\r\n") var err error switch smtpSettings.Encryption { case "tls": // TLS encryption err = sendMailTLS(addr, auth, smtpSettings.FromAddress, []string{toAddress}, msg) case "ssl": // SSL encryption (usually port 465) err = smtp.SendMail(addr, auth, smtpSettings.FromAddress, []string{toAddress}, msg) case "none": // No encryption (usually port 25 or 587 without STARTTLS) err = smtp.SendMail(addr, auth, smtpSettings.FromAddress, []string{toAddress}, msg) default: return fmt.Errorf("unsupported SMTP encryption type: %s", smtpSettings.Encryption) } if err != nil { return fmt.Errorf("failed to send email: %w", err) } log.Info().Msgf("Email sent successfully to %s", toAddress) return nil } // sendMailTLS sends an email over a TLS connection. func sendMailTLS(addr string, auth smtp.Auth, from string, to []string, msg []byte) error { conn, err := tls.Dial("tcp", addr, nil) if err != nil { return err } defer conn.Close() client, err := smtp.NewClient(conn, smtpSettings.Host) if err != nil { return err } defer client.Close() if auth != nil { if ok, _ := client.Extension("AUTH"); ok { if err = client.Auth(auth); err != nil { return err } } } if err = client.Mail(from); err != nil { return err } for _, addr := range to { if err = client.Rcpt(addr); err != nil { return err } } w, err := client.Data() if err != nil { return err } _, err = w.Write(msg) if err != nil { return err } err = w.Close() if err != nil { return err } return client.Quit() }