---
title: "Migrating email to mailers"
version: 6.1
locale: en
source: https://docs.djangoproject.com/en/6.1/howto/mailers-migration/
canonical: https://djangodocs.dev/en/6.1/howto/mailers-migration/
---
# Migrating email to mailers

Django 6.1 introduced the [`MAILERS`](/en/6.1/ref/settings/#std-setting-MAILERS) setting, replacing
[`EMAIL_BACKEND`](/en/6.1/ref/settings/#std-setting-EMAIL_BACKEND) and several other `EMAIL_*` settings. It also
introduced [`mail.mailers`](/en/6.1/topics/email/#django.core.mail.mailers) for obtaining configured email backend
instances, replacing [`mail.get_connection()`](/en/6.1/topics/email/#django.core.mail.get_connection). A new `using` argument
replaces the earlier `connection` in Django functions that send email.

This guide provides details on migrating existing projects to the new mailers
functionality.

All Django projects that send email should:

- If using any third-party packages that send email, [verify their
  compatibility](#migrating-to-mailers-third-party) with [`MAILERS`](/en/6.1/ref/settings/#std-setting-MAILERS)
  before making other changes.
- [Update email-related settings](#migrating-to-mailers-settings).
- Run with deprecation warnings enabled (see
  [Resolving deprecation warnings](/en/6.1/howto/upgrade-version/#resolving-deprecation-warnings)) to identify
  other code needing updates.

  > **Note**
  >
  > Running tests may not identify all relevant deprecations. Test suites
  > often use a non-functional email backend (such as the memory backend that
  > Django [substitutes during tests](/en/6.1/topics/testing/tools/#topics-testing-email)), so can
  > miss deprecation warnings that are only issued from the production email
  > configuration.
  >
  > Consider running with deprecation warnings enabled in production to catch
  > those deprecations. Or carefully review your code (including third-party
  > packages) for use of any deprecated email features.

Other updates are needed only for projects or reusable Django libraries that
use these specific features:

- [Replacing get\_connection() and connection arguments](#migrating-to-mailers-get-connection)
- [Replacing fail\_silently](#migrating-to-mailers-fail-silently)
- [Migrating custom email backends](#migrating-to-mailers-email-backends)
- [Replacing auth\_user and auth\_password](#migrating-to-mailers-auth)
- [Updating AdminEmailHandler email\_backend](#migrating-to-mailers-adminemailhandler)

> **Deprecated since Django 6.1**
>
> Deprecated since version 6.1: The following settings and functions will be removed in Django 7.0:
>
> - [`EMAIL_BACKEND`](/en/6.1/ref/settings/#std-setting-EMAIL_BACKEND), [`EMAIL_FILE_PATH`](/en/6.1/ref/settings/#std-setting-EMAIL_FILE_PATH),
>   [`EMAIL_HOST`](/en/6.1/ref/settings/#std-setting-EMAIL_HOST), [`EMAIL_HOST_PASSWORD`](/en/6.1/ref/settings/#std-setting-EMAIL_HOST_PASSWORD),
>   [`EMAIL_HOST_USER`](/en/6.1/ref/settings/#std-setting-EMAIL_HOST_USER), [`EMAIL_PORT`](/en/6.1/ref/settings/#std-setting-EMAIL_PORT),
>   [`EMAIL_SSL_CERTFILE`](/en/6.1/ref/settings/#std-setting-EMAIL_SSL_CERTFILE), [`EMAIL_SSL_KEYFILE`](/en/6.1/ref/settings/#std-setting-EMAIL_SSL_KEYFILE),
>   [`EMAIL_TIMEOUT`](/en/6.1/ref/settings/#std-setting-EMAIL_TIMEOUT), [`EMAIL_USE_SSL`](/en/6.1/ref/settings/#std-setting-EMAIL_USE_SSL),
>   [`EMAIL_USE_TLS`](/en/6.1/ref/settings/#std-setting-EMAIL_USE_TLS)
> - [`mail.get_connection()`](/en/6.1/topics/email/#django.core.mail.get_connection) and the `connection` arguments to mail
>   functions
> - The `fail_silently` argument to [`send_mail()`](/en/6.1/topics/email/#django.core.mail.send_mail),
>   [`send_mass_mail()`](/en/6.1/topics/email/#django.core.mail.send_mass_mail), [`mail_admins()`](/en/6.1/topics/email/#django.core.mail.mail_admins), [`mail_managers()`](/en/6.1/topics/email/#django.core.mail.mail_managers),
>   and [`EmailMessage.send()`](/en/6.1/topics/email/#django.core.mail.EmailMessage.send)
> - The `auth_user` and `auth_password` arguments to [`send_mail()`](/en/6.1/topics/email/#django.core.mail.send_mail)
>   and [`send_mass_mail()`](/en/6.1/topics/email/#django.core.mail.send_mass_mail)
> - The `email_backend` argument to [`AdminEmailHandler`](/en/6.1/ref/logging/#django.utils.log.AdminEmailHandler)

## Migrating settings

Often, the only change needed to migrate to mailers is updating email-related
settings. In your project’s settings, define a [`MAILERS`](/en/6.1/ref/settings/#std-setting-MAILERS) dict with a
`"default"` entry matching the earlier `EMAIL_*` settings:

```
MAILERS = {
    "default": {
        "BACKEND": ...,  # value of EMAIL_BACKEND setting
        "OPTIONS": {
            # values from other deprecated EMAIL_* settings
            ...,
        },
    },
}
```

For example, to update these settings:

```
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
EMAIL_HOST = "mail.example.net"
EMAIL_USE_TLS = True
EMAIL_PORT = 587
EMAIL_HOST_USER = "user@example.net"
EMAIL_HOST_PASSWORD = "password"
```

use:

```
MAILERS = {
    "default": {
        "BACKEND": "django.core.mail.backends.smtp.EmailBackend",
        "OPTIONS": {
            "host": "mail.example.net",
            "use_tls": True,
            # port is not needed: it defaults to 587 with use_tls True.
            "username": "user@example.net",
            "password": "password",
        },
    },
}
```

The complete list of deprecated `EMAIL_*` settings and where they should be
moved in a [`MAILERS`](/en/6.1/ref/settings/#std-setting-MAILERS) configuration is:

- [`EMAIL_BACKEND`](/en/6.1/ref/settings/#std-setting-EMAIL_BACKEND) becomes `"BACKEND"`. If your settings didn’t
  define `EMAIL_BACKEND`, the default value was
  `"django.core.mail.backends.smtp.EmailBackend"` (which is also the default
  if a [`MAILERS`](/en/6.1/ref/settings/#std-setting-MAILERS) configuration doesn’t specify the `"BACKEND"`).
- [`EMAIL_FILE_PATH`](/en/6.1/ref/settings/#std-setting-EMAIL_FILE_PATH) becomes `"file_path"` in `"OPTIONS"` (with
  `"BACKEND"` set to `"django.core.mail.backends.filebased.EmailBackend"`).
- [`EMAIL_HOST`](/en/6.1/ref/settings/#std-setting-EMAIL_HOST) becomes `"host"` in `"OPTIONS"`. A `"host"` is
  required for the SMTP email backend. If your settings didn’t define
  `EMAIL_HOST`, set `"host"` to `"localhost"` (the default value for the
  deprecated setting).
- [`EMAIL_HOST_PASSWORD`](/en/6.1/ref/settings/#std-setting-EMAIL_HOST_PASSWORD) becomes `"password"` in `"OPTIONS"`.
- [`EMAIL_HOST_USER`](/en/6.1/ref/settings/#std-setting-EMAIL_HOST_USER) becomes `"username"` in `"OPTIONS"`. (Note
  `"username"` doesn’t quite follow the naming pattern for the other
  deprecated settings.)
- [`EMAIL_PORT`](/en/6.1/ref/settings/#std-setting-EMAIL_PORT) becomes `"port"` in `"OPTIONS"`. It can be omitted
  if the connection uses the default port for its security (465 for SSL, 587
  for TLS, or 25 for an unsecured SMTP connection).
- [`EMAIL_SSL_CERTFILE`](/en/6.1/ref/settings/#std-setting-EMAIL_SSL_CERTFILE) becomes `"ssl_certfile"` in `"OPTIONS"`.
- [`EMAIL_SSL_KEYFILE`](/en/6.1/ref/settings/#std-setting-EMAIL_SSL_KEYFILE) becomes `"ssl_keyfile"` in `"OPTIONS"`.
- [`EMAIL_TIMEOUT`](/en/6.1/ref/settings/#std-setting-EMAIL_TIMEOUT) becomes `"timeout"` in `"OPTIONS"`.
- [`EMAIL_USE_SSL`](/en/6.1/ref/settings/#std-setting-EMAIL_USE_SSL) becomes `"use_ssl"` in `"OPTIONS"`.
- [`EMAIL_USE_TLS`](/en/6.1/ref/settings/#std-setting-EMAIL_USE_TLS) becomes `"use_tls"` in `"OPTIONS"`.

For third-party or custom email backends, the available `"OPTIONS"` depend on
the backend. Refer to the third-party documentation, or for custom backends see
[Migrating custom email backends](#migrating-to-mailers-email-backends) below.

The [Configuring email](/en/6.1/topics/email/#topic-email-configuration) topic has more information on the
`MAILERS` setting and additional configuration examples.

## Reusable library readiness

In most cases, third-party packages that send email through Django will
continue working with projects whose settings have been upgraded to use
[`MAILERS`](/en/6.1/ref/settings/#std-setting-MAILERS). (If they use any deprecated mail features, those will of
course cause deprecation warnings.)

There are two deprecated features that are *not* supported when
[`MAILERS`](/en/6.1/ref/settings/#std-setting-MAILERS) is defined in a project’s settings:

- Trying to access any of the deprecated `EMAIL_*` settings on
  `django.conf.settings` (e.g., checking `settings.EMAIL_BACKEND` or using
  `settings.EMAIL_HOST_USER`).
- Calling [`mail.get_connection("path.to.EmailBackend")`](/en/6.1/topics/email/#django.core.mail.get_connection) with a specific backend path. (Other arguments to
  `get_connection()` are still supported, and will simply issue deprecation
  warnings when [`MAILERS`](/en/6.1/ref/settings/#std-setting-MAILERS) is defined.)

If a third-party package does either of those, projects that use it will not be
able to change to the [`MAILERS`](/en/6.1/ref/settings/#std-setting-MAILERS) setting until the package has been
updated.

### Solving “not available when MAILERS is defined” errors

If either of these errors are raised within a third-party package, that
indicates it is not compatible with the [`MAILERS`](/en/6.1/ref/settings/#std-setting-MAILERS) setting:

- `AttributeError: "The *name* setting is not available when MAILERS is
  defined"` where *name* is [`EMAIL_BACKEND`](/en/6.1/ref/settings/#std-setting-EMAIL_BACKEND), [`EMAIL_HOST`](/en/6.1/ref/settings/#std-setting-EMAIL_HOST),
  or one of the other deprecated settings.
- `RuntimeError: get_connection(backend, ...) is not supported with MAILERS.`

If you see these errors, check if a newer version of that dependency is
available. If not (and if there are no alternatives to that package), you will
need to remove [`MAILERS`](/en/6.1/ref/settings/#std-setting-MAILERS) from your settings and replace it with the
equivalent [deprecated email settings](#deprecated-email-settings) until
the package has been updated.

If those errors are coming from your own code, see the other sections in this
migration guide for recommended updates.

## Replacing `get_connection()` and `connection` arguments

The replacements for the deprecated [`mail.get_connection()`](/en/6.1/topics/email/#django.core.mail.get_connection) function
and `connection` arguments to other mail functions depend on how and why
the connections are being created:

- `get_connection()` called with no arguments

  Replace with [`mailers.default`](/en/6.1/topics/email/#django.core.mail.mailers.default). For example, update this code:

  ```
  connection = mail.get_connection()
  connection.send_messages([email1, email2])
  ```

  To:

  ```
  connection = mail.mailers.default
  connection.send_messages([email1, email2])
  ```

  Note that `mailers.default` *is* the default for Django’s mail-sending
  functions. Code like this:

  ```
  mail.send_mail(..., connection=mail.get_connection())
  ```

  can be updated to:

  ```
  mail.send_mail(...)  # No connection arg needed.
  ```
- `get_connection(fail_silently=True)`

  See [Replacing fail\_silently](#migrating-to-mailers-fail-silently).
- `get_connection(...)` called with any other arguments

  Define a custom [`MAILERS`](/en/6.1/ref/settings/#std-setting-MAILERS) configuration with the desired backend
  and options. Then refer to it in the `using` argument when sending mail,
  or obtain an email backend instance from [`mail.mailers`](/en/6.1/topics/email/#django.core.mail.mailers) with the
  configuration name.

  For example, to upgrade this code:

  ```
  connection = mail.get_connection(
      "path.to.custom.EmailBackend", option1=True, option2="value"
  )
  mail.send_mail(..., connection=connection)
  connection.send_messages([email1, email2])
  ```

  Define a custom [`MAILERS`](/en/6.1/ref/settings/#std-setting-MAILERS) configuration in your settings:

  ```
  MAILERS = {
      "default": {...},
      "custom": {
          "BACKEND": "path.to.custom.EmailBackend",
          "OPTIONS": {
              "option1": True,
              "option2": "value",
          },
      },
  }
  ```

  And then use it like this:

  ```
  mail.send_mail(..., using="custom")
  mail.mailers["custom"].send_messages([email1, email2])
  ```

## Replacing `fail_silently`

The deprecated `fail_silently` arguments to [`send_mail()`](/en/6.1/topics/email/#django.core.mail.send_mail),
[`send_mass_mail()`](/en/6.1/topics/email/#django.core.mail.send_mass_mail), [`mail_admins()`](/en/6.1/topics/email/#django.core.mail.mail_admins), [`mail_managers()`](/en/6.1/topics/email/#django.core.mail.mail_managers), and
[`EmailMessage.send()`](/en/6.1/topics/email/#django.core.mail.EmailMessage.send) can be replaced in several ways. Existing usage
seems to have several different expectations for the behavior, many of which
don’t match the actual (and email backend-dependent) implementation. Consider
removing `fail_silently` entirely if there is not a specific need for it.

Calls with `fail_silently=True` should be updated with one of these options,
depending on the caller’s intent:

- To send a message if email has been configured but avoid raising an error
  if it hasn’t (e.g., in a reusable library), wrap the send call in `try:` /
  `except mail.MailerDoesNotExist: pass`.
- To ignore *all* exceptions (e.g., to avoid cascading failures in an error
  handler that sends mail), wrap the send call in `try:` / `except
  Exception: pass`.
- To ignore only SMTP-related errors, wrap the send call in `try` /
  `except OSError: pass`. Note that this ignores both transient network
  glitches *and* SMTP configuration problems (just like the existing SMTP
  email backend `fail_silently` implementation).
- To ignore end user typos in `to` addresses and other delivery problems,
  remove the `fail_silently` argument. Recipient errors are not generally
  detected at send time, so using `fail_silently` for this purpose doesn’t
  accomplish anything and could mask other problems like configuration errors.

  (In *local delivery* configurations, SMTP servers may report some recipient
  errors at send time. If you are using `fail_silently` specifically to
  ignore those errors, consider instead intercepting
  [`SMTPRecipientsRefused`](https://docs.python.org/3/library/smtplib.html#smtplib.SMTPRecipientsRefused) and/or
  [`SMTPResponseException`](https://docs.python.org/3/library/smtplib.html#smtplib.SMTPResponseException)s with particular `smtp_code`
  values as a more precise filter.)
- To create an email configuration that ignores certain backend-dependent
  errors and reuse it for multiple sending operations, create a custom
  [`MAILERS`](/en/6.1/ref/settings/#std-setting-MAILERS) configuration with `"fail_silently": True` in the
  [`"OPTIONS"`](/en/6.1/ref/settings/#std-setting-MAILERS-OPTIONS), then refer to that configuration
  with `using` in the send call.

Calls with `fail_silently=False` should be updated to remove the
`fail_silently` arg, as that is the default.

## Migrating custom email backends

Custom `EmailBackend` implementations may need to be updated for
compatibility with mailers.

- In the backend’s `__init__()` method, accept explicit keyword arguments for
  all configuration options that can come from [`"OPTIONS"`](/en/6.1/ref/settings/#std-setting-MAILERS-OPTIONS). Backends that use custom settings for configuration can
  continue to do so (or not, as they choose), but keyword arguments should take
  precedence over settings.
- Accept variable `**kwargs` and pass them to superclass init. (This will
  include a new `alias` argument which must be passed to the superclass.)
  Ensure that any `**kwargs` used by the backend are *not* passed to
  superclass init, as that would generate an `InvalidMailer` error for
  unknown OPTIONS.
- Backends must now handle `fail_silently` themselves, if they want to
  support it. There is no requirement to support `fail_silently`, and
  backends that don’t offer it should eliminate that keyword argument. (Do not
  pass an explicit `fail_silently` arg to superclass init.)
- Do not accept variable positional `*args` or pass them to superclass init.

The `BaseEmailBackend` superclass now initializes an `alias` attribute.
This is useful for error messages (e.g., `raise InvalidMailer(f"Bad host
{host}", alias=self.alias)`), but should not be used for accessing
`settings.MAILERS` directly. All OPTIONS for a mailer configuration are
passed to backend init as keyword arguments.

For reusable libraries that want to support compatibility with deprecated mail
functions and settings, or that support older Django versions:

- A backend can detect it is being initialized without [`MAILERS`](/en/6.1/ref/settings/#std-setting-MAILERS) by
  checking if `self.alias is None`. (Django’s built-in backends check this to
  decide whether deprecated settings should be used.) Libraries supporting
  older Django versions will need to use `getattr(self, "alias", None)`.
- Backends that borrow Django’s SMTP email settings like [`EMAIL_HOST`](/en/6.1/ref/settings/#std-setting-EMAIL_HOST)
  must *not* try to access them when [`MAILERS`](/en/6.1/ref/settings/#std-setting-MAILERS) is in use (`self.alias
  is not None`), as this will cause a “not available when MAILERS is defined”
  `AttributeError`.
- Libraries supporting multiple Django versions can identify support for
  mailers with either `hasattr(django.core.mail, "mailers")` or
  `django.VERSION >= (6, 1)`.

## Replacing `auth_user` and `auth_password`

The deprecated `auth_user` and `auth_password` arguments to
[`send_mail()`](/en/6.1/topics/email/#django.core.mail.send_mail) and [`send_mass_mail()`](/en/6.1/topics/email/#django.core.mail.send_mass_mail) can be replaced by defining a
custom [`MAILERS`](/en/6.1/ref/settings/#std-setting-MAILERS) configuration with
`"username"` and `"password"` [`"OPTIONS"`](/en/6.1/ref/settings/#std-setting-MAILERS-OPTIONS), and
refer to that configuration with the `using` argument when sending mail.

For example, to upgrade:

```
mail.send_mail(..., auth_user="admin", auth_password="admin-password")
```

Add a custom [`MAILERS`](/en/6.1/ref/settings/#std-setting-MAILERS) configuration in your settings:

```
MAILERS = {
    # Existing default configuration.
    "default": {
        "OPTIONS": {
            "host": "smtp.example.com",
            "username": "default-user",
            "password": "default-password",
        },
    },
    # Duplicate the default configuration, changing the auth.
    "admin-config": {
        "OPTIONS": {
            "host": "smtp.example.com",
            "username": "admin",
            "password": "admin-password",
        },
    },
}
```

And then refer to it when sending:

```
mail.send_mail(..., using="admin-config")
```

## Updating AdminEmailHandler `email_backend`

The deprecated `email_backend` argument to the logging
[`AdminEmailHandler`](/en/6.1/ref/logging/#django.utils.log.AdminEmailHandler) can be replaced with a custom
[`MAILERS`](/en/6.1/ref/settings/#std-setting-MAILERS) configuration, referring to it with the `using`
argument.

For example, if your settings include:

```
LOGGING = {
    # ...
    "handlers": {
        "mail_admins": {
            "class": "django.utils.log.AdminEmailHandler",
            "email_backend": "third.party.EmailBackend",
        },
    },
    # ...
}
```

Replace that with:

```
LOGGING = {
    # ...
    "handlers": {
        "mail_admins": {
            "class": "django.utils.log.AdminEmailHandler",
            "using": "admin-logging",  # defined in MAILERS
        },
    },
    # ...
}

MAILERS = {
    "default": {...},
    "admin-logging": {
        "BACKEND": "third.party.EmailBackend",
    },
}
```
