Library / SDK
xhit/go-simple-mail avatar
xhit/go-simple-mail

go-simple-mail: a Go SMTP client built for bulk sending and kept connections

Golang package for send email. Support keep alive connection, TLS and SSL. Easy for bulk SMTP.

700 stars108 forksGoMIT

At a glance

What is it?
go-simple-mail is a MIT licensed Go package that sends email over SMTP with a persistent connection, connect and send timeouts, TLS and STARTTLS, and a long list of message features from attachments to DKIM signing. It is the de facto fork of two unmaintained packages by Joe Grasse, and its latest tagged release is v2.16.0 from 2023.
Who is it for?
Adopt go-simple-mail if you need to send real email from Go and your volume is high enough that reconnecting for every message shows up in your logs, since the persistent connection and the separate connect and send timeouts are the reason the package exists. Do not adopt it if you need to send mail through a local Postfix or an HTTP API, because the package only speaks SMTP.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 7 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the package does and what it deliberately does not

The README opens with the claim that this is the best way to send emails in Go with SMTP keep alive and timeout for connect and send. The Introduction section is more measured: Go Simple Mail is a simple and efficient package to send emails, and it is well tested and documented. The scope limit is stated plainly in the same paragraph. Go Simple Mail can only send emails using an SMTP server, and the API is flexible enough that it is easy to implement other methods for sending emails using a local Postfix, an API, and so on. That sentence is a design statement, not a caveat. The library owns the SMTP conversation, the connection lifecycle and the message assembly, and it leaves the transport choice above SMTP to you.

A fork of two unmaintained packages

The provenance matters for judging the project, and the README is unusually open about it. The package contains, and is based on, two packages by Joe Grasse: the mail package, unmaintained since Jun 29, 2018, and the mime package, unmaintained since Oct 1, 2015. The README also states that a lot of changes in Go Simple Mail were sent with no response, which reads as an acknowledgement that upstream contributions were hard to land. Two things follow. First, the code lineage is old and the feature list is long, which is what you expect from a maintained fork of a dormant original. Second, the version numbering tells you where you stand: the module is github.com/xhit/go-simple-mail/v2, the README examples are stated to be for v2.2.0 and above, and the recent release tags are v2.16.0 from 2023-08-17, v2.15.0 from 2023-07-07 and v2.14.1 from 2023-07-06.

Keep alive, timeouts and the bulk sending path

This is the core of the package, and the README feature list names it directly: sending multiple emails with the same SMTP connection, described as keep alive or persistent connection, plus a timeout for connecting to an SMTP server and a timeout for sending an email. For a bulk sender, the difference between one TCP and TLS handshake per message and one handshake for the whole batch is the difference between a service that keeps up and one that falls over on a rate limit. The timeouts are separate on purpose, and the distinction matters operationally: a connect timeout catches an unreachable or blackholed relay, while a send timeout catches a server that accepted the connection and then stopped talking. The example code shows both set to ten seconds, and the package also offers the ability to send NOOP, RESET, QUIT and CLOSE to the SMTP client, which is what you need when you want to keep a connection warm between bursts rather than tearing it down.

Encryption, authentication and the TLS escape hatch

On the transport side the package supports SSL/TLS and STARTTLS, and it also supports an unencrypted connection, which the README marks as not recommended. Authentication covers PLAIN, LOGIN and CRAM-MD5 since v2.3.0, with AUTO added in v2.14.0 as the default mode, and since v2.10.0 you can connect to an SMTP server without authentication at all, which is what you need against a local relay. Custom TLS configuration has been available since v2.5.0, and the example shows it in a form that should make reviewers wince, InsecureSkipVerify set to true, with a comment saying it is useful for testing. That example is a trap in a tutorial, because the field it sets is exactly the one that disables certificate verification. Since v2.15.0 you can also send using a custom connection, which the README calls ideal for proxy, so you can hand the package a connection you have already established and secured yourself.

The message feature list, and what each addition cost

The feature list reads like a changelog accumulated over years, and each item carries the version it arrived in, which is how you can tell what is load bearing and what is recent. The base set covers multiple attachments by path, in base64 and from bytes since v2.6.0, inline attachments from file, base64 and bytes, multiple recipients, priority, reply to, sender and from, embedded images, HTML and text templates, automatic encoding of special characters, return path, alternative email body, CC and BCC, and custom headers in the message. Later additions include sending with a different envelope from since v2.7.0, sending an RFC822 formatted message since v2.8.0, text/calendar body support and a List-Unsubscribe header since v2.11.0, DKIM signing since v2.11.0, and Delivery Status Notification support since v2.16.0. Two of these have a dependency cost worth naming. DKIM signing is not implemented in the package, it is delegated, and the example imports github.com/toorop/go-dkim, which is the only entry in the go.mod require block. DSN is a MIME feature that most mail providers treat as an opt-in.

The three behaviour flags that will change your mail

The README documents three defaults that are worth checking against your own expectations before you send anything, because each one changes the bytes on the wire. First, by default duplicated recipients throws an error, and since v2.13.0 you can set email.AllowDuplicateAddress = true to skip the check. Second, by default the Bcc header is not set in the email, and since v2.14.0 you can set email.AddBccToHeader = true to add it, which matters because leaving it off hides recipients from each other but also means a Bcc list is not visible in the message itself. Third, all addresses are validated against RFC5322 by default, and setting email.UseProvidedAddress = true skips that validation, in which case you are responsible for ensuring a valid address is sent. Each of these is a deliberate default in the safe direction, and each is a switch you would only flip for a reason you can name.

Installing it and the first message

The package uses go modules, so installation is a single go get with the v2 path, and the go.mod file confirms the module path and the Go version requirement of 1.13, with the README stating Go 1.13+ is required.

go
server := mail.NewSMTPClient()

// SMTP Server
server.Host = "smtp.example.com"
server.Port = 587
server.Username = "[email protected]"
server.Password = "examplepass"
server.Encryption = mail.EncryptionSTARTTLS

// Variable to keep alive connection
server.KeepAlive = false

// Timeout for connect to SMTP Server
server.ConnectTimeout = 10 * time.Second

// Timeout for send the data and wait respond
server.SendTimeout = 10 * time.Second

The email itself is built with mail.NewMSG, which the README describes as a simple html with inline and CC example. Two API changes are worth knowing before you upgrade. In v2.2.0 the signatures of SetBody and AddAlternative stopped accepting raw strings such as text/html and text/plain and require the contentType constants TextHTML or TextPlain instead, and the README calls that a breaking change, notes that the upgrade is quite simple although it is not quite following semantic versioning, and gives the diff. The documentation is published on pkg.go.dev under the v2 path, and the repository root shows the implementation split across attach.go, auth.go, email.go, header.go, message.go and smtp.go with a matching test file for each.

console
$ go get github.com/xhit/go-simple-mail/v2

The usage example builds an SMTP client, points it at a host and port, sets credentials and the encryption mode, then connects. This is the shape of a first send.

The alternative, and the honest limits

The comparison to make is with the Go standard library, which ships net/smtp. The standard library can send mail, and it is what many projects reach for first, but it opens a connection per message, has no notion of a persistent session, and offers no separate connect and send timeouts, which is the exact set of gaps this package was written to fill. The README is blunt about the difference in one line, that sending from localhost is supported because the Go standard SMTP package cannot do that, with the reason supplied as an aside. Where the standard library wins is that it is in the standard library, and for a low volume of transactional mail the difference may not matter at all. The limits of go-simple-mail are the mirror image of its strengths. It speaks only SMTP, so if your provider only offers an HTTP API you are back to writing a client for that. It pulls in a DKIM dependency for one feature you may never enable, and it has had no tagged release since 2023, so the version you adopt today is the version you maintain yourself. The repository is not archived and the last push was on 2026-10-16, so work continues on the branch even though the newest tag is more than three years old.

Editorial conclusion

Adopt go-simple-mail if you need to send real email from Go and your volume is high enough that reconnecting for every message shows up in your logs, since the persistent connection and the separate connect and send timeouts are the reason the package exists. Do not adopt it if you need to send mail through a local Postfix or an HTTP API, because the package only speaks SMTP. Before you pin a version, read the release history yourself, since the most recent tag is v2.16.0 from 2023 while the last push was on 2026-10-16, and decide whether you want DKIM signing, which pulls in a separate dependency.

Frequently asked questions

What is go-simple-mail and what is it for?

It is a Go package for sending email over SMTP with keep alive and timeouts for both connecting to the server and sending the data. The README describes it as a simple and efficient package to send emails, and the API is flexible enough to build other sending methods on top of it.

How do I install go-simple-mail?

The package uses go modules, so you run go get github.com/xhit/go-simple-mail/v2. The go.mod file declares the module as github.com/xhit/go-simple-mail/v2 with go 1.13, and the README states Go 1.13+ is required.

How do I keep an SMTP connection alive for bulk sending with go-simple-mail?

You set server.KeepAlive on the SMTP client, and the README lists sending multiple emails with the same SMTP connection as a supported feature, alongside separate ConnectTimeout and SendTimeout settings. The package also lets you send NOOP, RESET, QUIT and CLOSE to the SMTP client.

What changed in go-simple-mail 2.2.0?

The signatures of SetBody and AddAlternative used to accept strings such as text/html and text/plain and now require the contentType constants TextHTML or TextPlain. The README calls it a breaking change and says the upgrade is quite simple, while noting it is not quite following semantic versioning.

Does go-simple-mail support DKIM signing and Delivery Status Notifications?

Yes. Support for adding a DKIM signature and for the List-Unsubscribe header are listed since v2.11.0, and Delivery Status Notification support is listed since v2.16.0. DKIM signing is delegated to the separate go-dkim package, which appears in the example code and in the go.mod requirements.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. Releases
  5. xhit/go-simple-mail on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/xhit-go-simple-mail.svg)](https://hysenlabs.com/projects/xhit-go-simple-mail)

Was this useful?