Gist: Send emails (via SMTP relay) in Go
Send emails (via SMTP relay) in Go
Last updated on: 2025-01-04
package mailx
import (
"bytes"
"log/slog"
"net/mail"
"net/smtp"
"strings"
)
type Emailer interface {
Email(*Message) error
}
type Message struct {
From mail.Address
To []string
Subject string
PlainTextBody string
}
type SMTPEmailer struct {
AuthUsername string // Ex: "myaccount@example.org".
AuthPassword string // Ex: "123456".
AuthHost string // Ex: "example.org".
RelayAddress string // Ex: "smtp.example.org:587"
}
func (e *SMTPEmailer) Email(msg *Message) error {
auth := smtp.PlainAuth("", e.AuthUsername, e.AuthPassword, e.AuthHost)
return smtp.SendMail(e.RelayAddress, auth, msg.From.Address, msg.To, DATA(msg))
}
// Generates a SMTP DATA string.
func DATA(e *Message) []byte {
d := &bytes.Buffer{}
d.WriteString("From: " + e.From.String() + "\r\n")
d.WriteString("To: " + strings.Join(e.To, "; ") + "\r\n")
d.WriteString("Subject: " + e.Subject + "\r\n")
d.WriteString("MIME-Version: " + "1.0" + "\r\n")
d.WriteString("Content-Type: " + "text/plain" + "\r\n")
d.WriteString("\r\n")
d.WriteString(e.PlainTextBody)
d.WriteString("\r\n")
return d.Bytes()
}
type MockEmailer struct {
Logger *slog.Logger // Mock emails will be logged here.
Err error // To mock failed send.
}
func (e *MockEmailer) Email(msg *Message) error {
e.Logger.Info("mock email",
"error", e.Err,
"from_name", msg.From.Name,
"from_address", msg.From.Address,
"to", msg.To,
"subject", msg.Subject,
"body", msg.PlainTextBody,
)
return e.Err
}