Skip to content

Email

The email package sends HTML emails over SMTP and registers a Mailer as an injectable dependency.

The Mailer interface

type Mailer interface {
	Mail(*Message) error
}

type Message struct {
	From     string
	Subject  string
	To       []string
	HTMLBody string
}

SMTPMailer is the built-in implementation. NewSMTPMailer(host, port, username, password, from) dials the SMTP server with a one-minute timeout, and Mail sends a Message (falling back to the mailer’s from when the message has none).

Registering

Register(ctx, config) registers a lazy singleton Mailer built from a Config — a type with a Mailer() Mailer method. SMTPConfig implements it from the usual fields:

kernel.Register(func(ctx context.Context, c *config.Config) {
	email.Register(ctx, c.Mail)
})

The generated config.Config.Mail is an *email.SMTPConfig populated from environment variables:

Mail: &email.SMTPConfig{
	From:     env.String("MAIL_FROM", "[email protected]"),
	Host:     env.String("MAIL_HOST", "sandbox.smtp.mailtrap.io"),
	Port:     env.Int("MAIL_PORT", 2525),
	Username: env.String("MAIL_USERNAME", "user"),
	Password: env.String("MAIL_PASSWORD", "pass"),
},

Sending mail

Inject email.Mailer and call Mail. Combining it with the view package is the common pattern — render a template to bytes and send it:

type EmailHandler struct {
	Mailer email.Mailer `inject:""`
}

func (h *EmailHandler) Send(ctx context.Context, to, name string) error {
	body, err := view.View("welcome.html", map[string]string{"Name": name}).Bytes(ctx)
	if err != nil {
		return err
	}
	return h.Mailer.Mail(&email.Message{
		To:       []string{to},
		Subject:  "Welcome",
		HTMLBody: string(body),
	})
}

The auth package uses this to send verification and password-reset emails.

Testing

The email/emailtest subpackage provides a TestMailer that records sent messages in memory instead of dialing SMTP. NewTestMailerConfig plugs it into email.Register so tests can assert on EmailsSent():

mailer := emailtest.NewTestMailer()
email.Register(ctx, emailtest.NewTestMailerConfig())
// ...
assert.Len(t, mailer.EmailsSent(), 1)