Django 6.1 landed on August 5 with a quiet change that has a loud deadline: EMAIL_BACKEND and every flat EMAIL_* setting are deprecated and will be removed in Django 7.0. The replacement is MAILERS — a named-dict system that mirrors how Django already handles databases, caches, and file storage. If your project sends email and you are running Django 6.1, it is printing RemovedInDjango70Warning right now. If you skip this migration and upgrade to 7.0, email breaks in production on day one, silently, before your first deployment finishes.
What Changed and Why It Is an Improvement
The old approach crammed all email configuration into a handful of top-level settings. One backend, one set of credentials, no first-class path for mixing transactional and marketing email in the same project without third-party hacks. MAILERS fixes all of that by adopting the same pattern Django already uses for DATABASES, CACHES, STORAGES, and TASKS: a named dictionary where each key is a backend alias and "default" is used when no alias is specified.
If you have touched the DATABASES dict, you already understand the mental model. The only new concept is the using argument on email-sending functions, which selects the mailer by alias at call time.
How to Migrate
The migration is mechanical. Here is the before-and-after for a standard SMTP setup.
Before (deprecated, removed in Django 7.0):
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
EMAIL_HOST = "smtp.example.com"
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = "noreply@example.com"
EMAIL_HOST_PASSWORD = env("EMAIL_PASSWORD")
After (Django 6.1+ MAILERS):
MAILERS = {
"default": {
"BACKEND": "django.core.mail.backends.smtp.EmailBackend",
"OPTIONS": {
"host": "smtp.example.com",
"port": 587,
"use_tls": True,
"username": "noreply@example.com",
"password": env("EMAIL_PASSWORD"),
"timeout": 60,
},
},
}
Remove the old flat settings once MAILERS is in place. Django 6.1 supports both simultaneously during a transition window, but the moment MAILERS is defined, the old settings emit the deprecation warning.
One more call-site change: the connection= argument to send_mail(), send_mass_mail(), and EmailMessage is now deprecated. Replace it with using=:
# Old (deprecated)
send_mail("Subject", "Body", from_email, [to_email], connection=my_conn)
# New
send_mail("Subject", "Body", from_email, [to_email], using="default")
The Feature That Makes the Migration Worth Doing Now
Compliance with a deprecation is not exciting. The multi-backend pattern is. Before MAILERS, routing different email types to different providers required either a third-party library or an ugly connection-factory wrapper. Now it is native:
MAILERS = {
"default": {
"BACKEND": "django.core.mail.backends.smtp.EmailBackend",
"OPTIONS": {
"host": "smtp.mailgun.org",
"port": 587,
"use_tls": True,
"username": env("MAILGUN_USER"),
"password": env("MAILGUN_PASSWORD"),
},
},
"marketing": {
"BACKEND": "anymail.backends.amazon_ses.EmailBackend",
"OPTIONS": {"region": "us-east-1"},
},
}
Transactional confirmations go through Mailgun via "default". Marketing blasts go through Anymail‘s Amazon SES backend via "marketing". Dev environments use a console backend without touching production credentials. This is the multi-provider setup that Rails developers have had for fifteen years and that Python developers have been patching around with third-party packages. It is now in core.
Compatibility Checks Before You Flip the Switch
Two popular packages have known breakage in Django 6.1 that you need to resolve before migrating.
django-ses below 4.8.0: Django 6.1 removed fail_silently from BaseEmailBackend.__init__(). Older versions of SESBackend still forwarded it, so instantiating the backend from a MAILERS alias raises InvalidMailer: Unknown options 'fail_silently'. Upgrade to django-ses 4.8.0 or later before adding MAILERS.
django-health-check: The health_check.Mail check raises AttributeError when EMAIL_BACKEND is absent and MAILERS is defined instead. Upgrade to the latest release of django-health-check to get the fix.
Anymail 15.2: No action needed. Anymail fully supports the MAILERS configuration with no code changes.
Two System Checks to Add to CI
Django 6.1 ships two new mail system checks. Add manage.py check --deploy to your CI pipeline if it is not there already — that is the only way to catch mail.E001, which fires when your "default" mailer uses a development-only backend like console or filebased in production.
- mail.W001 —
MAILERSis defined but has no"default"key. Every email send without an explicitusing=will fail at runtime. - mail.E001 —
MAILERS["default"]is a dev backend. Only triggered by--deploy. Add this flag to your production deployment check or your staging CI job.
One more trap: if your test suite uses override_settings to swap in locmem or dummy backends, it will not emit the deprecation warning. Teams have been surprised to find their code was still using the old flat settings because tests never triggered the warning. Audit settings.py directly rather than trusting test output.
The Timeline
Django 6.1 (August 2026): MAILERS is opt-in. Old settings still work but print RemovedInDjango70Warning. Django 7.0 (early 2027): EMAIL_BACKEND and all flat EMAIL_* settings are removed. After that, Django moves to an annual release cycle (DEP 20 accepted August 10) — 7.0 is the last version before the new cadence, making it a natural forcing function.
Read the official Django migration guide for the full list of deprecated call signatures. Migrate in Django 6.1 now. The migration is twenty minutes of settings work. Waiting until 7.0 forces a same-day fix during an upgrade, under pressure, in production.













