Email Testing in Development


Testing software that requires unique email addresses is a pain. Automated testing tools can lessen the burden by using counters or random strings to create unique email addresses, but that stops at localized testing – those email addresses can’t actually receive mail. A common method often used to resolve this is a “catch-all” email alias that accepts any email sent to it and forwards it to a specfic address. While this method can work well for the solo developer, it’s inadequate in a team environment where each member needs to see the message.

Fortunately, Python has an excellent customizeable SMTP server built-in that we can leverage to help us create a simple system that accepts emails and forwards them onto the appropriate recipient.

For this to work we have a few prerequisites:

  • A pubicly accessible machine (i.e. EC2 micro instance, etc.) that can send outbound email and run a Python script
  • A domain name with DNS under our control
  • sendmail or another Mail Transfer Agent

Let’s begin:

Launch a publicly accessible server that can send outbound email

Log into the machine and start an MTA (like sendmail) running on localhost, only accepting connections from 127.0.0.1. Many Linux distributions come with sendmail pre-installed.

Create a subdomain for your development email addresses

Access the DNS zone for your domain and create an A record pointing to the public IP address of the server mentioned above. Then, create an MX record pointing to that subdomain as well.

Example:

devmail.example.org A 1.2.3.4
devmail.example.org MX 0 devmail.example.org

The following gist runs a simple SMTP server that accepts all mail sent to it and processes it as follows:

  • If recipient is a list of email addresses, only process the first email address found
  • If recipient is a single email address, process it as usual
  • Using the format account--anything@devmail.YOURDOMAIN.COM, extract the token before the double hyphen – if nothing is found, discard the message
  • If a string is found before the double-hypen, use it to build a real email address

Example:

joe--testing123@devmail.YOURDOMAIN.COM will be processed and re-sent to joe@YOURDOMAIN.COM

The script expects a local MTA to be running on localhost:587. Please be sure to not run that MTA on your public IP address and create an open SPAM relay.

Setup the SMTP server script to run in a daemon process

You can run the SMTP server script with any service monitor like upstart, supervisor, daemontools, etc.

To install supervisor:
> pip install supervisor

Add the following to the end of /etc/supervisor.conf:

[program:smtp-proxy]
command=/path/to/smtp_proxy.py 
user=root
redirect_stderr=true
exitcodes=1

To run on port 25 (or any port < 1024) the script will need to be run as root. If you can run on a port > 1024, please do so and replace user=root with another user on the system (also replacing ('0.0.0.0', 25) with the appropriate port in the SMTP server script).

Start the SMTP server with:
> supervisorctl -c /etc/supervisor.conf start smtp-proxy

Tail supervisor’s logs for any issues:
> tail -f /tmp/supervisord.log