Skip to main content

A Django email backend for Amazon's Simple Email Service

Project description

Info:A Django email backend for Amazon’s Simple Email Service
Author: Harry Marr (,
Collaborators:Paul Craciunoiu (,

pypi build python django

A bird’s eye view

Django-SES is a drop-in mail backend for Django. Instead of sending emails through a traditional SMTP mail server, Django-SES routes email through Amazon Web Services’ excellent Simple Email Service (SES).


For details about each release, see the GitHub releases page:

Using Django directly

Amazon SES allows you to also setup usernames and passwords. If you do configure things that way, you do not need this package. The Django default email backend is capable of authenticating with Amazon SES and correctly sending email.

Using django-ses gives you additional features like deliverability reports that can be hard and/or cumbersome to obtain when using the SMTP interface.

Note: In order to use smtp with Amazon SES, you may have to install some supporting packages for ssl. Check out this SMTP SSL email backend for Django

Why SES instead of SMTP?

Configuring, maintaining, and dealing with some complicated edge cases can be time-consuming. Sending emails with Django-SES might be attractive to you if:

  • You don’t want to maintain mail servers.
  • You are already deployed on EC2 (In-bound traffic to SES is free from EC2 instances).
  • You need to send a high volume of email.
  • You don’t want to have to worry about PTR records, Reverse DNS, email whitelist/blacklist services.
  • You want to improve delivery rate and inbox cosmetics by DKIM signing your messages using SES’s Easy DKIM feature.
  • Django-SES is a truely drop-in replacement for the default mail backend. Your code should require no changes.

Getting going

Assuming you’ve got Django installed, you’ll need Boto3 1.0.0 or higher. Boto is a Python library that wraps the AWS API.

You can do the following to install boto3 (we’re using –upgrade here to make sure you get the latest version):

pip install --upgrade boto3

Install django-ses:

pip install django-ses

Add the following to your

EMAIL_BACKEND = 'django_ses.SESBackend'

# These are optional -- if they're set as environment variables they won't
# need to be set here as well

# Additionally, if you are not using the default AWS region of us-east-1,
# you need to specify a region, like so:
AWS_SES_REGION_NAME = 'us-west-2'

Alternatively, instead of AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY, you can include the following two settings values. This is useful in situations where you would like to use a separate access key to send emails via SES than you would to upload files via S3:


Now, when you use django.core.mail.send_mail, Simple Email Service will send the messages by default.

Since SES imposes a rate limit and will reject emails after the limit has been reached, django-ses will attempt to conform to the rate limit by querying the API for your current limit and then sending no more than that number of messages in a two-second period (which is half of the rate limit, just to be sure to stay clear of the limit). This is controlled by the following setting:

AWS_SES_AUTO_THROTTLE = 0.5 # (default; safety factor applied to rate limit)

To turn off automatic throttling, set this to None.

Check out the example directory for more information.

Monitoring email status using Amazon Simple Notification Service (Amazon SNS)

To set this up, install django-ses with the events extra:

pip install django-ses[events]

Then add a event url handler in your

from django_ses.views import SESEventWebhookView
from django.views.decorators.csrf import csrf_exempt
urlpatterns = [ ...
                url(r'^ses/event-webhook/$', SESEventWebhookView.as_view(), name='handle-event-webhook'),

SESEventWebhookView handles bounce, complaint, send, delivery, open and click events. It is also capable of auto confirming subscriptions, it handles SubscriptionConfirmation notification.


  1. Add an SNS topic.

2. In SES setup an SNS destination in “Configuration Sets”. Use this configuration set by setting AWS_SES_CONFIGURATION_SET. Set the topic to what you created in 1.

3. Add an https subscriber to the topic. (eg. Do not check “Enable raw message delivery”.


Using signal ‘bounce_received’ for manager bounce email. For example:

from django_ses.signals import bounce_received
from django.dispatch import receiver

def bounce_handler(sender, mail_obj, bounce_obj, raw_message, *args, **kwargs):
    # you can then use the message ID and/or recipient_list(email address) to identify any problematic email messages that you have sent
    message_id = mail_obj['messageId']
    recipient_list = mail_obj['destination']
    print("This is bounce email object")


Using signal ‘complaint_received’ for manager complaint email. For example:

from django_ses.signals import complaint_received
from django.dispatch import receiver

def complaint_handler(sender, mail_obj, complaint_obj, raw_message,  *args, **kwargs):


Using signal ‘send_received’ for manager send email. For example:

from django_ses.signals import send_received
from django.dispatch import receiver

def send_handler(sender, mail_obj, send_obj, raw_message,  *args, **kwargs):


Using signal ‘delivery_received’ for manager delivery email. For example:

from django_ses.signals import delivery_received
from django.dispatch import receiver

def delivery_handler(sender, mail_obj, delivery_obj, raw_message,  *args, **kwargs):


Using signal ‘open_received’ for manager open email. For example:

from django_ses.signals import open_received
from django.dispatch import receiver

def open_handler(sender, mail_obj, open_obj, raw_message, *args, **kwargs):


Using signal ‘click_received’ for manager send email. For example:

from django_ses.signals import click_received
from django.dispatch import receiver

def click_handler(sender, mail_obj, bounce_obj, raw_message, *args, **kwargs):

SES Event Monitoring with Configuration Sets

You can track your SES email sending at a granular level using SES Event Publishing. To do this, you set up an SES Configuration Set and add event handlers to it to send your events on to a destination within AWS (SNS, Cloudwatch or Kinesis Firehose) for further processing and analysis.

To ensure that emails you send via django-ses will be tagged with your SES Configuration Set, set the AWS_SES_CONFIGURATION_SET setting in your to the name of the configuration set:

AWS_SES_CONFIGURATION_SET = 'my-configuration-set-name'

This will add the X-SES-CONFIGURATION-SET header to all your outgoing e-mails.

If you want to set the SES Configuration Set on a per message basis, set AWS_SES_CONFIGURATION_SET to a callable. The callable should conform to the following prototype:

def ses_configuration_set(message, dkim_domain=None, dkim_key=None,
                            dkim_selector=None, dkim_headers=()):
    configuration_set = 'my-default-set'
    # use message and dkim_* to modify configuration_set
    return configuration_set

AWS_SES_CONFIGURATION_SET = ses_configuration_set


  • message is a django.core.mail.EmailMessage object (or subclass)
  • dkim_domain is a string containing the DKIM domain for this message
  • dkim_key is a string containing the DKIM private key for this message
  • dkim_selector is a string containing the DKIM selector (see DKIM, below for explanation)
  • dkim_headers is a list of strings containing the names of the headers to be DKIM signed (see DKIM, below for explanation)


Using DomainKeys is entirely optional, however it is recommended by Amazon for authenticating your email address and improving delivery success rate. See Besides authentication, you might also want to consider using DKIM in order to remove the via message shown to gmail users - see

Currently there are two methods to use DKIM with Django-SES: traditional Manual Signing and the more recently introduced Amazon Easy DKIM feature.


Easy DKIM is a feature of Amazon SES that automatically signs every message that you send from a verified email address or domain with a DKIM signature.

You can enable Easy DKIM in the AWS Management Console for SES. There you can also add the required domain verification and DKIM records to Route 53 (or copy them to your alternate DNS).

Once enabled and verified Easy DKIM needs no additional dependencies or DKIM specific settings to work with Django-SES.

For more information and a setup guide see:

Manual DKIM Signing

To enable Manual DKIM Signing you should install the pydkim package and specify values for the DKIM_PRIVATE_KEY and DKIM_DOMAIN settings. You can generate a private key with a command such as openssl genrsa 512 and get the public key portion with openssl rsa -pubout <private.key. The public key should be published to if your domain is You can use a different name instead of ses by changing the DKIM_SELECTOR setting.

The SES relay will modify email headers such as Date and Message-Id so by default only the From, To, Cc, Subject headers are signed, not the full set of headers. This is sufficient for most DKIM validators but can be overridden with the DKIM_HEADERS setting.



Example DNS record published to Route53 with boto:

route53 add_record ZONEID TXT ‘“v=DKIM1; p=xxx”’ 86400

SES Sending Stats

Django SES comes with two ways of viewing sending statistics.

The first one is a simple read-only report on your 24 hour sending quota, verified email addresses and bi-weekly sending statistics.

To generate and view SES sending statistics reports, include, update INSTALLED_APPS:

    # ...
    # ...

… and

urlpatterns += (url(r'^admin/django-ses/', include('django_ses.urls')),)

Optional enhancements to stats:

Store daily stats

If you need to keep send statistics around for longer than two weeks, django-ses also comes with a model that lets you store these. To use this feature you’ll need to run:

python migrate

To collect the statistics, run the get_ses_statistics management command (refer to next section for details). After running this command the statistics will be viewable via /admin/django_ses/.

Django SES Management Commands

To use these you must include django_ses in your INSTALLED_APPS.

Managing Verified Email Addresses

Manage verified email addresses through the management command.

python ses_email_address –list

Add emails to the verified email list through:

python ses_email_address –add

Remove emails from the verified email list through:

python ses_email_address –delete

You can toggle the console output through setting the verbosity level.

python ses_email_address –list –verbosity 0

Collecting Sending Statistics

To collect and store SES sending statistics in the database, run:

python get_ses_statistics

Sending statistics are aggregated daily (UTC time). Stats for the latest day (when you run the command) may be inaccurate if run before end of day (UTC). If you want to keep your statistics up to date, setup cron to run this command a short time after midnight (UTC) daily.

Django Builtin-in Error Emails

If you’d like Django’s Builtin Email Error Reporting to function properly (actually send working emails), you’ll have to explicitly set the SERVER_EMAIL setting to one of your SES-verified addresses. Otherwise, your error emails will all fail and you’ll be blissfully unaware of a problem.

Note: You will need to sign up for SES and verify any emails you’re going to use in the from_email argument to django.core.mail.send_email(). Boto has a verify_email_address() method:


django-ses requires boto3 and django >= 2.2.

Full List of Settings

Required. Your API keys for Amazon SES.
Required. Alternative API keys for Amazon SES. This is useful in situations where you would like to use separate access keys for different AWS services.
Optionally specify what region your SES service is using. Note that this is required if your SES service is not using us-east-1, as omitting these settings implies this region. Details:
Instruct Amazon SES to forward bounced emails and complaints to this email. For more information please refer to
Optional. Use this to mark your e-mails as from being from a particular SES Configuration Set. Set this to a string if you want all messages to have the same configuration set. Set this to a callable if you want to set configuration set on a per message basis.
Default Django setting, optionally set this. Details:
Optional. If these settings are defined and the pydkim module is installed then email messages will be signed with the specified key. You will also need to publish your public key on DNS; the selector is set to ses by default. See for further detail.
Optional. Default is True. Verify the contents of the message by matching the signature you recreated from the message contents with the signature that Amazon SNS sent with the message. See for further detail.
Optional. Default is ‘’ and ‘’.


If you are using a proxy, please enable it via the env variables.

If your proxy server does not have a password try the following:

import os
os.environ["HTTP_PROXY"] = ""
os.environ["HTTPS_PROXY"] = ""

if your proxy server has a password try the following:

import os
os.environ["HTTP_PROXY"] = ""
os.environ["HTTPS_PROXY"] = ""



If you’d like to fix a bug, add a feature, etc

  1. Start by opening an issue.
    Be explicit so that project collaborators can understand and reproduce the issue, or decide whether the feature falls within the project’s goals. Code examples can be useful, too.
  2. File a pull request.
    You may write a prototype or suggested fix.
  3. Check your code for errors, complaints.
  4. Write and run tests.
    Write your own test showing the issue has been resolved, or the feature works as intended.

Running Tests

To run the tests:


If you want to debug the tests, just add this file as a python script to your IDE run configuration.

Creating a Release

To create a release:

virtualenv -p python3 ~/.virtualenvs/django-ses
workon django-ses
pip3 install twine
python3 sdist
python3 bdist_wheel --universal
twine upload dist/*

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Files for django-ses, version 2.2.1
Filename, size File type Python version Upload date Hashes
Filename, size django_ses-2.2.1-py2.py3-none-any.whl (26.3 kB) File type Wheel Python version py2.py3 Upload date Hashes View
Filename, size django-ses-2.2.1.tar.gz (41.8 kB) File type Source Python version None Upload date Hashes View

Supported by

AWS AWS Cloud computing Datadog Datadog Monitoring DigiCert DigiCert EV certificate Facebook / Instagram Facebook / Instagram PSF Sponsor Fastly Fastly CDN Google Google Object Storage and Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Salesforce Salesforce PSF Sponsor Sentry Sentry Error logging StatusPage StatusPage Status page