Production-ready email package for Go with SMTP support, templating, retries, connection pooling, DKIM signing, and provider adapters for SendGrid, Mailgun, and AWS SES.
Documentation · API Reference · Changelog
net/smtp gets you a connection and a DATA command. Everything past that —
the parts that turn "I can send one email" into "I can run this in
production" — is what goemail provides:
| Capability | goemail | Raw net/smtp |
|---|---|---|
| Retry with exponential backoff | ✓ | You build it |
| Connection pooling for high throughput | ✓ | You build it |
| Rate limiting | ✓ | You build it |
| DKIM signing (RSA-SHA256 / Ed25519-SHA256) | ✓ | You build it |
| HTML templates, attachments, batch sending | ✓ | You build it |
| Provider HTTP adapters (SendGrid, Mailgun, AWS SES) | ✓ | You build it |
| Middleware (logging, metrics, hooks, recovery) | ✓ | You build it |
| Header injection protection, address validation | ✓ | You build it |
| Async sending with a buffered worker queue | ✓ | You build it |
goemail isn't a replacement for net/smtp — the default Sender is built on
top of it. It's the reliability and delivery layer around raw SMTP that most
services sending email end up writing themselves, packaged once and kept
production-safe by default.
- 📤 SMTP Support - TLS/STARTTLS, authentication
- 📝 Templating - Go templates for HTML and plain text emails
- 📎 Attachments - Send files with proper MIME encoding
- 🔄 Retry Logic - Exponential backoff with configurable attempts
- ⚡ Rate Limiting - Built-in rate limiting to prevent overwhelming servers
- 🔍 Logging Interface - Bring your own logger (slog, zap, logrus, etc.)
- 🧪 Testing - Mock sender for easy testing
- 🎯 Builder API - Fluent, chainable API for constructing emails
- 🔒 Security - Email header injection protection, address validation
- 🎨 Batch Sending - Send multiple emails concurrently with limits
- 🔗 Connection Pooling - Reuse SMTP connections for high-throughput sending
- 🔌 Middleware Pipeline - Composable middleware for logging, metrics, recovery, and hooks
- 🔀 Async Sending - Background queue worker with configurable workers and buffer
- 🌐 Provider Adapters - SendGrid, Mailgun, and AWS SES via HTTP APIs (providers modules)
- ✍️ DKIM Signing - Sign outgoing emails with RSA-SHA256 or Ed25519-SHA256 (RFC 6376/8463)
- 📊 Context Support - Full context.Context integration for timeouts and cancellation
go get github.com/KARTIKrocks/goemailpackage main
import (
"context"
"log"
"time"
"github.com/KARTIKrocks/goemail"
)
func main() {
// Configure SMTP
config := email.SMTPConfig{
Host: "smtp.gmail.com",
Port: 587,
Username: "your-email@gmail.com",
Password: "your-app-password",
From: "your-email@gmail.com",
UseTLS: true,
}
// Create sender and mailer
sender, err := email.NewSMTPSender(config)
if err != nil {
log.Fatal(err)
}
mailer := email.NewMailer(sender, config.From)
defer mailer.Close()
// Send email
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
err = mailer.Send(ctx,
[]string{"recipient@example.com"},
"Hello!",
"This is a test email.",
)
if err != nil {
log.Fatal(err)
}
}// Create template
tmpl := email.NewTemplate("welcome")
tmpl.SetSubject("Welcome {{.Name}}!")
tmpl.SetHTMLTemplate(`
<!DOCTYPE html>
<html>
<body>
<h1>Hello {{.Name}}!</h1>
<p>Welcome to our service. Click below to get started:</p>
<a href="{{.VerifyLink}}">Verify Email</a>
</body>
</html>
`)
// Register template
mailer.RegisterTemplate("welcome", tmpl)
// Send using template
data := map[string]any{
"Name": "John Doe",
"VerifyLink": "https://example.com/verify/abc123",
}
err := mailer.SendTemplate(ctx, []string{"john@example.com"}, "welcome", data)// Read file
pdfData, _ := os.ReadFile("invoice.pdf")
email := email.NewEmail().
SetFrom("billing@example.com").
AddTo("customer@example.com").
SetSubject("Your Invoice").
SetBody("Please find your invoice attached.").
AddAttachment("invoice.pdf", "application/pdf", pdfData)
err := mailer.SendEmail(ctx, email)Full guides live at kartikrocks.github.io/goemail:
| Guide | Covers |
|---|---|
| Getting Started | Install and send your first email |
| SMTP & Configuration | SMTPConfig, provider relay settings (Gmail, SendGrid, SES, Mailgun), connection pooling |
| Mailer | Send, SendHTML, SendTemplate, batch sending, Close |
| Email Builder | The fluent Email builder API |
| Templates | Registering and rendering HTML/text templates |
| Middleware | Logging, metrics, recovery, and hooks middleware |
| Async Sending | Buffered worker queue for non-blocking sends |
| Reliability | Retry logic, rate limiting, context timeouts |
| DKIM Signing | RSA-SHA256 / Ed25519-SHA256 signing (RFC 6376/8463) |
| Provider Adapters | SendGrid, Mailgun, and AWS SES via HTTP APIs, plus the OpenTelemetry tracing middleware |
| Webhooks | Parsing provider delivery-event webhooks |
| Metrics | The MetricsCollector interface and a worked Prometheus example |
| Logging | Bringing your own logger |
| Security | Credential handling, header injection protection, address validation, App Passwords |
| Testing | Unit-testing code that sends email with MockSender |
Exact type signatures are generated from source on pkg.go.dev.
Runnable programs are in examples/ — basic, template,
attachment, batch, pool, middleware, and testing.
goemail signs and sends outbound mail with credentials and key material you
provide, so header/CRLF injection, credential handling, and DKIM signing are
treated as part of the API, not an afterthought. v0.2.0 (CHANGELOG.md)
enforced a minimum of TLS 1.2 on STARTTLS connections and closed several
CRLF/header-injection gaps that v0.1.0 did not catch.
Every push and pull request to main is scanned by
CodeQL,
with a full re-scan weekly to catch newly published query patterns against
unchanged code. govulncheck gates every merge on advisories that are
reachable from this code's call graph. Both run separately against each of
the five modules — the root package and the four providers/* sub-modules —
because a scan started from the root stops at the nested go.mod boundaries
and would miss the providers' own dependency trees. Dependabot tracks updates
across all five modules, the docs site, and the GitHub Actions themselves.
See SECURITY.md for supported versions, what is in scope, and how to report a vulnerability privately.
Contributions welcome! Please read CONTRIBUTING.md for guidelines.