Amazon SES
SMTP
Django
Email Integration
Web Development

Amazon SES SMTP with Django

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Amazon SES works well with Django because Django already knows how to send mail through any standard SMTP server. The important part is configuring SES correctly: verify identities, get region-specific SMTP credentials, and point Django at the right SMTP endpoint.

Prepare SES Before Touching Django

A Django setting alone is not enough. In SES, you need three things first:

  1. A verified sender identity, usually a domain or specific email address.
  2. SMTP credentials created for the SES SMTP interface.
  3. Production access if your account is still in the SES sandbox.

SES SMTP credentials are not the same as a normal AWS access key in the way you use them. AWS provides a dedicated SMTP username and password flow, and those credentials are region-specific. That means the hostname and credentials for us-east-1 are different from what you would use in another region.

A common SMTP host looks like this:

text
email-smtp.us-east-1.amazonaws.com

For Django, the usual port choices are:

  • '587 with STARTTLS'
  • '465 with SSL'

Port 587 with TLS is the most common setup.

Configure Django Settings

Keep credentials out of source control. Read them from environment variables instead of hard-coding them in settings.py.

python
1import os
2
3EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
4EMAIL_HOST = os.environ["SES_SMTP_HOST"]
5EMAIL_PORT = 587
6EMAIL_HOST_USER = os.environ["SES_SMTP_USERNAME"]
7EMAIL_HOST_PASSWORD = os.environ["SES_SMTP_PASSWORD"]
8EMAIL_USE_TLS = True
9DEFAULT_FROM_EMAIL = "[email protected]"
10SERVER_EMAIL = "[email protected]"

Example environment values:

bash
export SES_SMTP_HOST="email-smtp.us-east-1.amazonaws.com"
export SES_SMTP_USERNAME="AKIAIOSFODNN7EXAMPLE"
export SES_SMTP_PASSWORD="your-smtp-password"

If you are using a deployment platform, map those values into its secret manager rather than exporting them manually on every boot.

Send a Test Email

Once settings are in place, use Django’s mail API:

python
1from django.core.mail import send_mail
2
3send_mail(
4    subject="SES test message",
5    message="Your Django app can send through Amazon SES.",
6    from_email="[email protected]",
7    recipient_list=["[email protected]"],
8    fail_silently=False,
9)

You can also test interactively:

bash
python manage.py shell
python
from django.core.mail import send_mail
send_mail("hello", "testing", "[email protected]", ["[email protected]"])

If the app raises SMTPAuthenticationError, check the region, username, and password first.

Sending HTML Email

Transactional mail usually needs both text and HTML versions. Django supports that directly:

python
1from django.core.mail import EmailMultiAlternatives
2
3message = EmailMultiAlternatives(
4    subject="Welcome",
5    body="Welcome to the site.",
6    from_email="[email protected]",
7    to=["[email protected]"],
8)
9message.attach_alternative(
10    "<p><strong>Welcome</strong> to the site.</p>",
11    "text/html",
12)
13message.send()

SES will accept the message over SMTP, but deliverability still depends on domain setup. In production, you should configure SPF, DKIM, and ideally DMARC for the sending domain.

Troubleshooting Real Failures

Two issues cause most SES and Django setup failures.

The first is sandbox mode. In the SES sandbox, you can only send to verified recipients. If mail succeeds in development but only to certain addresses, this is usually why.

The second is a region mismatch. Suppose your SMTP credentials were created in us-east-1, but Django is pointed at an endpoint in eu-west-1. Authentication will fail even if the username and password look correct.

Another useful check is connection security. Do not set both EMAIL_USE_TLS and EMAIL_USE_SSL to True. Pick the mode that matches the port you are using.

Common Pitfalls

Many developers assume SES SMTP uses their everyday AWS console login. It does not. Use SMTP credentials generated for SES.

Another mistake is forgetting identity verification. SES can reject mail from an address or domain that has not been verified, even though the SMTP connection itself works.

Hard-coding secrets in settings.py is also a bad habit. It creates rotation pain and increases the chance of leaking credentials.

Finally, do not stop at “email sent successfully” in application logs. Check SES metrics, bounce handling, and domain authentication records if delivery quality matters.

Summary

  • Django can use Amazon SES through the standard SMTP backend.
  • Verify the sender identity and create SES SMTP credentials first.
  • Use the region-specific SES SMTP hostname and matching credentials.
  • Store credentials in environment variables, not in source files.
  • Watch for sandbox restrictions, region mismatches, and TLS configuration errors.

Course illustration
Course illustration

All Rights Reserved.