package email import ( "bytes" "crypto/tls" "fmt" "net" "net/mail" "net/smtp" "os/exec" ) const ( SMTPHost = "smtp.migadu.com" SMTPPort = 465 ) func SendLocalEmail(username, subject, body string) error { cmd := exec.Command("/usr/sbin/sendmail", username) cmd.Stdin = bytes.NewBufferString(fmt.Sprintf("Subject: %s\n\n%s", subject, body)) if err := cmd.Run(); err != nil { return fmt.Errorf("failed to send local email: %w", err) } return nil } type ExternalMailer struct { Password string } func NewExternalMailer(pw string) *ExternalMailer { if pw == "" { panic("why?") } return &ExternalMailer{ Password: pw, } } func (m *ExternalMailer) Send(address, subj, body string) error { from := mail.Address{Name: "Tilde Town Admins", Address: "root@tilde.town"} to := mail.Address{Name: "", Address: address} // Setup headers headers := make(map[string]string) headers["From"] = from.String() headers["To"] = to.String() headers["Subject"] = subj // Setup message message := "" for k, v := range headers { message += fmt.Sprintf("%s: %s\r\n", k, v) } message += "\r\n" + body // Connect to the SMTP Server servername := fmt.Sprintf("%s:%d", SMTPHost, SMTPPort) host, _, _ := net.SplitHostPort(servername) auth := smtp.PlainAuth("", "root@tilde.town", m.Password, host) // TLS config tlsconfig := &tls.Config{ InsecureSkipVerify: true, ServerName: host, } // Here is the key, you need to call tls.Dial instead of smtp.Dial // for smtp servers running on 465 that require an ssl connection // from the very beginning (no starttls) conn, err := tls.Dial("tcp", servername, tlsconfig) if err != nil { return fmt.Errorf("failed dial: %w", err) } c, err := smtp.NewClient(conn, host) if err != nil { return fmt.Errorf("failed to make smtp client: %w", err) } // Auth if err = c.Auth(auth); err != nil { return fmt.Errorf("failed to make auth: %w", err) } // To && From if err = c.Mail(from.Address); err != nil { return fmt.Errorf("failed to create mail: %w", err) } if err = c.Rcpt(to.Address); err != nil { return fmt.Errorf("failed to add rcpt: %w", err) } // Data w, err := c.Data() if err != nil { return fmt.Errorf("failed to send data: %w", err) } _, err = w.Write([]byte(message)) if err != nil { return fmt.Errorf("failed to write: %w", err) } err = w.Close() if err != nil { return fmt.Errorf("failed to close: %w", err) } c.Quit() return nil }