Documentation
¶
Overview ¶
Package mail sends email from a web app: a Mailer service apps inject, configured from the environment (or .env), with a log driver for development and tests and an SMTP driver for production.
app := web.New(mail.Provide()) // MAIL_DRIVER, MAIL_HOST, … from the environment
@web.Post("/signup")
func Signup(ctx context.Context, in NewUser, m *mail.Mailer) error {
return m.Send(ctx, mail.Message{
To: []string{in.Email},
Subject: "Welcome",
HTML: <Welcome name={in.Name} />, // the text part is made from it
})
}
The default driver, log, sends nothing: it logs each message and keeps it for Sent. In development the toolbar's Mail panel shows the messages a request sent, the HTML in a preview.
Index ¶
- Variables
- func Provide(cfg ...Config) web.Option
- type Attachment
- type Config
- type InvalidError
- type Mailer
- func (m *Mailer) Driver() string
- func (m *Mailer) Flush(ctx context.Context) error
- func (m *Mailer) Reset()
- func (m *Mailer) Send(ctx context.Context, msg Message) error
- func (m *Mailer) SendLater(ctx context.Context, msg Message) error
- func (m *Mailer) Sent() []Sent
- func (m *Mailer) Stop(ctx context.Context) error
- type Message
- type Sent
- type Transport
Constants ¶
This section is empty.
Variables ¶
var ErrQueueFull = errors.New("mail: the queue is full")
ErrQueueFull is SendLater's error when Config.Queue messages are waiting already.
Functions ¶
Types ¶
type Attachment ¶
type Attachment struct {
Filename string
ContentType string // from the file name's extension when empty
Data []byte
}
Attachment is a file sent with a message.
type Config ¶
type Config struct {
// Driver is "log" (the default: log the message, send nothing) or
// "smtp". Transport, when set, sends instead of either.
Driver string
Transport Transport
Host string
Port int // 0: 465 with tls, 587 with starttls, 25 with none
Username string
Password string
// Encryption is "starttls" (the default: upgrade the connection, and
// fail when the server can't), "tls" (TLS from the start, port 465) or
// "none" (local catchers only; the password isn't sent unencrypted
// except to localhost).
Encryption string
TLS *tls.Config // a private CA, or a test server's certificate
LocalName string // the name the client gives in EHLO; "localhost"
// Timeout bounds dialing the server, and each send when the context has
// no deadline of its own (six times as long). Default 10s.
Timeout time.Duration
From string // the sender when a message names none: "app@example.com" or "App <app@example.com>"
FromName string // its name, when From has none
// SendLater's retries after the first attempt (default 3) and the wait
// before the first, doubling after each (default 2s). Only temporary
// failures are retried: a 4xx answer, a connection that fails.
Retries int
Backoff time.Duration
// Queue bounds the messages SendLater holds at once, sending or
// waiting (default 1000): past it, SendLater refuses with ErrQueueFull
// rather than hold more in memory.
Queue int
Logger *slog.Logger // the log driver's and SendLater's; slog's default
}
Config configures a Mailer. ConfigFromEnv reads it from the environment.
func ConfigFromEnv ¶
func ConfigFromEnv() Config
ConfigFromEnv reads the configuration from the environment (and the env files web.New loaded): MAIL_DRIVER, MAIL_HOST, MAIL_PORT, MAIL_USERNAME, MAIL_PASSWORD, MAIL_ENCRYPTION, MAIL_FROM, MAIL_FROM_NAME. A MAIL_PORT that isn't a number fails the app's next Build or Start, naming it.
type InvalidError ¶
type InvalidError struct{ Reason string }
InvalidError is a message refused before sending: what is wrong with it.
func (*InvalidError) Error ¶
func (e *InvalidError) Error() string
type Mailer ¶
type Mailer struct {
// contains filtered or unexported fields
}
Mailer sends messages. It is safe for concurrent use.
func (*Mailer) Flush ¶
Flush waits until the messages SendLater queued are sent or given up, or ctx is done: for tests.
func (*Mailer) Send ¶
Send builds the message and sends it with the Mailer's driver. A message that isn't valid — no recipient, an address that doesn't parse, a line break in a header — is refused before anything is sent.
func (*Mailer) SendLater ¶
SendLater builds the message now — so it is refused now when invalid, and its HTML renders with ctx — and sends it in the background, retrying temporary failures (Config.Retries, Config.Backoff). A failure after the last attempt is logged. Stop waits for the messages still queued. Past Config.Queue messages held at once, it refuses with ErrQueueFull.
type Message ¶
type Message struct {
From string // the Mailer's From when empty
To []string
Cc []string
Bcc []string // receive it without being listed in it
ReplyTo string
Subject string
// Text is the plain-text body; made from HTML when empty.
Text string
// HTML is the HTML body: a JSX or templ component, or ui.Safe(html)
// for HTML you have as a string. It renders with Send's context.
HTML ui.Node
Headers map[string]string // more headers: List-Unsubscribe, X-Campaign, …
Attachments []Attachment
}
Message is an email. Every address is "user@example.com" or "Name <user@example.com>".
type Sent ¶
type Sent struct {
Message
From string // the sender, as written in the message
Recipients []string // every address it went to, Bcc included
HTML, Text string // the bodies, rendered
Raw []byte // the MIME message
At time.Time
}
Sent is a message the log driver kept: as given, and as built.