Documentation
¶
Overview ¶
Package email builds bounded messages, renders typed templates and submits through borrowed transports. Acceptance is not proof of inbox delivery. Jobs and transactional publication remain owned by package jobs.
Index ¶
- Constants
- func JobHandler[P any](mailer *Mailer, build Builder[P]) jobs.Handler[P]
- func Module(name foundation.ProviderID, key foundation.Key[*Mailer], ...) foundation.Module
- type Address
- func (Address) Format(s fmt.State, _ rune)
- func (a Address) Header() string
- func (Address) JSONContract() contract.JSON[Address]
- func (Address) LogValue() slog.Value
- func (a Address) Mailbox() string
- func (a Address) MarshalJSON() ([]byte, error)
- func (a Address) MarshalText() ([]byte, error)
- func (a Address) Name() string
- func (a *Address) UnmarshalJSON(data []byte) error
- func (a *Address) UnmarshalText(data []byte) error
- func (a Address) Validate() error
- type Attachment
- type Body
- type Builder
- type Config
- type DataAttachment
- func (a DataAttachment) ContentID() string
- func (a DataAttachment) ContentType() storage.MediaType
- func (a DataAttachment) Filename() string
- func (DataAttachment) Format(s fmt.State, _ rune)
- func (DataAttachment) LogValue() slog.Value
- func (a DataAttachment) Size() int
- func (a DataAttachment) WithContentID(id string) (DataAttachment, error)
- type Diagnostics
- type Driver
- type DriverFunc
- type DynamicTemplate
- type HTTPConfig
- type IdempotencyKey
- type Kind
- type Layout
- type LocalizedTemplate
- type Mailer
- func (m *Mailer) Close(ctx context.Context) error
- func (m *Mailer) Done() <-chan struct{}
- func (*Mailer) Format(s fmt.State, _ rune)
- func (*Mailer) LogValue() slog.Value
- func (m *Mailer) Message(subject string, to ...Address) Message
- func (m *Mailer) Send(ctx context.Context, message Message, options SendOptions) (result Result, err error)
- func (m *Mailer) Snapshot() Diagnostics
- type MailerName
- type Mailers
- type Message
- func (m Message) Attach(attachments ...Attachment) Message
- func (m Message) AttachData(attachments ...DataAttachment) Message
- func (m Message) AttachStored(file StoredAttachment) (Message, error)
- func (m Message) AttachUpload(ctx context.Context, file UploadSource) (Message, error)
- func (m Message) Attachments() []Attachment
- func (m Message) BCC() []Address
- func (m Message) Bcc(addresses ...Address) Message
- func (m Message) CC() []Address
- func (m Message) Cc(addresses ...Address) Message
- func (m Message) DataAttachments() []DataAttachment
- func (m Message) EnvelopeRecipients() []Address
- func (Message) Format(s fmt.State, _ rune)
- func (m Message) From() Address
- func (m Message) HTML(html string) Message
- func (m Message) HTMLBody() string
- func (m Message) Header(name, value string) Message
- func (m Message) Headers() map[string]string
- func (m Message) Locale(locale i18n.LocaleID) Message
- func (m Message) LocaleID() i18n.LocaleID
- func (Message) MarshalJSON() ([]byte, error)
- func (m Message) RecipientCount() int
- func (m Message) ReplyAddresses() []Address
- func (m Message) ReplyTo(addresses ...Address) Message
- func (m Message) Subject() string
- func (m Message) Text(text string) Message
- func (m Message) TextBody() string
- func (m Message) To() []Address
- func (m Message) Validate() error
- type NamedMailer
- type Notice
- type Observer
- type Outbound
- type Receipt
- type ResolvedAttachment
- type Result
- type SendOptions
- type Snapshot
- type Stage
- type StoredAttachment
- type StructuredDriver
- type Template
- type TemplateSource
- type UploadSource
Constants ¶
const MaxAddressBytes = 1024
const MaxAttachments = 32
const MaxDataAttachmentBytes = 10 << 20
MaxDataAttachmentBytes bounds one in-memory attachment; the mailer's MaxAttachmentBytes and MaxMessageBytes still apply.
const MaxDisplayNameBytes = 256
const MaxHeaders = 32
const MaxMailboxBytes = 254
const MaxRecipients = 50
Variables ¶
This section is empty.
Functions ¶
func JobHandler ¶
JobHandler plugs into Definition[P].Declare. Capture/Dispatch/Enqueue, attribution, serialization, versioning, retries and outbox routing remain the existing jobs API. Each execution reuses its stable ID as provider key. Ambiguous acceptance is terminal, including on idempotent providers: provider retention is finite and does not cover arbitrary worker redelivery intervals.
func Module ¶
func Module(name foundation.ProviderID, key foundation.Key[*Mailer], requires []foundation.ProviderID, construct func(foundation.Resolver) (*Mailer, error)) foundation.Module
Module registers an owned mailer. Requires must name providers owning its borrowed transport and disks so sends drain before those resources close.
Types ¶
type Address ¶
type Address struct {
// contains filtered or unexported fields
}
Address is one validated ASCII mailbox with an optional UTF-8 display name. SMTPUTF8 local parts and IDN conversion are deliberately not implicit.
func NewAddress ¶
NewAddress validates a mailbox and display name, returning a construction failure for invalid input.
func ParseAddress ¶
ParseAddress parses an address header and validates its mailbox and display name.
func (Address) Header ¶
Header explicitly reveals the formatted mailbox. Generic formatting is redacted.
func (Address) JSONContract ¶
JSONContract is the single scalar wire declaration used by generated DTOs and contract export. Display-name mailboxes are strings, not OpenAPI email-format strings; NewAddress/ParseAddress retain the stricter runtime mailbox checks.
func (Address) MarshalJSON ¶
MarshalJSON validates and encodes the address header as a JSON string.
func (Address) MarshalText ¶
Text configuration reuses the same mailbox parser as message construction.
func (*Address) UnmarshalJSON ¶
UnmarshalJSON decodes and validates an address header, replacing the receiver only on success.
func (*Address) UnmarshalText ¶
UnmarshalText parses an address header, replacing the receiver only on success.
type Attachment ¶
type Attachment struct {
Disk storage.DiskID `json:"disk"`
Key storage.ObjectKey `json:"key"`
Filename string `json:"filename"`
ContentType storage.MediaType `json:"content_type"`
ContentID string `json:"content_id,omitempty"`
Version storage.VersionID `json:"version,omitempty"`
IfMatch storage.ETag `json:"if_match,omitempty"`
}
Attachment references shared storage. Pin Version or IfMatch when queued so redelivery cannot silently send replacement content. Readers and OS paths never enter serialized email data.
func (Attachment) Format ¶
func (Attachment) Format(s fmt.State, _ rune)
Format writes a fixed label without exposing attachment metadata.
func (Attachment) LogValue ¶
func (Attachment) LogValue() slog.Value
LogValue returns a fixed log label without exposing attachment metadata.
func (Attachment) Validate ¶
func (a Attachment) Validate() error
Validate checks storage identifiers, conditions, and attachment metadata.
type Body ¶
Body is rendered template output. Locale is set by LocalizedTemplate and carried to the message.
type Builder ¶
Builder renders one deterministic message from a declared job DTO. Capture template inputs and pinned attachment references in that DTO. Never read mutable recipient state or current time when an identical retry is required.
type Config ¶
type Config struct {
// From supplies Mailer.Message; explicit NewMessage senders are never replaced.
From Address
MaxActive, MaxMessageBytes, MaxAttachmentBytes int
Timeout time.Duration
// MessageIDDomain is the right-hand side of generated Message-ID headers.
// Empty uses each message's sender domain.
MessageIDDomain string
}
Config configures default sender, capacity, size budgets, timeout, and message identifier domain.
func DefaultConfig ¶
func DefaultConfig() Config
DefaultConfig returns default mailer capacity, size limits, and timeout.
type DataAttachment ¶
type DataAttachment struct {
// contains filtered or unexported fields
}
DataAttachment is in-memory content attached directly, for generated files such as a rendered invoice. It holds an owned copy of the bytes. It is not serializable: queued and snapshotted email must reference stored attachments.
func NewDataAttachment ¶
func NewDataAttachment(filename string, contentType storage.MediaType, data []byte) (DataAttachment, error)
NewDataAttachment copies and validates nonempty attachment data and metadata.
func (DataAttachment) ContentID ¶
func (a DataAttachment) ContentID() string
ContentID returns the attachment's inline content identifier.
func (DataAttachment) ContentType ¶
func (a DataAttachment) ContentType() storage.MediaType
ContentType returns the attachment's media type.
func (DataAttachment) Filename ¶
func (a DataAttachment) Filename() string
Filename returns the attachment filename.
func (DataAttachment) Format ¶
func (DataAttachment) Format(s fmt.State, _ rune)
Format writes a fixed label without exposing attachment data.
func (DataAttachment) LogValue ¶
func (DataAttachment) LogValue() slog.Value
LogValue returns a fixed log label without exposing attachment data.
func (DataAttachment) Size ¶
func (a DataAttachment) Size() int
Size returns the attachment byte count.
func (DataAttachment) WithContentID ¶
func (a DataAttachment) WithContentID(id string) (DataAttachment, error)
WithContentID returns an inline copy referenced as cid:id from HTML.
type Diagnostics ¶
type Diagnostics struct {
Active int
Closing bool
Calls, Accepted, Failed, ObserverFailures uint64
}
Diagnostics reports active sends, closing state, and send and observer counters.
type Driver ¶
type Driver interface {
// Send submits an outbound message and returns its acceptance receipt or failure.
Send(context.Context, Outbound) (Receipt, error)
}
Driver performs one submission. It must classify failures, honor context, avoid implicit retries, and return only after releasing its I/O. Mailer borrows it; the application closes transport resources after Mailer.Done.
type DriverFunc ¶
DriverFunc adapts a function to Driver.
type DynamicTemplate ¶
type DynamicTemplate struct {
// contains filtered or unexported fields
}
DynamicTemplate is the explicit heterogeneous-map escape hatch.
func NewDynamicTemplate ¶
func NewDynamicTemplate(source TemplateSource) (DynamicTemplate, error)
NewDynamicTemplate parses template sources for dynamically typed rendering.
type HTTPConfig ¶
type HTTPConfig struct {
Endpoint string
Timeout time.Duration
Transport http.RoundTripper
}
HTTPConfig configures API adapters. Empty Endpoint selects the provider's documented URL; overrides must use HTTPS or an explicit loopback HTTP URL. A supplied RoundTripper is borrowed and must not retry submissions itself.
func DefaultHTTPConfig ¶
func DefaultHTTPConfig() HTTPConfig
DefaultHTTPConfig returns HTTP settings with the default mailer timeout.
type IdempotencyKey ¶
type IdempotencyKey string
IdempotencyKey identifies one logical submission. Reuse only for an identical message. Provider support and retention are documented by each adapter.
func (IdempotencyKey) Format ¶
func (IdempotencyKey) Format(s fmt.State, _ rune)
Format writes a fixed label without exposing the key.
func (IdempotencyKey) LogValue ¶
func (IdempotencyKey) LogValue() slog.Value
LogValue returns a fixed log label without exposing the key.
func (IdempotencyKey) Validate ¶
func (k IdempotencyKey) Validate() error
Validate checks that a nonempty key contains printable ASCII and is at most 256 bytes; an empty key is allowed.
type Kind ¶
type Kind string
Kind describes whether a failed submission is safe to retry. Only Transient means known non-acceptance with a potentially recoverable cause.
func Classification ¶
Classification inspects extension errors inside callback isolation. Unknown errors, incomplete error graphs, panic and Goexit fail conservatively; underlying text is never exposed. Custom error methods must return.
type Layout ¶
type Layout struct {
Text, HTML string
}
Layout is a shared trusted wrapper for message bodies: its HTML and Text sources render the message's own body where they call {{template "content" .}}, with the same typed data. A layout part applies only when the message defines that part. The subject is never wrapped.
type LocalizedTemplate ¶
type LocalizedTemplate[T any] struct { // contains filtered or unexported fields }
LocalizedTemplate holds one typed template per locale and selects it along the locale set's fallback chain (for example pt-BR, then pt, then the default). The rendered Body records the locale actually used.
func NewLocalizedTemplate ¶
func NewLocalizedTemplate[T any](locales i18n.LocaleSet, sources map[i18n.LocaleID]TemplateSource) (LocalizedTemplate[T], error)
NewLocalizedTemplate requires a template for the set's default locale; every source locale must belong to the set.
type Mailer ¶
type Mailer struct {
// contains filtered or unexported fields
}
Mailer coordinates email submission with capacity limits and lifecycle tracking.
func (*Mailer) Close ¶
Close cancels admission and active I/O. Its context bounds only this caller's wait; Done remains open until every callback really exits. Borrowed resources are not closed. Calling Close from an active send context returns fault.Cycle.
func (*Mailer) Done ¶
func (m *Mailer) Done() <-chan struct{}
Done returns the mailer's completion channel; a nil or uninitialized mailer returns a closed channel.
func (*Mailer) Message ¶
Message starts an immutable message using this mailer's configured sender. An unconfigured sender produces a message rejected by Send's normal validation.
func (*Mailer) Send ¶
func (m *Mailer) Send(ctx context.Context, message Message, options SendOptions) (result Result, err error)
Send waits for actual completion even when an extension ignores cancellation. A non-nil error never claims known acceptance; an accepted result remains accepted if a Finished observer fails or the context expires afterward.
func (*Mailer) Snapshot ¶
func (m *Mailer) Snapshot() Diagnostics
Snapshot returns a synchronized diagnostic snapshot; a nil mailer reports closing.
type MailerName ¶
type MailerName string
MailerName selects an instance, distinct from names of other service families.
func (MailerName) Validate ¶
func (n MailerName) Validate() error
Validate validates the mailer name.
type Mailers ¶
type Mailers struct {
// contains filtered or unexported fields
}
Mailers is immutable; default and named selection alias the same instance.
func NewMailers ¶
func NewMailers(selected MailerName, entries ...NamedMailer) (*Mailers, error)
NewMailers constructs a named mailer registry with an explicit default selection.
func (*Mailers) DefaultName ¶
func (r *Mailers) DefaultName() MailerName
DefaultName returns the selected default name, or an empty name for a nil registry.
func (*Mailers) Mailer ¶
func (r *Mailers) Mailer(name MailerName) (*Mailer, error)
Mailer looks up a named mailer through the registry.
func (*Mailers) Names ¶
func (r *Mailers) Names() []MailerName
Names returns the registry's mailer names, or nil for a nil registry.
type Message ¶
type Message struct {
// contains filtered or unexported fields
}
Message is immutable. Builders copy changed collections; no caller map or slice is retained. Validate runs again at the submission boundary.
func NewMessage ¶
NewMessage creates a message with a copy of the recipient slice; validation occurs separately.
func (Message) Attach ¶
func (m Message) Attach(attachments ...Attachment) Message
Attach returns a message copy with storage attachment references appended.
func (Message) AttachData ¶
func (m Message) AttachData(attachments ...DataAttachment) Message
AttachData adds in-memory attachments (see DataAttachment).
func (Message) AttachStored ¶
func (m Message) AttachStored(file StoredAttachment) (Message, error)
AttachStored snapshots a stored file or a loaded single-file model slot into this message. It performs no reads; Send resolves bytes through the mailer's storage registry, using the captured version or ETag. Missing/unloaded files fail rather than silently omitting the attachment. Retain the stored object for the lifetime of queued mail; a reference does not prevent deletion.
func (Message) AttachUpload ¶
AttachUpload reads and closes one upload now, without persisting it. The returned message owns the bytes and survives request cleanup. Detected bytes determine its media type; the client type is only a compatible text hint. MaxDataAttachmentBytes bounds the read; mailer limits also apply at Send. Queueing/snapshotting requires stored references instead of runtime uploads.
func (Message) Attachments ¶
func (m Message) Attachments() []Attachment
Attachments returns a copy of the storage attachment slice.
func (Message) DataAttachments ¶
func (m Message) DataAttachments() []DataAttachment
DataAttachments returns a copy of the data attachment slice.
func (Message) EnvelopeRecipients ¶
EnvelopeRecipients includes BCC. MIME headers deliberately exclude BCC.
func (Message) Header ¶
Header returns a message copy with a canonicalized header name and an independently owned header map.
func (Message) Locale ¶
Locale records the message's language. MIME transports send it as the Content-Language header; LocalizedTemplate sets it when rendering.
func (Message) MarshalJSON ¶
MarshalJSON rejects accidental queuing of runtime messages. Queue a declared DTO containing template data and Attachment references through JobHandler.
func (Message) RecipientCount ¶
RecipientCount returns the total number of To, CC, and BCC addresses.
func (Message) ReplyAddresses ¶
ReplyAddresses returns a copy of the reply address slice.
func (Message) ReplyTo ¶
ReplyTo returns a message copy with a copy of the supplied reply addresses.
type NamedMailer ¶
type NamedMailer struct {
Name MailerName
Value *Mailer
}
NamedMailer borrows one existing instance. Selection never creates another owner.
type Notice ¶
type Notice struct {
Stage Stage
Recipients, Bytes int
Accepted bool
Failure Kind
Duration time.Duration
}
Notice deliberately excludes addresses, subject, body, attachment names, message IDs and keys. Finished observers cannot undo provider acceptance.
type Outbound ¶
type Outbound struct {
// contains filtered or unexported fields
}
Outbound can only be constructed by Mailer after validation and resolution. Driver implementations receive this immutable submission snapshot. A structured submission (see StructuredDriver) carries no MIME document.
func (Outbound) Attachments ¶
func (o Outbound) Attachments() []ResolvedAttachment
Attachments returns a copy of the resolved attachment slice.
func (Outbound) IdempotencyKey ¶
func (o Outbound) IdempotencyKey() IdempotencyKey
IdempotencyKey returns the submission's idempotency key.
type Receipt ¶
type Receipt struct{ MessageID string }
Receipt means provider acceptance, never inbox delivery. SMTP may have no ID.
type ResolvedAttachment ¶
type ResolvedAttachment struct {
// contains filtered or unexported fields
}
ResolvedAttachment owns a bounded snapshot. Bytes returns a copy, never a reader into a storage resource. Drivers must not retain borrowed calls.
func (ResolvedAttachment) Bytes ¶
func (a ResolvedAttachment) Bytes() []byte
Bytes returns a copy of the attachment bytes.
func (ResolvedAttachment) Format ¶
func (ResolvedAttachment) Format(s fmt.State, _ rune)
Format writes a fixed label without exposing attachment data.
func (ResolvedAttachment) Reference ¶
func (a ResolvedAttachment) Reference() Attachment
Reference returns the attachment reference metadata.
func (ResolvedAttachment) Size ¶
func (a ResolvedAttachment) Size() int
Size returns the attachment byte count.
type SendOptions ¶
type SendOptions struct{ IdempotencyKey IdempotencyKey }
SendOptions configures a send's idempotency key.
type Snapshot ¶
type Snapshot struct {
// contains filtered or unexported fields
}
Snapshot is an explicit durable, rendered message. Capture it only after resolving the intended recipient. It contains private email content and must be protected like an outbox payload. It contains no readers or executable code. Unlike a source-data job, retrying a snapshot never rerenders or changes routes.
func CaptureMessage ¶
CaptureMessage freezes a validated message within value.JSONMaxBytes. Every attachment must pin Version or IfMatch; mutable storage names cannot enter a durable rendered message. Ordinary Message JSON serialization remains denied.
func (Snapshot) MarshalJSON ¶
MarshalJSON validates the snapshotted message and returns its JSON representation.
func (Snapshot) Message ¶
Message decodes and validates a version-one message, requiring version or match conditions on storage attachments.
func (*Snapshot) UnmarshalJSON ¶
UnmarshalJSON decodes a bounded JSON snapshot, replacing the receiver only after message validation.
type StoredAttachment ¶
type StoredAttachment interface {
// EmailAttachment returns the stored object's email attachment declaration.
EmailAttachment() (Attachment, error)
}
StoredAttachment supplies one pinned reference without I/O. Foundry's attachments.File, Attachment and loaded One slots implement this contract. The caller must authorize access to the file before attaching it.
type StructuredDriver ¶
type StructuredDriver interface {
// StructuredSubmission reports whether the driver accepts structured submissions.
StructuredSubmission() bool
}
StructuredDriver is optional. A provider API that submits native fields (bodies, headers, attachments) rather than the rendered MIME document reports true, so Mailer skips MIME rendering; Outbound.MIME is then empty. SMTP, SES, Cloudflare, memory and log drivers receive the full MIME document.
type Template ¶
type Template[T any] struct { // contains filtered or unexported fields }
Template holds parsed email templates for a concrete data type.
func NewTemplate ¶
func NewTemplate[T any](source TemplateSource) (Template[T], error)
NewTemplate parses template sources for a named struct type, rejecting other data types.
type TemplateSource ¶
TemplateSource is trusted application template code. Data is escaped by html/template. Do not put untrusted template source or template.HTML in DTOs. Layout optionally wraps the Text and HTML bodies.
type UploadSource ¶
UploadSource accepts a captured browser upload (http.UploadedFile) without email depending on HTTP. The caller owns the underlying file.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package cloudflare submits MIME through Cloudflare Email Service's REST API.
|
Package cloudflare submits MIME through Cloudflare Email Service's REST API. |
|
Package failover composes borrowed email transports.
|
Package failover composes borrowed email transports. |
|
internal
|
|
|
httptransport
Package httptransport owns the shared one-request, bounded-response policy.
|
Package httptransport owns the shared one-request, bounded-response policy. |
|
Package log simulates acceptance while logging only bounded message metadata.
|
Package log simulates acceptance while logging only bounded message metadata. |
|
Package mailgun submits multipart messages through Mailgun's v3 API.
|
Package mailgun submits multipart messages through Mailgun's v3 API. |
|
Package memory supplies a bounded, opt-in email recorder.
|
Package memory supplies a bounded, opt-in email recorder. |
|
Package postmark submits through Postmark's single-email API.
|
Package postmark submits through Postmark's single-email API. |
|
Package resend submits through Resend's single-email HTTP API.
|
Package resend submits through Resend's single-email HTTP API. |
|
Package ses submits MIME through SES SendRawEmail using the existing AWS SDK credential and SigV4 interfaces.
|
Package ses submits MIME through SES SendRawEmail using the existing AWS SDK credential and SigV4 interfaces. |
|
Package smtp sends MIME messages over SMTP connections owned by the driver.
|
Package smtp sends MIME messages over SMTP connections owned by the driver. |