How to Send Emails in Go

Go (informally known as Golang) is a popular back-end language born in Google labs back in 2007. The devs behind it were all frustrated with the omnipresent C++ (wonder why!) and, as history shows over and over again, such frustration often leads to building something great. Now, many years later, you might be sitting with a freshly delivered Gopher mascot on your desk, working on a Go project you picked up just for fun… and you’re gradually starting to regret your decision because you got stuck on such a simple thing as sending emails.

Despair no more! We’re covering various approaches for you so you can decide how to best handle such a useful functionality. Let’s get started!

Sending emails with smtp.SendMail

The Go language itself comes with dozens of diverse packages to enable new functionalities. These packages cover things such as file encryption, error handling, color palettes, or URL parsing; that is, lots of the features necessary to build a working web application. It’s no surprise that one of those packages is labeled as an SMTP.

SMTP (Simple Mail Transfer Protocol) is used to send email by moving messages between email clients and servers. Golang also relies on this protocol and offers a basic and easy way to add email functionality to a Go app by implementing a library . 

This package’s main function is SendMail with the following syntax:

func SendMail(addr server:port, a Auth, from email_address, to []email_address, msg []content_here) error

It lets you connect to a server (addr attribute, which must include a port number — for example, mail.mailtrap.io:123). You can then specify the authentication method (more about that below), the sender’s and recipient’s email addresses, and the HTML that will be included in the message. Finally, you can clarify what will happen should an error occur.

To authenticate, you can use either of the two available methods:

  • Plain authentication
  • Cram-MD5 authentication

Plain authentication is the most basic method of authorizing an email client to act on your behalf. You provide your user name and password, which are encoded with the basic base64 method. In Golang, this method is represented by the PlainAuth function and comes in the following shape:

func PlainAuth(identity, username, password, host server:port) Auth

Cram-MD5 is a bit more sophisticated. Using the provided credentials, it utilizes the challenge-response mechanism to authenticate with a server. It adds an extra layer of security and, although it comes with plenty of weaknesses, is still a more secure option than PlainAuth. The CRAMMD5Auth function comes with the following syntax:

func CRAMMD5Auth(username, secret string) Auth

Secret used in the previous code is either the user’s password or a hash of it.

Coming back to the smtp.SendMail function, here’s a sample code that uses PlainAuth to authenticate:

package main

import (
	"log"
	"net/smtp"
)

func main() {
	// Choose auth method and set it up
	auth := smtp.PlainAuth("", "piotr@mailtrap.io", "extremely_secret_pass", "smtp.mailtrap.io")

	// Here we do it all: connect to our server, set up a message and send it
	to := []string{"billy@microsoft.com"}
	msg := []byte("To: billy@microsoft.com\r\n" +
		"Subject: Why are you not using Mailtrap yet?\r\n" +
		"\r\n" +
		"Here’s the space for our great sales pitch\r\n")
	err := smtp.SendMail("smtp.mailtrap.io:25", auth, "piotr@mailtrap.io", to, msg)
	if err != nil {
		log.Fatal(err)
	}
}

Several things to note: The SendMail function will automatically use TLS encryption if the server supports it — any major SMTP server will do so. Also, SendMail doesn’t itself offer support for DKIM authentication or MIME attachments. Luckily, for the latter there’s an alternative method that works just fine. More about that later!

Server infrastructure for SendMail function

As you’ve probably noticed by now, we’ve already tried to connect to mail.maitrap.io several times, so that is obviously our Golang mail server. This is because we need to use a mail server, or at least something that resembles one, to handle sending email. You can compose the most effective email ever written, but without proper infrastructure, it won’t even reach the first handshake. 

One approach would be to use a regular Linux machine to work as a server. It would use a command-line utility called sendmail to handle email sending. This post gives a detailed clarification on what the process looks like.

Another approach to consider would be to use a dedicated server for SMTP transmission. Using Postfix and Ubuntu, you could easily set up the architecture and send the first emails in minutes.

Note, however, that if you’ve never used this server for sending emails, you will suffer because of its lack of reputation. As we’ve discussed in another article, receiving servers pay a lot of attention to the reputation of a server that’s trying to send them an email. If they don’t know it or, even worse, know it as sending rather spammy content, they’re likely to discard the message or, at best, place it in a spam folder. Use more “experienced” servers or utilize those provided by 3rd party providers.

If you’re on a budget and need to send only occasional messages, you can utilize Google’s SMTP server that comes with free Gmail or a paid Google Apps account. See this article for more detailed instructions on how to set it up. Google allows users to send up to 99 emails per day. The limit resets 24 hours after it’s reached. 

If you need something bigger but don’t want to set up your own server, you’ll want to look into integrating the API of a transactional email provider. More about that below.
Finally, chances are you want to send emails that are a bit more sophisticated than a typical “hello world.” Go supports HTML templates with its html/template package so you can build a beautiful, responsive template to send to your users. There’s a number of tutorials on building templates in Go; in our opinion, this one seems really interesting.

Other configurations

Sending an email to a single recipient is fairly simple, but what if we have several people in mind? Luckily, this is also really easy to set up. Let’s cut a piece of the code from the previous paragraph and focus solely on the message headers and body:

to := []string{"billy@microsoft.com"}
	msg := []byte("To: billy@microsoft.com\r\n" +
		"Subject: Why you’re not using Mailtrap yet?\r\n" +
		"\r\n" +
		"Here’s the space for our great sales pitch\r\n")

Notice how the recipient’s email address is placed in both the headers and the body. In order to send emails to more than one recipient, we’ll need to add them to both parts, separated by a comma.

to := []string{"billy@microsoft.com", “stevie@microsoft.com}
	msg := []byte("To: billy@microsoft.com, stevie@microsoft.com \r\n" +
		"Subject: Why you’re not using Mailtrap yet?\r\n" +
		"\r\n" +
		"Here’s the space for our great sales pitch\r\n")

Now, let’s assume this email is mainly addressed to Mr. Gates, but we want Mr. Ballmer to be cc’ed.

to := []string{"billy@microsoft.com"}
cc:= []string{“stevie@microsoft.com”}
	msg := []byte("To: billy@microsoft.com\r\n" +
		“cc: stevie@microsoft.com\r\n"
		"Subject: Why you’re not using Mailtrap yet?\r\n" +
		"\r\n" +
		"Here’s the space for our great sales pitch\r\n")

Finally, let’s imagine that we don’t want Bill to know that Steve knows. This is done differently by adding Steve to the function parameters but excluding him from the message headers.

to := []string{"billy@microsoft.com", “stevie@microsoft.com}
	msg := []byte("To: billy@microsoft.com\r\n" +
		"Subject: Why you’re not using Mailtrap yet?\r\n" +
		"\r\n" +
		"Here’s the space for our great sales pitch\r\n")

Okay, we’ve taken care of the recipients. Now, what if we want to include an attachment with our message? Golang uses the mime/multipart method by default for this purpose, but it’s far from straightforward. That’s why developers prefer 3rd-party libraries that simplify the process without adding too much boilerplate. Among them, Jordan Wright’s “email” library is the most popular. It can also be used to add cc or bcc along with other features. We strongly recommend it.

Using Golang’s API to connect 3rd party mailing services

If you’re going to be emailing hundreds or thousands of users, or are sending something a bit more sophisticated than password reset instructions, you will probably want to use something that is likewise more sophisticated. An obvious approach would be to connect your Go app to a 3rd party service that specializes in transactional mailings. This comes with several quite convincing benefits:

  • You can send emails from a recognizable domain with an established reputation. This can have a serious impact on your deliverability.
  • You can create beautiful email templates with drag & drop wizards, without the need to write any HTML.
  • Finally, you can preview your emails before they’re sent to avoid unpleasant surprises.

There’s a number of resources ready to work with Go that you can utilize. Mailgun offers its own SDK for Go. SendGrid also comes with its own community-driven Go library. If Mailjet is your choice, you’ll also find numerous code samples for Golang in their REST API docs. If you prefer other platforms, you’ll likely find other user-made libraries to make integration smoother.

Each of these platforms (except for Mandrill) comes with a free pricing tier that lets you use some functionalities and send a limited number of messages. 

Summary

This wraps up our rather quick guide to sending emails in Golang. As you can see, the choice comes down to either utilizing basic in-built functionalities of Go or connecting to 3rd parties to send emails on your behalf. 


If you’re also programming with other frameworks, check out our blog for detailed articles on sending emails in Django, Node.js, Python, and many others. We’ll be covering more soon, so stay tuned!