Email ¶
mail.Message represents an envelope and its text/HTML content. mail.Sender
validates messages before dispatching to an explicit mail.Transport. Delivery
is synchronous and context-aware. Construction performs no network activity.
sender := mail.Sender{Transport: mail.SMTP{
Address: "smtp.example.com:587",
Username: smtpUsername,
Password: smtpPassword,
}}
err := sender.Send(ctx, mail.Message{
From: "App <app@example.com>",
To: []string{"recipient@example.com"},
Subject: "Account invitation",
Text: "Your account is ready.",
HTML: "<p>Your account is ready.</p>",
})Credentials and recipients come from application configuration or trusted data.
The account starter wires recovery delivery in project/accounts.go; the
authentication guide lists its environment settings.
Ask your agent ¶
Read https://cicadel.fauzaanu.com/en/dev/topics/email/index.md.
Add email delivery for [event] using Cicadel mail.Sender.
Read SMTP credentials from secret configuration, send after successful persistence,
and test recipients and message content with an in-memory transport.Message and MIME contract ¶
Messages support To, Cc, Bcc, ReplyTo, plain text, HTML alternatives,
attachments and extension headers. Bcc addresses are used only for the SMTP
envelope and never appear in serialized MIME. Message.Bytes() validates and
serializes the message with Date, Message-ID, UTF-8 headers, quoted-printable
bodies, multipart alternatives and base64 attachments. MIME parts use CRLF and
standard line wrapping. The sender mailbox and recipient mailboxes are parsed,
and CR/LF/NUL header injection is rejected.
message.Attachments = []mail.Attachment{{
Filename: "report.csv",
ContentType: "text/csv",
Data: csvBytes,
}}
message.Headers = map[string]string{"X-Application": "reports"}Attachment names cannot include path separators. Bytes are application-provided; this API does not read arbitrary filesystem paths. Extra headers accept X-* headers, Message-ID, In-Reply-To and References; they cannot override envelope, MIME or Bcc fields. Duplicate case-insensitive header names are rejected. Callers own attachment size limits and must not mutate messages during a send.
Use mail.RenderComponent(ctx, message, content) to render compiled typed UI into
the HTML body; supply message.Text explicitly for a text alternative. Existing
mail.Render remains a compatibility helper for separate Go text and escaped
HTML templates. Neither helper converts arbitrary user HTML into trusted markup.
Email client CSS support differs from browser CSS; tailor email components to
the intended email clients.
SMTP and batches ¶
SMTP.Encryption defaults to starttls, requiring STARTTLS and certificate
verification. tls supports implicit TLS, commonly port 465. A cloned
TLSConfig can supply a private certificate pool; disabling verification is
rejected and the minimum TLS version is 1.2. Credentials are sent only after TLS.
Explicit plain mode is limited to an actual loopback destination and refuses
credentials; it is for local mail capture tools.
The default timeout is 30 seconds for the batch. Context cancellation closes the
connection, including while awaiting an SMTP response. Sender.SendMany validates
the full input before delivery and reuses one SMTP connection when supported.
It returns the number accepted before an error. A failed QUIT after all DATA
commands were accepted does not make those messages failed sends. A connection
failure during DATA acknowledgement can leave delivery uncertain; the caller
owns its retry/idempotency policy. The framework does not silently retry or
silently swallow delivery errors.
Development backends ¶
| Backend | Behavior |
|---|---|
mail.Capture | Thread-safe in-memory outbox with deep copies on write and read |
&mail.Console{Writer: writer} | Serialized MIME to an explicit writer, with synchronized writes |
mail.File{Directory: path} | One mode-0600 .eml file per message in a private directory |
mail.Discard{} | Explicitly validate without delivery |
Custom mail.Transport | Implement Send(context.Context, mail.Message) error |
Console/file messages include private bodies and reset links. Select them explicitly for development; the accounts starter uses SMTP. Writers, filesystems, credentials and provider accounts remain application-owned. No application email is sent by tests: the SMTP tests use isolated loopback servers with locally created certificates, and account tests inject a capture callback.
mail/delivery_test.go verifies MIME parsing, attachment decoding, Bcc privacy,
header rejection, outbox isolation, file permissions, STARTTLS/implicit TLS,
connection reuse, partial delivery, failed upgrades and cancellation. Run the
package under the race detector alongside the framework CI suite.