Golar v0.5.1

Mail

github.com/dayanchm/golar/mail builds and sends email. A Mailer sends a Message; drivers deliver it over SMTP, print it to the log or record it for tests.

mailer, err := mail.FromEnv() // MAIL_DRIVER, MAIL_HOST, ...
err = mailer.Send(ctx, mail.Message{
    To:      []string{"Ayşe <ayse@example.com>"},
    Subject: "Welcome",
    Text:    "Thanks for signing up.",
    HTML:    "<p>Thanks for signing up.</p>",
})

Messages

Field Notes
From required; mail.WithFrom and FromEnv fill it when empty
To, Cc, Bcc at least one recipient; Bcc never appears in headers
ReplyTo optional
Subject required, one line; non-ASCII is encoded
Text, HTML at least one; both are sent as multipart/alternative
Headers extra headers such as List-Unsubscribe; cannot replace the ones above

Addresses may include display names. Validate rejects unparsable addresses and any CR or LF in the subject or headers, so user input cannot add headers or recipients. Bytes returns the encoded MIME message.

Drivers

SMTP

mailer := &mail.SMTP{
    Host:       "smtp.example.com",
    Port:       587,               // default; 465 with TLS
    Username:   "apikey",
    Password:   os.Getenv("MAIL_PASSWORD"),
    Encryption: mail.StartTLS,     // default; mail.TLS or mail.None
}

With StartTLS the server must offer STARTTLS and its certificate must be valid; the connection is never downgraded to plain text. TLS connects with implicit TLS. None is for local catchers such as Mailpit; credentials are then only sent to localhost. Timeout (30 seconds) and the context bound the whole delivery. Each Send opens one connection.

Log

mail.Log{} prints the sender, recipients, subject and text body to the standard logger, so links can be followed in development. Do not use it in production.

Fake

fake := mail.NewFake()
// ... run code that sends mail through fake ...
m := fake.AssertSent(t, "ayse@example.com") // latest message to that address
fake.AssertCount(t, 1)
fake.AssertNothingSent(t)

Fake validates and records messages without a network. Messages, SentTo and Reset inspect and clear them; set Err to make sends fail.

Configuration

mail.FromEnv() reads:

Variable Default Notes
MAIL_DRIVER log log or smtp
MAIL_HOST required for smtp
MAIL_PORT 587, or 465 with tls
MAIL_USERNAME, MAIL_PASSWORD optional
MAIL_ENCRYPTION starttls starttls, tls or none
MAIL_FROM_ADDRESS required default sender
MAIL_FROM_NAME optional sender name

Invalid values return an error at startup instead of failing on the first send.

Templates

var welcome = mail.MustTemplate(
    "Welcome to {{.App}}",
    "Hello {{.Name}}, thanks for joining {{.App}}.",
    "<p>Hello {{.Name}}, thanks for joining {{.App}}.</p>",
)

m, err := welcome.Render(map[string]string{"App": "Demo", "Name": name})
m.To = []string{email}
err = mailer.Send(ctx, m)

The subject and text body use text/template; the HTML body uses html/template, which escapes data. Templates fail on missing keys. Rendered subjects are joined onto one line. Build a mail.Template from template.ParseFS results to keep templates in files.

Password reset and verification emails

auth.PasswordResetMail and auth.VerificationMail turn a mailer into the Send functions of auth.PasswordBroker and auth.EmailVerification:

broker := &auth.PasswordBroker{
    Provider: users,
    Store:    &auth.SQLResetStore{DB: db},
    Send: auth.PasswordResetMail{
        Mailer:  mailer,
        URL:     "https://app.example.com/reset-password", // ?token=…&email=… is added
        AppName: "Demo",
    }.Send,
}
verification := &auth.EmailVerification{
    Secret:   []byte(os.Getenv("APP_KEY")),
    Provider: users,
    Send: auth.VerificationMail{
        Mailer: mailer,
        URL:    "https://app.example.com/api/auth/verify-email", // ?token=… is added
    }.Send,
}

URL must be absolute. The default templates are auth.DefaultResetTemplate and auth.DefaultVerificationTemplate; set Template to use your own, with the fields of auth.LinkMail (AppName, Email, Link). Reset emails need users with an AuthEmail() string method.

Generated projects

Projects with authentication read MAIL_*, APP_URL and APP_KEY from .env. golar new writes a random APP_KEY and MAIL_DRIVER=log, so reset and verification links appear in the server log. Set MAIL_DRIVER=smtp and the MAIL_HOST variables to deliver them. Tests pass a fake mailer to bootstrap.NewWithDB(db, mail.WithFrom(fake, "test@example.com")) and read the links from fake.AssertSent.

Edit this page on GitHub