town/email/email.go

121 lines
2.0 KiB
Go

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
}