package email import ( "bytes" "crypto/tls" "errors" "fmt" "net/smtp" "os" "os/exec" ) const ( from = "root@tilde.town" SMTPHost = "smtp.zoho.com" SMTPPort = 465 ) func LoadPassword() (string, error) { f, err := os.Open("/town/docs/smtp.pw") if err != nil { return "", fmt.Errorf("could not open smtp password file: %w", err) } pw := make([]byte, 100) n, err := f.Read(pw) if err != nil { return "", fmt.Errorf("could not read smtp password file: %w", err) } if n == 0 { return "", errors.New("smtp password file was empty") } return string(pw[0:n]), nil } 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, subject, body string) error { headers := map[string]string{ "From": from, "To": address, "Subject": subject, } message := "" for k, v := range headers { message += fmt.Sprintf("%s: %s\r\n", k, v) } message += "\r\n" + body auth := smtp.PlainAuth("", from, m.Password, SMTPHost) server := fmt.Sprintf("%s:%d", SMTPHost, SMTPPort) tlsconf := &tls.Config{ InsecureSkipVerify: true, ServerName: server, } conn, err := tls.Dial("tcp", server, tlsconf) if err != nil { return err } c, err := smtp.NewClient(conn, SMTPHost) if err != nil { return err } if err = c.Auth(auth); err != nil { return fmt.Errorf("auth failed for smtp: %w", err) } if err = c.Mail(from); err != nil { return err } if err = c.Rcpt(address); err != nil { return err } w, err := c.Data() if err != nil { return err } _, err = w.Write([]byte(message)) if err != nil { return err } w.Close() c.Quit() return nil }