Automating Emails with Go

How to send HTML emails using the Go standard library

Jonathan Thompson
Geek Culture
5 min readSep 10, 2021

--

Photo by Stephen Phillips - Hostreviews.co.uk on Unsplash

I started learning Go in July to support my transition from Senior QA Engineer to a position as a Software Engineer. During this time, I binged Udemy courses, books, and articles to learn the ins and outs of the language. However, learning a language is more than simply reading and watching videos; it takes doing to really become proficient.

With that in mind, I began searching for projects to tackle in order to exercise my newfound love of Go.

Fantasy Football and Go

I have been playing fantasy football since 2016, having started with a single league and since expanding to three per year. This year, I took the next step in assuming the role of commissioner for Pendo’s fifth fantasy season. As part of this change, I wanted to commemorate my first season leading a group of fantasy leagues by providing my players with something special, a weekly digest covering news and notes for our leagues.

My initial thought was to send out a weekly email to each player within the league. In the formulation stage, I would write out a basic text email, then manually send it one-by-one to each league member by inputting an email gathered from a Google sheet. With 36 members across three leagues, this was bound to be tedious.

So how could I expedite this process?

The answer? Go.

Importing a CSV

The first thing that I had to do was import data from the Google sheet as I was definitely not going to manually enter 36 emails into Gmail. The easiest way to do this would be to download the sheet as a CSV, then import.

Let’s use this CSV for this tutorial:

players.csv

Thankfully, I had learned to import CSV files while taking Todd McLeod’s Web Development with Google’s Go Programming Language course on Udemy.

The first thing that we need to do is create a function that takes a file name for a CSV file within our directory. Then use the standard os package to open the file. We can then use the newly opened file to act as a reader for the csv package to generate a new CSV reader.

Once done, we use the readAll method to gather all rows of the CSV file, then iterate through.

Running this will return a slice of slices containing row data.

Output from printing rows.

We can clean this up by thinking of how our data is structured. Each slice contains a player name and email. We can create a struct using this information, then create an empty slice of said struct. This allows us to use dot notation later in our code.

Once we iterate through our rows, we can add row data to a struct literal and append that to our empty slice. Finally, we return the slice from the function.

Sending Emails

Now that we have data, we can use this to send our emails. For this, we will use the net/smtp package. I followed a basic tutorial for setup.

The first thing that we need to do is create a function for sending an email, import our CSV within the function, then iterate through our data. Next, we will build a struct for a server, then add a method for building an address.

We can now build a message header featuring a From, To, Subject, and Body. We will use this when sending our email.

Email messages must be sent as bytes so we convert from a string to byte, then return. We can now build out our authorization and use the net/smtp package to send a basic email.

Running this will send an email, like so:

I clearly need to check my email more often.

That doesn’t look very great, does it?

We can dress it up a bit by sending an HTML email instead. To do this, we need to modify our existing code so that it parses an HTML template, then inserts the template as the email body. HTML emails allow us to use images such as company logos, as well as styling for a more engaging email.

Designing and Parsing a Template

To start, we need to design an HTML template. While I have not worked in the front end for years now, I would like to think I still understand basic HTML.

We will start off by adding style tags so we can make our email mobile friendly. The last thing we want to do is send an email to a user that cannot read it on all of their devices. Ideally, we would like our content to be centered in the middle of the page and take up about 33% of the screen space. That way, the reader does not have to scan their entire screen just to read the content of the email. On mobile however, we would like the content to take up the entire screen.

Once the styling is finished, we can begin adding to the body with a header and content.

A mobile-friendly email template.

Now that our template has been built, we will go ahead and build a function for parsing templates and sending the result as an email body. To do so, we need to use the html/template package in Go’s standard library.

We can use the ParseFiles function to load a template file, then use the bytes package to generate a new Buffer. Buffers implement the io.Writer interface, allowing it to be used in the template Execute method. Finally, we will use the String method for our Buffer to return a string version of the template.

Putting this all together will allow you to send emails that look like this:

The most recent edition of Pendo’s Fantasy Football Digest.

Summary

Sending a batch of emails is easy using Go’s powerful standard library. The encoding/csv package allows us to read CSV files while the net/smtp package gives us the ability to send basic emails. With html/template, we can parse rich HTML templated emails for an even more dynamic mailing.

Jonathan Thompson is an Associate Software Engineer, Backend at Pendo.io. He currently resides in Raleigh, NC with his wife and a Goldendoodle named Winston. You can connect with him on LinkedIn, or follow him on either Twitter or Github.

--

--

Jonathan Thompson
Geek Culture

Writing about Golang, JavaScript, and Python with a little test automation