Documentation
¶
Overview ¶
Package email provides helpers for formatting and delivering mail via SMTP.
SendWithClient sanitizing and deduplicates recipients case-insensitively across the To, CC, and BCC lists in that order. The primary recipient is always addressed first, and only one RCPT command is issued per unique address. CC headers include only deduplicated CC recipients while BCC addresses are added to the envelope but never leaked via headers.
Index ¶
- Constants
- Variables
- func ConnectSMTP(cfg config.SMTPConfig) (*smtp.Client, error)
- func ConnectSMTPWithContext(ctx context.Context, cfg config.SMTPConfig) (*smtp.Client, error)
- func GetMaxBackoff() time.Duration
- func GetRetryLimit() int
- func SendWithClient(client *smtp.Client, cfg config.SMTPConfig, task Task, cache *AttachmentCache) (err error)
- func SetMaxBackoff(d time.Duration)
- func SetRetryLimit(limit int)
- type AttachmentCache
- type AttachmentProcessor
- type DispatchOptions
- type DispatchResult
- type OffsetTracker
- type Task
- type TemplateCache
Constants ¶
const DefaultAttachmentCacheLimit int64 = 256 << 20 // 256 MiB
DefaultAttachmentCacheLimit caps the total bytes of base64-encoded attachment payloads held in cache per dispatch. Files whose encoded size would exceed the remaining budget are streamed inline instead.
Variables ¶
var ( ErrAttachmentTooLarge = errors.New("attachment exceeds maximum allowed size") ErrUnsupportedAttachmentType = errors.New("unsupported attachment type") )
Functions ¶
func ConnectSMTP ¶
func ConnectSMTP(cfg config.SMTPConfig) (*smtp.Client, error)
ConnectSMTP establishes a persistent, authenticated SMTP client with TLS and context support.
func ConnectSMTPWithContext ¶ added in v1.1.0
ConnectSMTPWithContext establishes a persistent, authenticated SMTP client with TLS and context support. This allows for proper cancellation during connection attempts.
func GetMaxBackoff ¶ added in v1.1.0
GetMaxBackoff returns the current max backoff duration (thread-safe)
func GetRetryLimit ¶ added in v1.1.0
func GetRetryLimit() int
GetRetryLimit returns the current retry limit (thread-safe)
func SendWithClient ¶
func SendWithClient(client *smtp.Client, cfg config.SMTPConfig, task Task, cache *AttachmentCache) (err error)
SendWithClient formats and delivers an email using an active SMTP client. Recipients from the To, CC, and BCC fields are trimmed, deduplicated in that order (case-insensitively), and issued RCPT commands exactly once with the primary recipient always first. The CC header is rendered from the unique CC list, while BCC addresses are kept solely on the SMTP envelope. It uses cfg.SMTP.From as both the envelope sender and header From address.
cache may be nil; when supplied, attachments are read and base64-encoded once per dispatch run and reused across all recipients.
func SetMaxBackoff ¶ added in v1.1.0
SetMaxBackoff sets the maximum backoff delay for retries
func SetRetryLimit ¶
func SetRetryLimit(limit int)
SetRetryLimit sets the max retry attempts per failed email, with exponential backoff.
Types ¶
type AttachmentCache ¶ added in v1.1.0
type AttachmentCache struct {
// contains filtered or unexported fields
}
AttachmentCache memoizes base64-encoded attachment payloads keyed by absolute path. Population is lazy and concurrency-safe. A single shared cache should be created per dispatch and torn down with Reset when the run ends.
func NewAttachmentCache ¶ added in v1.1.0
func NewAttachmentCache(maxBytes int64) *AttachmentCache
NewAttachmentCache constructs a cache with the given total-size cap. A non-positive cap falls back to DefaultAttachmentCacheLimit.
func (*AttachmentCache) Get ¶ added in v1.1.0
func (c *AttachmentCache) Get(path string) (*cachedAttachment, error)
Get returns the cached attachment for path, populating the cache on first access. Returns (nil, errCacheCapExceeded) when the file would push the cache past its byte cap; callers should fall back to streaming.
func (*AttachmentCache) Reset ¶ added in v1.1.0
func (c *AttachmentCache) Reset()
Reset releases all cached payloads. Call once when the dispatch run ends.
type AttachmentProcessor ¶ added in v1.0.0
type AttachmentProcessor struct {
// contains filtered or unexported fields
}
AttachmentProcessor handles efficient processing of email attachments
func NewAttachmentProcessor ¶ added in v1.0.0
func NewAttachmentProcessor(maxSize int64) *AttachmentProcessor
NewAttachmentProcessor creates a new attachment processor
func (*AttachmentProcessor) ProcessAttachment ¶ added in v1.0.0
ProcessAttachment handles a single attachment efficiently. It opens the file only once and reuses the handle for both MIME detection and reading.
type DispatchOptions ¶ added in v1.1.0
type DispatchOptions struct {
Context context.Context
Monitor monitor.Monitor
Tracker OffsetTracker
// StartOffset is retained for API compatibility but is no longer consulted
// for offset arithmetic — Task.Index is treated as an absolute position
// and Tracker.MarkComplete handles concurrency-safe advancement.
StartOffset int
// AttachmentCache is reused across all sends in this dispatch. When nil,
// the dispatcher creates one with DefaultAttachmentCacheLimit. Pass a
// pre-populated cache to share across multiple dispatches.
AttachmentCache *AttachmentCache
// OffsetSaveInterval controls how often the tracker is flushed to disk.
// Zero falls back to 200ms. Negative disables periodic flushing (only the
// final save at dispatch end is performed).
OffsetSaveInterval time.Duration
// PendingEmails seeds the monitor dashboard with all expected recipients
// before any worker runs. StartDispatcher populates this from the task
// slice automatically; streaming callers should supply it from their
// recipient list so the dashboard shows everyone in Pending state.
PendingEmails []string
}
DispatchOptions contains optional parameters for email dispatching
type DispatchResult ¶ added in v1.1.0
DispatchResult holds summary statistics from a dispatch run.
func StartDispatcher ¶
func StartDispatcher(tasks []Task, cfg config.SMTPConfig, concurrency int, batchSize int, opts *DispatchOptions) DispatchResult
StartDispatcher sends emails using a worker pool. It is the bulk entry point for slice-based task lists; for streaming sources see StartDispatcherStream.
Per-success offset persistence is coalesced through a background flusher so the disk syncs do not serialize the worker hot path. Offset semantics use a contiguous high-water mark (Tracker.MarkComplete) so resume is correct under concurrency.
func StartDispatcherStream ¶ added in v1.1.0
func StartDispatcherStream(ctx context.Context, taskCh <-chan Task, cfg config.SMTPConfig, concurrency int, batchSize int, opts *DispatchOptions) DispatchResult
StartDispatcherStream consumes tasks from a channel rather than a slice. Use it when the recipient list is large enough that holding all rendered tasks in RAM is undesirable. The caller is responsible for closing taskCh when no more tasks will be produced.
All workers will return once taskCh is drained or ctx is cancelled.
type OffsetTracker ¶ added in v1.1.0
OffsetTracker interface for tracking email delivery progress.
MarkComplete records that the absolute task index `idx` was successfully delivered. Implementations are expected to maintain a contiguous high-water mark — the saved offset advances only past indices that have all been completed, even when workers finish out of order.
UpdateOffset and Save remain on the interface for backward compatibility with external callers (CLI cleanup paths, tests).
type Task ¶
type Task struct {
Recipient parser.Recipient
Subject string
Body string // HTML body (from --template)
PlainText string // Plain-text body (from --text, for multipart/alternative)
Retries int
Attachments []string
CC []string
BCC []string
Index int // Position in original task list for offset tracking
}
Task represents an email send job with recipient data.
type TemplateCache ¶ added in v1.0.0
type TemplateCache struct {
// contains filtered or unexported fields
}
TemplateCache provides thread-safe caching of parsed email templates
func NewTemplateCache ¶ added in v1.0.0
func NewTemplateCache(maxAge time.Duration, maxSize int) *TemplateCache
NewTemplateCache creates a new template cache with given configuration
func (*TemplateCache) Clear ¶ added in v1.0.0
func (c *TemplateCache) Clear()
Clear removes all templates from cache
func (*TemplateCache) Get ¶ added in v1.0.0
func (c *TemplateCache) Get(path string) (*template.Template, error)
Get retrieves a template from cache (checking age) or parses it if missing/expired.
func (*TemplateCache) GetCurrentSize ¶ added in v1.1.0
func (c *TemplateCache) GetCurrentSize() int
GetCurrentSize returns the current number of cached templates
func (*TemplateCache) Stop ¶ added in v1.1.0
func (c *TemplateCache) Stop()
Stop stops cleanup goroutine and cleans up resources