All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
0.2.0 - 2026-06-06
- Enforce a minimum of TLS 1.2 on STARTTLS connections in both the SMTP sender and the connection pool.
- Reject custom header names that contain characters outside the RFC 5322 field-name set, and reject CR/LF in custom header values, when building messages.
- Strip CR/LF from email addresses that fail to parse instead of emitting them unmodified into message headers.
- Validate attachment filenames and content types for CR/LF, and default a
missing attachment content type to
application/octet-stream.
Mailer.SendEmailandMailer.SendBatchnow deep-copy the supplied email so the caller's slices and maps are never mutated, and they return an error when given a nil email.- The Mailgun provider now propagates multipart form-field write errors instead of silently discarding them.
0.1.0 - 2026-04-19
Initial public release.
Emailtype with fluent builder API (NewEmail,SetFrom,AddTo,AddCc,AddBcc,SetReplyTo,SetSubject,SetBody,SetHTMLBody,AddAttachment,AddHeader,Build,Validate).Senderinterface (Send,Close) as the core abstraction for all delivery backends.Mailerhigh-level wrapper withSend,SendHTML,SendTemplate,SendEmail, andSendBatch(concurrent delivery with configurable limit).NewMailerWithOptionswith theMailerOptionfunctional-options pattern andWithMiddlewarehelper.Errortype exposingOp,From,To, and the wrapped underlying error; supportserrors.Is/errors.As.- Sentinel errors:
ErrNoRecipients,ErrNoSender,ErrNoSubject,ErrNoBody,ErrInvalidHeader,ErrPoolClosed,ErrPoolTimeout,ErrQueueFull,ErrQueueClosed,ErrPanicked. - Email address validation via
net/mailon From, To, Cc, Bcc, and Reply-To. - CRLF injection protection on all header keys and values, including Subject and custom headers.
AddHeadercanonicalizes keys withtextproto.CanonicalMIMEHeaderKeyto prevent duplicate-case headers.AddAttachmentdefensively copies the caller's byte slice.
SMTPSenderwithSMTPConfig(Host, Port, Username, Password, From, UseTLS, Timeout, MaxRetries, RetryDelay, RetryBackoff, RateLimit).- STARTTLS support with
ServerNameset for hostname verification. - Exponential backoff retry logic with a 5-minute per-attempt ceiling.
- Non-retry fast-path for deterministic failures (validation errors, context cancellation, missing recipients/sender/subject/body, and permanent SMTP 5xx replies per RFC 5321).
- Token-bucket rate limiting via
golang.org/x/time/rate(configurable or disabled with a negative value). - Per-connection deadline applied to dial, STARTTLS, auth, MAIL/RCPT/DATA so a slow server cannot hang the send indefinitely.
- Graceful shutdown of the SMTP client on error paths via a single deferred
client.Close.
- Optional SMTP connection pool activated by setting
PoolSize > 0. - Configurable
MaxIdleConns,PoolMaxLifetime,PoolMaxIdleTime,MaxMessages(messages per connection before rotation),PoolWaitTimeout. - Health-check probe (
RSET) on every checkout and on connections received from the wait queue. - LIFO idle-connection reuse and a FIFO waiter queue honoring
PoolWaitTimeoutas a real ceiling across health-check retries. - Background cleaner goroutine that evicts expired and idle-timed-out connections.
Close()drains idle connections and signals waiters withErrPoolClosed.
AsyncSenderwrapping anySenderwith a buffered work queue and configurable worker goroutines.- Functional options:
WithQueueSize,WithWorkers,WithAsyncLogger,WithErrorHandler. Send(fire-and-forget) detaches caller cancellation viacontext.WithoutCancelwhile preserving request-scoped values.SendWaitblocks until delivery completes or the context is cancelled.- Graceful shutdown via
Close(sync.Once): drains the queue, waits for workers, then closes the underlying sender.
TemplatewithSetSubject,SetTextTemplate,SetHTMLTemplate, andRender(data). Subject usestext/template; HTML useshtml/templatewith auto-escaping.- Optional HTML sanitization on rendered output via
WithSanitizationandWithSanitizationPolicy. - Template loaders:
LoadTemplateFromFile,LoadTemplateFromFS,LoadTemplatesFromDir,LoadTemplatesFromFS. Merges files with the same base name (welcome.html+welcome.txt+welcome.subject→ oneTemplate).
Middlewaretype andChain(sender, middlewares...)helper (first middleware is outermost).WithLogging(logger)— logs send attempts, successes, and failures.WithRecovery()— converts panics into errors wrappingErrPanicked.WithHooks(SendHooks)— user-definedOnSend,OnSuccess,OnFailurecallbacks.WithMetrics(collector)— records send counters and latency via theMetricsCollectorinterface.WithSanitization/WithSanitizationPolicy— sanitizesHTMLBodybefore delivery as a safety net.
- Provider-agnostic
WebhookEventnormalized type withEventTypeconstants (delivered,bounced,deferred,opened,clicked,complained,unsubscribed,dropped). WebhookParserandWebhookHandlerinterfaces for provider-specific parsing and event handling.WebhookReceiverhttp.HandlerwithWithWebhookLoggerandWithEventFilteroptions. Dispatches every event in a batch even when one fails (handlers must be idempotent).
DKIMConfigwith Domain, Selector, PrivateKey, optionalSignedHeaders,Expiration, and per-section (header/body) canonicalization choice.SignMessage(msg, config)produces a DKIM-Signature header prepended to the message.BuildRawMessageandBuildRawMessageWithDKIMfor raw-message providers (e.g. AWS SES).ParseDKIMPrivateKey(pem)accepts PKCS#8 (RSA or Ed25519) and PKCS#1 (RSA).- Automatic signing of every SMTP send when
SMTPConfig.DKIMis non-nil. - Supports simple and relaxed canonicalization for both headers and body.
- RSA-SHA256 and Ed25519-SHA256 algorithms;
Fromheader always signed per RFC 6376 §5.4.
- Proper multipart encoding:
multipart/mixed(with attachments),multipart/alternative(plain + HTML without attachments), and single-part fallbacks. - Quoted-printable body encoding and base64 attachment encoding with 76-character line wrapping per RFC 2045.
- RFC 2047 Q-encoding for non-ASCII subjects and display names.
- RFC 2231
filename*=encoding for non-ASCII attachment filenames. - Filename sanitization strips CR/LF/NUL and path separators from
Content-Disposition. - Deterministic custom-header ordering for reproducible output.
- Case-insensitive
Message-IDoverride; auto-generatedMessage-IDuses the sender's domain and acrypto/randidentifier.
Policywith builder methodsAllowElements,AllowAttributes,AllowGlobalAttributes,AllowURLProtocols,StripElements.EmailPolicy()ships a sensible default allowlist covering common email clients (Gmail, Outlook, Apple Mail, Yahoo).SanitizeHTMLandSanitizeHTMLWithPolicyentry points, plusSanitizeFuncMapfor use insidehtml/template.- URL-protocol allowlisting with HTML-entity decoding, WHATWG URL
normalization (strip tab/LF/CR/NUL), and control-character stripping to
catch
java	script:and similar obfuscations. - CSS value filtering: rejects
expression,javascript:,vbscript:,-moz-binding,behavior:, andurl(...)references with disallowed protocols.
Loggerinterface (Debug,Info,Warn,Error,With).NoOpLoggerdefault implementation.SlogLoggeradapter for the standard librarylog/slog.
MockSenderwithGetSentEmails,GetLastEmail,GetEmailCount,GetEmailsTo,GetEmailsBySubject,Reset, andSetSendFuncfor injecting error scenarios.
providers/sendgrid— SendGrid v3 Web API (/v3/mail/send), handles personalizations, Cc/Bcc, Reply-To, headers, and base64 attachments.providers/mailgun— Mailgun v3 Messages API with multipart form upload; supports US and EU base URLs. AttachmentContent-Typeis preserved on each form part.providers/ses— AWS SES v2 using raw MIME messages (viaBuildRawMessage), optional configuration set.providers/otelmail— OpenTelemetry tracing middleware that produces a client-kind span per send, with configurable tracer and span names.
examples/basic,examples/template,examples/attachment,examples/batch,examples/middleware,examples/pool,examples/testing.
Makefilewithall,test,vet,lint,build,bench,fmt,cover,ci, andexamplestargets.golangci-lintconfiguration.- GitHub Actions CI, Codecov integration, editorconfig, and contribution guidelines.
- Go 1.26 or newer.