Implementing Amazon Simple Email Service for a Django Site

It's a good idea to set up a proper SMTP server that can handle large volumes of transactional emails that your application might need such as registration emails, password resets, etc. Amazon's Simple Email Service (SES) has a number of steps to set it up correctly for your website which we'll run through here.

You'll need just one additional Python package installing within your project. I use Docker for all of my development and production implementation, so I'll go through the steps using Docker. If you're using a Python virtual environment and a package manager like pipenv, the steps are exactly the same except that you will need to remove the docker component that is prepended to the commands.

Assuming that your Docker setup uses a service called 'web' for your Django project, install relevant project packages:

$ docker-compose exec web pipenv install django-ses

Next up, you'll need to configure your settings in your Django project. Make the region the one that is where the majority of your website visitors are likely to be located.

# Settings.py

# Django SES Email Backend Settings
EMAIL_BACKEND = 'django_ses.SESBackend'
AWS_SES_REGION_NAME = 'eu-west-1'
AWS_SES_REGION_ENDPOINT = 'email.eu-west-1.amazonaws.com'
AWS_ACCESS_KEY_ID = os.environ['AWS_ACCESS_KEY_ID']
AWS_SECRET_ACCESS_KEY = os.environ['AWS_SECRET_ACCESS_KEY']
EMAIL_HOST = os.environ['EMAIL_HOST']
EMAIL_HOST_USER = os.environ['EMAIL_HOST_USER']
EMAIL_HOST_PASSWORD = os.environ['EMAIL_HOST_PASSWORD']
EMAIL_PORT = 587
EMAIL_USE_TLS = True
DEFAULT_FROM_EMAIL = os.environ['DEFAULT_FROM_EMAIL']

 

Log in to your AWS Management Console and do a search for IAM.

Although this tutorial is not about setting up the Identity and Access Management for your Amazon account, it's recommended that you do so. In short, you'll need to set up a group with some policy permissions to handle whatever aspects of Amazon's Web Services that you wish to use. For now, create a group and then attach the policy called 'AmazonSESFullAccess' to the group.

You'll then need to create a user and attach that user to the group. This gives this user (namely you) full access to Amazon's Simple Email Service. If you don't use Identity and Access Management, then you'll be doing everything as the root user which isn't a safe way to manage your account.

Once you've set up what you need for now in Identity and Access Management, return to your AWS Management Console home page, then do another search for SES.

From here, you'll need to register your domain and whitelist a couple of emails so that they can be used during testing.

For domains, go to the domains section and then click 'Verify a New Domain' button and enter your details in there.

During this process, one TXT and 3 CNAME records will need to be added to your domain name settings with your domain name's registrar. This YouTube video may help you with this process.

The 'Verification Status' and 'DKIM Status' should both turn to verified in green text.

Similarly, for emails, you may want to add your own email there for testing as well as add another email address that can be used as your DEFAULT_FROM_EMAIL setting within your project. This might be an admin@... or a webmaster@... email address that is used for transactional emails within your application.

Once you're happy that your Simple Email Service has been set up, you should have been provided with the settings that you can use within your environment variables. There are many ways to use environment variables, however, we will place these in a .env file within our project's root directory whilst we're in development and add them within our Heroku console as 'Config Vars' for production.

Note there are no spaces either side of the equals signs and there are no quotation marks or apostrophes required to denote strings.

# .env file

# Django SES Email Backend Settings
AWS_ACCESS_KEY_ID=your-access-key-id-from-amazon
AWS_SECRET_ACCESS_KEY=your-aws-secret-key-from-amazon
EMAIL_HOST=email-smtp.eu-west-1.amazonaws.com
EMAIL_HOST_USER=your-email-host-user-from-amazon
EMAIL_HOST_PASSWORD=your-email-host-password-from-amazon
DEFAULT_FROM_EMAIL={FirstName} {LastName} <admin@{your-domain-name}.com>

If you've seen my other tutorial on setting up Amazon's S3 storage service, then you can use the same AWS_SECRET_KEY_ID and AWS_SECRET_ACCESS_KEY for both the S3 storage service and the Simple Email Service. If you would prefer to use a separate setting, then there is one that can be used. You should read the docs on PyPI for 'django-ses'.

You will now need to build your container. So far, you haven't seen the Docker build procedure which I'm using for my development setup, however, this specific docker-compose.yml file can be found in my GitHub repo for this website here.

$ docker-compose build

Now, it's time to test whether file uploads such as profile or post images are working as intended, so we will need to make sure that our Docker container is up and running.

$ docker-compose up
You should now be able to access your development version of your website at http://localhost:8001
 

Side Note: You may well use port 8000 for your development setup as that is the default Django development server, however, I configure my Docker setup to specifically use port 8001. I only do this so I can visually differentiate between a standard Django development web server and my Dockerized project.

The workflow for setting up a registration and password reset process for your website is a totally separate process and beyond the scope of this tutorial. If you do have this already working locally, then you should request a forgotten password and the email will be generated using Amazon's Simple Email Service and it will come from your chosen email address that you defined in the DEFAULT_FROM_EMAIL setting.

You can use Amazon's 'Send a Test Email' feature to test whether your email configuration regarding Amazon SES is correctly configured. If this all works from here, then you know that your next challenge is wiring everything up in Django correctly.