Documentation
¶
Overview ¶
Package email provides a provider-agnostic email transport layer.
The package exposes a small Transport interface that can be implemented by any backend. Out of the box it ships with:
- SMTP transport (works with Gmail, AWS SES, SendGrid, Mailgun, Postmark, and any other provider that exposes SMTP).
- Chain transport that tries multiple transports in order, providing primary/secondary/tertiary failover.
- LogOnly transport for local development when no SMTP is configured; it emits a structured WARN log with the recipient and subject so the developer can manually deliver the message.
A small templates sub-package embeds plain text+HTML templates for common transactional emails (password reset, email verification, invitations).
Index ¶
Constants ¶
const ( TemplatePasswordReset = "password_reset" TemplateEmailVerification = "email_verification" TemplateInvitation = "invitation" // TemplateTenantInvitation invites a recipient to join a redesign Tenant // (the company-governance entity), distinct from the admin-provisioning // TemplateInvitation. Carries the tenant name, the role offered, and the // raw-token acceptance link. TemplateTenantInvitation = "tenant_invitation" // TemplateEmailChangeVerify is sent to the *new* address with the // verification link to confirm the email change. TemplateEmailChangeVerify = "email_change_verify" // TemplateEmailChangeNotice is sent to the *old* address as a // security notice that an email change has been requested. TemplateEmailChangeNotice = "email_change_notice" // TemplateEmailLoginCode carries the 6-digit OTP for passwordless // email login. TemplateEmailLoginCode = "email_login_code" // TemplateMagicLink carries the clickable single-use sign-in link for // passwordless email login. TemplateMagicLink = "magic_link" )
Known template names. Keep this list in sync with templates/.
Variables ¶
var ( // ErrInvalidMessage is returned (wrapped) when a Message fails validation. ErrInvalidMessage = errors.New("email: invalid message") // ErrTransport is returned (wrapped) when an underlying transport fails. ErrTransport = errors.New("email: transport failure") )
Sentinel errors returned by the email package. Underlying errors are wrapped with %w so callers can use errors.Is to test against these sentinels.
Functions ¶
func Redact ¶ added in v0.6.7
Redact returns a privacy-safe representation of an email address for use in logs and metrics labels: the first character of the local part, asterisks for the rest, and the domain. "alice@example.com" becomes "a***@example.com". Inputs without an "@" are returned unchanged.
Logs at production scale store every "to" address indefinitely; raw emails in those streams put the service squarely on the GDPR fast-lane. Every code path that logs an email address MUST use Redact instead.
Types ¶
type Chain ¶
type Chain struct {
// OnAttempt, if non-nil, is invoked synchronously after each inner Send
// with the index of the transport and the error it returned (nil on
// success). Hook is intended for metrics; keep it cheap and non-blocking.
OnAttempt func(idx int, err error)
// contains filtered or unexported fields
}
Chain is a Transport that delegates to an ordered list of inner transports, trying each in turn until one succeeds. Use it for primary/secondary/tertiary failover across providers.
type Message ¶
type Message struct {
// To is the recipient address (RFC 5322). Exactly one recipient is
// supported; for multi-recipient sends, call Send once per recipient so
// each delivery can be tracked and retried independently.
To string
// From is the sender address (RFC 5322). May be left empty when using a
// transport that injects a default From (e.g. SMTPConfig.From).
From string
// Subject is the email subject line.
Subject string
// HTML is the HTML body. Optional if Text is set.
HTML string
// Text is the plain-text body. Optional if HTML is set.
Text string
// ReplyTo, when non-empty, is written as the Reply-To header (RFC 5322).
// Used to route replies to a product support address while keeping the
// transactional From address. Must parse as an address when set.
ReplyTo string
// ListUnsubscribe, when non-empty, is written verbatim as the
// List-Unsubscribe header (RFC 2369), e.g.
// "<mailto:unsubscribe@example.com>" or an https URL in angle brackets.
// Improves deliverability/compliance; auth mail stays deliverable when
// unset.
ListUnsubscribe string
}
Message is a single outgoing email. Validate must be called (or NewMessage used) before passing to a Transport. Either HTML or Text (or both) must be non-empty.
func NewMessage ¶
NewMessage constructs a Message and runs Validate. Returns a wrapped ErrInvalidMessage on failure.
type SMTPConfig ¶
type SMTPConfig struct {
// Host is the SMTP server hostname (e.g. "smtp.gmail.com").
Host string
// Port is the SMTP server port. Common values:
// 25 - plain (dev / on-prem only).
// 587 - submission with STARTTLS upgrade.
// 465 - implicit TLS (a.k.a. SMTPS).
Port int
// User and Pass are credentials for PLAIN auth. If User is empty, no auth
// is attempted.
User string
Pass string
// From is the default From address used when Message.From is empty.
From string
// TLS enables implicit TLS on dial (use with port 465).
TLS bool
// StartTLS issues a STARTTLS upgrade after EHLO (use with port 587).
StartTLS bool
// InsecureSkipVerify disables TLS certificate verification. ONLY use this
// in tests against self-signed servers; never enable it in production.
InsecureSkipVerify bool
// DialTimeout caps how long Dial may block. Defaults to 10s.
DialTimeout time.Duration
}
SMTPConfig configures an SMTP transport. The zero value is not valid; use NewSMTP.
type Transport ¶
type Transport interface {
// Send delivers m. It must validate m and return a wrapped ErrInvalidMessage
// for malformed inputs, or a wrapped ErrTransport (or other error) for
// backend failures.
Send(ctx context.Context, m Message) error
}
Transport is the abstraction over an email backend. Implementations must be safe for concurrent use and should honor ctx cancellation as best they can.
func NewLogOnly ¶
NewLogOnly returns a Transport that logs each Send at WARN and returns nil. Intended for local development when no SMTP server is configured.
func NewSMTP ¶
func NewSMTP(cfg SMTPConfig) (Transport, error)
NewSMTP builds an SMTP transport from cfg.