go-smtp
An ESMTP client and server library for Go, implementing RFC 5321 plus AUTH, LMTP, and modern mail extensions.
Repository Health
Technical Analysis
go-smtp is a Go library that implements the Simple Mail Transfer Protocol end to end: an ESMTP client for sending mail and a full ESMTP/LMTP server implementation for receiving it. It exists because the Go standard library’s net/smtp is frozen and client-only, so any project that needs a real SMTP server, or client features beyond the basics, has to look elsewhere.
On the server side, consumers implement a small Backend/Session interface pair to plug in their own mail storage or routing logic, while go-smtp handles the protocol state machine, line parsing, error codes, and optional extensions (STARTTLS, AUTH via SASL, DSN, CHUNKING/BINARYMIME, SMTPUTF8, and more). The client mirrors this with a Dial/Client API for connecting, authenticating, and streaming a message body without buffering it entirely in memory.
It is maintained by emersion, the author of several widely used Go mail and IMAP libraries, and is used as the SMTP layer inside real mail servers and mail-handling tools rather than as a toy example implementation.
What You Get
- An ESMTP client (
Client,Dial,DialTLS,DialStartTLS) for connecting, authenticating via SASL, and streaming message bodies to a remote server - A pluggable ESMTP server (
Server,Backend,Session) where you implement mail handling and go-smtp handles the RFC 5321 command loop - LMTP (RFC 2033) support via the same server, for per-recipient delivery status reporting through the optional
LMTPSession/StatusCollectorinterfaces - Extension support for AUTH, STARTTLS, PIPELINING, 8BITMIME, BINARYMIME/CHUNKING, DSN, SMTPUTF8, DELIVERBY, MT-PRIORITY, and RRVS, each toggled independently on
Server - Structured SMTP error values (
SMTPErrorwith numeric code, enhanced code, and message) instead of opaque strings, usable from both client and server code
Common Use Cases
- Building a custom mail server or mail-relay component that needs full control over how incoming messages are accepted, validated, and stored
- Implementing LMTP delivery between a mail transfer agent and a local delivery agent, with per-recipient status reporting
- Adding outbound SMTP submission with SASL authentication to a Go application, beyond what the frozen
net/smtppackage supports - Prototyping or testing SMTP-speaking services locally, including the bundled
smtp-debug-servercommand for inspecting raw client traffic
Under The Hood
Architecture
go-smtp separates cleanly into a server half and a client half that share only low-level plumbing (net/textproto, SASL, error types). On the server side, Server owns the listener accept loop and per-connection bookkeeping (server.go), handing each connection to a Conn (conn.go) that runs the RFC 5321 command state machine: it wraps the raw connection in a line-limited reader, parses commands via parse.go, and dispatches them to a library-supplied Backend/Session implementation (backend.go). Extension behavior (LMTP status collection, BDAT chunking via an io.Pipe, dot-stuffed DATA streaming through a custom dataReader in data.go) is layered on top of this core loop rather than baked into it, so a minimal backend only needs to implement Reset/Logout/Mail/Rcpt/Data, while optional interfaces (LMTPSession, AuthSession) add capability without forcing every implementer to support it. The client (client.go) is a largely independent RFC 5321 implementation reusing the same textproto and SMTPError types, decoupled from the server’s Conn/Backend machinery.
Tech Stack
The library has a single external dependency, github.com/emersion/go-sasl, for SASL authentication mechanisms; everything else is Go standard library (net, crypto/tls, net/textproto, bufio, encoding/base64). go.mod targets Go 1.13, favoring broad compatibility over newer language features. There is no web framework, database, or build tooling beyond go build/go test; CI runs on sourcehut (.build.yml) rather than GitHub Actions, executing race-detector builds and tests with coverage reporting plus a gofmt formatting check. A small cmd/smtp-debug-server binary ships alongside the library for manual protocol inspection.
Code Quality
Testing is extensive relative to the library’s size: client_test.go and server_test.go are each larger than the production code they cover, with additional dedicated coverage for LMTP (lmtp_server_test.go) and command parsing (parse_test.go), plus runnable Example* functions that double as documentation. CI runs the full suite with the race detector and tracks coverage, and enforces gofmt formatting on every build. Errors are consistently typed via SMTPError (numeric code, RFC 2034 enhanced code, message) rather than ad hoc strings, used uniformly across client and server. There is no separate linter configuration beyond gofmt, and the test suite relies on the standard library’s testing package without an assertion framework, which is idiomatic for Go but means less structured failure output than table-driven frameworks with custom matchers.
API Design
The Backend/Session split is the core design decision: it lets applications own mail storage and routing while go-smtp owns protocol correctness, and optional interfaces (AuthSession for AUTH, LMTPSession for per-recipient LMTP status) are additive so simple backends stay simple. The extension surface is unusually broad for a Go SMTP library — most alternatives cover only basic ESMTP, while go-smtp also implements LMTP, DELIVERBY, MT-PRIORITY, and RRVS, extensions rarely found outside MTA-grade software. Combined with the frozen, client-only state of the standard library’s net/smtp, this makes go-smtp one of the few Go options for building a real SMTP server rather than only a client.
Used by 8 apps in this directory
Coder
Devops · Developer Tools · Code Editors
Self-hosted cloud development environments and AI coding agents — defined in Terraform, connected via WireGuard, automatically shut down when idle.
e2a
AI Agents · Automation
Give your AI agents a real, authenticated email address — with SPF/DKIM-verified inbound, HMAC-signed delivery, WebSocket fan-out, and human-in-the-loop approval built in.
Hatchet
AI Development · Developer Tools · Automation
A Postgres-backed orchestration engine for background tasks, AI agents, and durable workflows that replaces Redis queues and multi-datastore durable execution platforms with a single self-hostable service.
Hyvor Relay
Devops · AI Development · Monitoring
Self-hosted, open-source email API that automates DNS, manages SMTP delivery, and provides deep observability — replacing SES, Mailgun, and SendGrid with infrastructure you fully own.
Notifuse
Marketing
Open-source, self-hosted alternative to Mailchimp, Brevo, and Klaviyo — send newsletters and transactional emails without per-email pricing or vendor lock-in.
ntfy
Developer Tools · Marketing
Send push notifications to your phone or desktop from any script or service using a single HTTP PUT or POST—no sign-up required.
SigNoz
Monitoring · Analytics
Self-host your entire observability stack — logs, metrics, traces, and LLM monitoring — in one OpenTelemetry-native platform, without the Datadog bill.
Wakapi
Developer Tools · Analytics
Self-hosted WakaTime-compatible coding statistics backend that gives developers full control over their coding activity data.