Skip to content

Latest commit

Β 

History

591 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ“¨Β Β go-mail

Lightweight email package with multi-provider support (ses, mailgun, mandrill, postmark, resend, sendgrid, smtp)


Release Go Version License


CI / CD Β Β  Build Last Commit Β Β Β Β  Quality Β Β  Coverage
Security Β Β  Scorecard Security Β Β Β Β  Community Β Β  Contributors Bitcoin


Project Navigation

πŸš€Β Installation πŸ§ͺΒ ExamplesΒ &Β Tests πŸ“šΒ Documentation
🀝 Contributing πŸ› οΈΒ CodeΒ Standards ⚑ Benchmarks
πŸ€–Β AIΒ Usage βš–οΈΒ License πŸ‘₯Β Maintainers

Installation

go-mail requires a supported release of Go.

go get github.com/mrz1836/go-mail

Documentation

View the generated documentation

Quick Start

package main

import (
    "context"
    "log"

    gomail "github.com/mrz1836/go-mail"
)

func main() {
    // Configure the sender and at least one provider
    mail := &gomail.MailService{
        FromName:       "No Reply",
        FromUsername:   "no-reply",
        FromDomain:     "example.com",
        SendGridAPIKey: "SG.xxxx",
    }
    if err := mail.StartUp(); err != nil {
        log.Fatal(err)
    }

    // Create and send an email
    email := mail.NewEmail()
    email.Subject = "Welcome!"
    email.HTMLContent = "<p>Thanks for signing up.</p>"
    email.PlainTextContent = "Thanks for signing up."
    email.Recipients = []string{"Jane Doe <jane@example.com>"}

    result, err := mail.Send(context.Background(), email, gomail.SendGrid)
    if err != nil {
        log.Fatal(err)
    }
    log.Printf("sent via %s: %s", result.Provider, result.MessageID)
}

More complete examples (every provider, attachments, templates, failover and provider options) are in examples/examples.go.

Features

  • Supports multiple service providers (below), plus your own through the Provider interface
  • Failover across providers, with the provider's message id returned from Send
  • Provider-specific features through typed options (ie: Postmark message streams, SendGrid templates, Mailgun test mode)
  • AWS SES via static keys or the default credential chain (IAM role)
  • SMTP with STARTTLS or implicit TLS, optional authentication, and timeouts
  • Plain-text and HTML content
  • Recipients with display names (Jane Doe <jane@example.com>); duplicates across To, CC and BCC are removed
  • Multiple file attachments, plus inline (cid:) images
  • Custom headers, including one-click List-Unsubscribe (required by Gmail and Yahoo for bulk senders)
  • Tags, metadata, scheduled sending and idempotency keys (provider dependant)
  • Open & click tracking (provider dependant)
  • Inject css into html content
  • Basic template support
  • Max restrictions on To, CC and BCC
  • Secrets are redacted when the configuration is logged or marshaled to JSON
  • BCC recipients are never written into the message headers, and header values cannot inject new headers
Supported Service Providers
  • AWS SES (tags & metadata become message tags; tracking via a configuration set)
  • Mailgun (up to 10 tags; metadata becomes user variables; US or EU region)
  • Mandrill (recipients are not preserved: each To recipient only sees their own address)
  • Postmark (one tag per email: multiple tags are joined with a comma)
  • Resend (open & click tracking configured per domain)
  • SendGrid (native open & click tracking)
  • SMTP
Feature AWS SES Mailgun Mandrill Postmark Resend SendGrid SMTP
Tags βœ“ βœ“ βœ“ βœ“ βœ“ βœ“
Metadata βœ“ βœ“ βœ“ βœ“ βœ“ βœ“
Open / click tracking βœ“ βœ“ βœ“ βœ“
Scheduled send (SendAt) βœ“ βœ“ βœ“ βœ“
Idempotency key βœ“
Auto text βœ“ βœ“
View content link βœ“

When an email uses a feature its provider does not support, go-mail logs a warning (or returns ErrUnsupportedFeature when StrictFeatures is set). An unsupported SendAt is always an error, so a scheduled email is never sent early.

Mailgun detects an attachment's content type from its file name and uses the file name as the content id of an inline image, so inline attachments are sent named by their ContentID: use a content id with an extension (ie: logo.png, referenced as cid:logo.png).

Sending, Failover & Results
// Send returns the provider that accepted the email and its message id
result, err := mail.Send(ctx, email, gomail.Postmark, gomail.SendGrid) // tries Postmark, then SendGrid
if err != nil {
    return err
}
log.Printf("sent via %s: %s", result.Provider, result.MessageID)

// SendEmail is still available when only the error matters
err = mail.SendEmail(ctx, email, gomail.SMTP)

Every send is bounded by SendTimeout (default one minute) and honors the context. Attachments added with a reader are buffered on the first send, so the same email can be retried or failed over.

Provider-Specific Features

Each provider has a typed option that edits its native request right before it is sent, so anything the provider SDK supports is available. Options for other providers are ignored.

email.With(
    gomail.PostmarkOption(func(e *postmark.Email) { e.MessageStream = "broadcast" }),
    gomail.SendGridOption(func(m *mail.SGMailV3) { m.SetTemplateID("d-123") }),
    gomail.ResendOption(func(r *resend.SendEmailRequest) { r.TopicId = "topic_123" }),
    gomail.MailgunOption(func(m *mailgun.PlainMessage) { m.SetRequireTLS(true) }),
    gomail.MandrillOption(func(m *gochimp.Message) { m.Subaccount = "tenant-1" }),
    gomail.SESOption(func(in *ses.SendRawEmailInput) { in.FromArn = aws.String(arn) }),
)
Custom Providers & Clients

Register any Provider (a new service, a built-in provider with your own client, or a fake in tests). A registered provider is kept by StartUp.

// A custom provider
const SparkPost gomail.ServiceProvider = 100
err := mail.RegisterProvider(SparkPost, mySparkPostProvider)

// A built-in provider with a custom client (ie: SendGrid EU data residency)
client := sendgrid.NewSendClient(apiKey)
client.Request, _ = sendgrid.SetDataResidency(client.Request, "eu")
err = mail.RegisterProvider(gomail.SendGrid, gomail.NewSendGridProvider(client))

// A fake provider in your tests
err = mail.RegisterProvider(gomail.SMTP, fakeProvider)
Templates
htmlTemplate, _ := email.ParseHTMLTemplate("welcome.html") // {{.Styles}} is replaced with email.CSS, which is inlined
textTemplate, _ := email.ParseTextTemplate("welcome.txt")  // text/template: no HTML escaping
err := email.ApplyTemplates(htmlTemplate, textTemplate, data)
Configuration

A provider is loaded by StartUp for every service whose credentials are set.

Field Description
FromName, FromUsername, FromDomain Default sender (FromUsername and FromDomain are required)
AwsSesAccessID, AwsSesSecretKey AWS SES static credentials
AwsSesUseIAMRole Load AWS SES from the default credential chain instead of static keys
AwsSesRegion, AwsSesEndpoint, AwsSesConfigurationSet AWS SES region (default us-east-1), custom endpoint, and configuration set
MailgunAPIKey, MailgunDomain Mailgun credentials and sending domain (defaults to the domain of the from address)
MailgunAPIBase Mailgun API base URL (default US region; mailgun.APIBaseEU for the EU region)
MandrillAPIKey, PostmarkServerToken Mandrill and Postmark credentials
ResendAPIKey, SendGridAPIKey Resend and SendGrid credentials
SMTPHost, SMTPPort, SMTPUsername, SMTPPassword SMTP server (port defaults to 587; leave the username empty for a relay without auth)
SMTPImplicitTLS Connect with TLS from the start (always on for port 465)
AutoText, Important, TrackClicks, TrackOpens Defaults copied to every email created by NewEmail
EmailCSS Default CSS copied to every email (used by ParseHTMLTemplate)
MaxToRecipients, MaxCcRecipients, MaxBccRecipients Recipient limits (default 50 each)
MaxAttachmentSize Total attachment bytes per email (default 40 MiB, negative for no limit)
SendTimeout Maximum time for one provider send (default one minute, negative for no timeout)
StrictFeatures Return ErrUnsupportedFeature instead of logging a warning for unsupported features
Logger *slog.Logger for warnings (default slog.Default())
SMTP
  • Every send opens a new connection that honors the context deadline and cancellation
  • STARTTLS is used whenever the server offers it; set SMTPImplicitTLS (or port 465) for SMTPS
  • Server certificates are verified; credentials are never sent over an unencrypted connection (except to localhost)
  • PLAIN authentication is used, with LOGIN as a fallback for servers that only offer LOGIN (ie: Microsoft 365)
  • Use NewSMTPProvider with RegisterProvider for a custom tls.Config or EHLO name
Development Setup (Getting Started)

Install MAGE-X build tool for development:

# Install MAGE-X for development and building
go install github.com/mrz1836/mage-x/cmd/magex@latest
magex update:install
Library Deployment

This project uses goreleaser for streamlined binary and library deployment to GitHub. To get started, install it via:

brew install goreleaser

The release process is defined in the .goreleaser.yml configuration file.

Then create and push a new Git tag using:

magex version:bump bump=patch push=true branch=master

This process ensures consistent, repeatable releases with properly versioned artifacts and citation metadata.

Build Commands

View all build commands

magex help
GitHub Workflows

All workflows are driven by modular configuration in .github/env/ β€” no YAML editing required.

View all workflows and the control center β†’

Updating Dependencies

To update all dependencies (Go modules, linters, and related tools), run:

magex deps:update

This command ensures all dependencies are brought up to date in a single step, including Go modules and any managed tools. It is the recommended way to keep your development environment and CI in sync with the latest versions.


Examples & Tests

All unit tests and fuzz tests run via GitHub Actions and use Go version 1.26.x. View the configuration file.

Run all tests (fast):

magex test

Run all tests with race detector (slower):

magex test:race

Run the fuzz tests:

magex test:fuzz

Benchmarks

Run the Go benchmarks:

magex bench

Code Standards

Read more about this Go project's code standards.


πŸ€– AI Usage & Assistant Guidelines

Read the AI Usage & Assistant Guidelines for details on how AI is used in this project and how to interact with AI assistants.


Maintainers

MrZ
MrZ

Contributing

View the contributing guidelines and please follow the code of conduct.

How can I help?

All kinds of contributions are welcome πŸ™Œ! The most basic way to show your support is to star 🌟 the project, or to raise issues πŸ’¬. You can also support this project by becoming a sponsor on GitHub πŸ‘ or by making a bitcoin donation to ensure this journey continues indefinitely! πŸš€

Stars


License

License

About

πŸ“¨ Simple email interface across multiple service providers (ses, postmark, mailgun, mandrill, resend, sendgrid, smtp)

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

45 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages