I used to dread developing code for email-related tasks. It always felt like it was difficult to get set up for, and that there was a lot of potential for things to go wrong. When the email task we’re working on is still underway, we want to avoid sending emails to people outside our development team, and even then we try to avoid inundating that short list of people with a slew of emails as minor adjustments continually get made and are tested.

Having worked with several different technologies, I’ve seen a number of approaches to handling this. Many of these approaches come with their own set of problems. I’m going to start off by illustrating a couple of bad examples, since it’s always nice when you can learn from others’ mistakes instead of learning the hard way. After that, we’ll dive into what I think is a good way to handle emails from a development environment.

Bad Examples I’ve Seen

Sending Emails to Database Records

In some systems I’ve worked on, emails were supposed to be sent to users that had database records. Often times, these user records represented real data, and hence had email addresses of people that we should not be emailing during the testing and development process. Unfortunately, I’ve seen times when those people were mistakenly emailed. That’s a problem!

This can be circumvented with an email address replacement. Logic can be set up in the codebase to swap out a real email address with a hardcoded representation of the developer’s email address; this way only the developer receives the email.

This requires modifications to the code itself, which is not ideal. This means either having to change the code back once it is production-ready, or setting up branching logic that determines if it’s being run from a production or development environment. While this works, I think we’d all prefer to avoid making code changes solely to accommodate the environment our code is being executed on.

Sending Emails in Bulk

Another problem I’ve seen occurred when the developer thought they were safe. Emails were only being sent to colleagues, but they were being sent off in bulk. A loop had been established to loop through the list of colleagues that could receive the email. This had been done so that each individual received their own separate email, which is nice so as not to expose other peoples’ email addresses.

Unfortunately, during development, the loop was not iterating properly, and would have looped indefinitely during testing had it not been interrupted. By the time this problem had been identified, it was already too late. Since emails were actually sending, the sheer volume of emails sent out caused the sender’s email domain to become blacklisted. This was a major problem!

How to Send Emails from a Dev Environment

MailHog

I no longer dread working on email-related tasks, and I owe this new outlook to having the proper toolkit to deal with things in a more elegant way. Lately, I’ve been turning to an application called MailHog. It’s a utility that works very much like an email server, but captures emails coming into a database, and provides a website interface for viewing those emails instead of actually delivering them to the targeted recipient (it does have an option to deliver the email after previewing).

There are several other utilities like MailHog, but I’ve found this one to be the easiest to set up and use. MailHog is written in GoLang, and so will compile for pretty much any platform you need it to run on. I’m on Windows, and there’s a binary I can download and run quite easily (without installation). They even provide a DOCKERFILE so that you can run it through Docker Hub if that’s your preference.

Best Practices

When I run it, I call it using the following switches so that it runs according to the configuration that I have chosen:

-smtp-bind-addr :2500 -api-bind-addr :8080 -ui-bind-addr :8080

Doing so tells it to listen for emails on port 2500 (most email servers use port 25), and allows me to view any emails it has received using a web browser pointed at http://localhost:8080

Once it’s running, make sure your code knows that your email server is located on localhost on port 2500, and all subsequent emails that it sends out should get trapped by MailHog. It’s that simple!

When all set up, you can rest assured that you’ll be able to see the emails as intended. The original recipient of the email will be retained, the content of the email can be viewed as HTML or text, you can preview/download attachments, etc.

When setting up any system for delivering emails, it’s always a good practice to configure the email server details in a single place. This is commonly done in a .env file, but not all technologies will be able to leverage such configuration. Assuming you’ve followed this kind of best practice, then only that configuration file will need to be updated as you move the project from development into sandbox/production environments.

I hope this helps you out and makes email-related tasks less of a burden. If you need help implementing something like this, feel free to drop us a note.