• 3.1
  • 3.2
  • 5.0
  • Версия документации: 6.1

Отправка электронных писем

Хотя Python позволяет легко отправлять электронные письма с помощью модуля smtplib, Django предоставляет несколько дополнительных функций. Они позволяют быстро отправлять письма, легко отлаживать оправку при разработке, и предоставляют поддержку окружений, которые не могут использовать SMTP.

Код находится в модуле django.core.mail.

Быстрые примеры

Используйте send_mail() для простой отправки электронной почты. Например, чтобы отправить обычное текстовое сообщение:

from django.core.mail import send_mail

send_mail(
    "Subject here",
    "Here is the message.",
    "from@example.com",
    ["to@example.com"],
    fail_silently=False,
)

Если необходимы дополнительные функции отправки электронной почты, используйте EmailMessage или EmailMultiAlternatives. Например, чтобы отправить составное электронное письмо, включающее версии HTML и обычный текст с определенным шаблоном и настраиваемыми заголовками, вы можете использовать следующий подход:

from django.core.mail import EmailMultiAlternatives
from django.template.loader import render_to_string

# First, render the plain text content.
text_content = render_to_string(
    "templates/emails/my_email.txt",
    context={"my_variable": 42},
)

# Secondly, render the HTML content.
html_content = render_to_string(
    "templates/emails/my_email.html",
    context={"my_variable": 42},
)

# Then, create a multipart email instance.
msg = EmailMultiAlternatives(
    subject="Subject here",
    body=text_content,
    from_email="from@example.com",
    to=["to@example.com"],
    headers={"List-Unsubscribe": "<mailto:unsub@example.com>"},
)

# Lastly, attach the HTML content to the email instance and send.
msg.attach_alternative(html_content, "text/html")
msg.send()

Письмо отправлено через SMTP хост и порт, которые указаны в настройках EMAIL_HOST и EMAIL_PORT. Настройки EMAIL_HOST_USER и EMAIL_HOST_PASSWORD, если указаны, используются для авторизации на SMTP сервере, а настройки EMAIL_USE_TLS и EMAIL_USE_SSL указывают использовать ли безопасное соединение.

Примечание

При отправке письма через django.core.mail будет использоваться кодировка из DEFAULT_CHARSET.

send_mail()

send_mail(subject, message, from_email, recipient_list, *, fail_silently=False, auth_user=None, auth_password=None, connection=None, html_message=None)

Самый простой способ отправить письмо – использовать django.core.mail.send_mail().

Параметры subject, message, from_email и recipient_list являются обязательными.

  • subject: строка.

  • message: строка.

  • from_email: строка. Если None, Django будет использовать значение параметра DEFAULT_FROM_EMAIL.

  • recipient_list: список строк, каждая является email. Каждый получатель из recipient_list будет видеть остальных получателей в поле «To:» письма.

Следующие параметры являются необязательными и должны быть указаны в качестве аргументов ключевого слова, если они используются.

  • fail_silently: булево. При False send_mail вызовет smtplib.SMTPException. Смотрите документацию smtplib, чтобы узнать список всех ошибок, каждый из которых наследуется от SMTPException.

  • auth_user: необязательное имя пользователя, которое используется при авторизации на SMTP сервере. Если не указано, Django будет использовать значение EMAIL_HOST_USER.

  • auth_password: необязательный пароль, который используется при авторизации на SMTP сервере. Если не указано, Django будет использовать значение EMAIL_HOST_PASSWORD.

  • connection: необязательный бэкенд, который будет использоваться для отправки письма. Если не указан, будет использоваться бэкенд по умолчанию. Смотрите раздел о бэкендах для отправки электронной почты.

  • html_message: если html_message указано, письмо будет с multipart/alternative, и будет содержать message с типом text/plain, и html_message с типом text/html.

Возвращает количество успешно отправленных писем (которое будет 0 или 1, т.к. функция отправляет только одно письмо).

Не рекомендуется, начиная с версии 6.0: Передача параметров fail_silly и более поздних версий в качестве позиционных аргументов устарела.

send_mass_mail()

send_mass_mail(datatuple, *, fail_silently=False, auth_user=None, auth_password=None, connection=None)

django.core.mail.send_mass_mail() используется для массовой рассылки электронных писем.

datatuple – кортеж, каждый элемент которого следующего формата:

(subject, message, from_email, recipient_list)

fail_silly, auth_user, auth_password и connection имеют те же функции, что и в send_mail(). Если они используются, они должны быть переданы в качестве аргументов ключевого слова.

Каждый отдельный элемент datatuple создает отдельное сообщение электронной почты. Как и в send_mail(), получатели в одном и том же recipient_list будут видеть другие адреса в поле «Кому:» сообщения электронной почты.

Например, следующий код отправит два отдельных письма двум отдельным спискам получателей. Однако, будет использоваться одно подключения к почтовому серверу:

message1 = (
    "Subject here",
    "Here is the message",
    "from@example.com",
    ["first@example.com", "other@example.com"],
)
message2 = (
    "Another Subject",
    "Here is another message",
    "from@example.com",
    ["second@test.com"],
)
send_mass_mail((message1, message2), fail_silently=False)

Возвращает количество успешно отправленных писем.

Не рекомендуется, начиная с версии 6.0: Передача параметров fail_silly и более поздних версий в качестве позиционных аргументов устарела.

send_mass_mail() или send_mail()

Основное различие между send_mass_mail() и send_mail() заключается в том, что send_mail() открывает соединение с почтовым сервером при каждом запуске, тогда как send_mass_mail() использует одно соединение для всех своих сообщений. Это делает send_mass_mail() немного более эффективным.

mail_admins()

mail_admins(subject, message, *, fail_silently=False, connection=None, html_message=None)

django.core.mail.mail_admins() отправляет письма администраторам сайта, которые указаны в настройке ADMINS.

mail_admins() к заголовку письма добавляет префикс из EMAIL_SUBJECT_PREFIX, по умолчанию "[Django] ".

Заголовок «From:» будет содержать значение SERVER_EMAIL.

Этот метод существует для удобства и читаемости.

Если указан html_message, письмо будет с multipart/alternative, и будет содержать message с типом text/plain, и html_message с типом text/html.

Не рекомендуется, начиная с версии 6.0: Передача параметров fail_silly и более поздних версий в качестве позиционных аргументов устарела.

mail_managers()

mail_managers(subject, message, *, fail_silently=False, connection=None, html_message=None)

django.core.mail.mail_managers() аналогичен mail_admins(), но отправляет письма менеджерам сайта, которые указаны в MANAGERS.

Не рекомендуется, начиная с версии 6.0: Передача параметров fail_silly и более поздних версий в качестве позиционных аргументов устарела.

Примеры

Отправляет одно письмо john@example.com и jane@example.com, они оба указаны в «To:»:

send_mail(
    "Subject",
    "Message.",
    "from@example.com",
    ["john@example.com", "jane@example.com"],
)

Это отправляет сообщение на адреса john@example.com и jane@example.com, причем оба они получают отдельное электронное письмо:

datatuple = (
    ("Subject", "Message.", "from@example.com", ["john@example.com"]),
    ("Subject", "Message.", "from@example.com", ["jane@example.com"]),
)
send_mass_mail(datatuple)

Защищаемся от инъекции заголовков электронного письма

Инъекции заголовков – это атака, во время которой атакующий добавляет данные в заголовки письма «To:» и «From:», которое создает ваш код.

Функции электронной почты Django, описанные выше, защищают от внедрения заголовков, запрещая переводы строк в значениях заголовков. Если какой-либо subject, from_email или recipient_list содержит новую строку (в стиле Unix, Windows или Mac), функция электронной почты (например, send_mail()) вызовет ValueError и, следовательно, не отправит электронное письмо. Вы несете ответственность за проверку всех данных перед их передачей функциям электронной почты.

Если message содержит заголовки в начале, они просто будут выведены в начале содержимого письма.

Вот пример представления, которое берет subject, message и from_email из данных POST запроса, отправляет их на admin@example.com и перенаправляет на «/contact/thanks/», когда это будет сделано:

from django.core.mail import send_mail
from django.http import HttpResponse, HttpResponseRedirect


def send_email(request):
    subject = request.POST.get("subject", "")
    message = request.POST.get("message", "")
    from_email = request.POST.get("from_email", "")
    if subject and message and from_email:
        try:
            send_mail(subject, message, from_email, ["admin@example.com"])
        except ValueError:
            return HttpResponse("Invalid header found.")
        return HttpResponseRedirect("/contact/thanks/")
    else:
        # In reality we'd use a form class
        # to get proper validation errors.
        return HttpResponse("Make sure all fields are entered and valid.")
Changed in Django 6.0:

Старые версии вызывали django.core.mail.BadHeaderError из-за некоторых недопустимых заголовков. Это было заменено на ValueError.

Класс EmailMessage

Функции Django send_mail() и send_mass_mail() на самом деле представляют собой тонкие оболочки, использующие класс EmailMessage.

Не все возможности класса EmailMessage доступны через send_mail() и связанные с ним функции-оболочки. Если вы хотите использовать расширенные функции, такие как получатели со скрытой копией, вложения файлов или электронная почта, состоящая из нескольких частей, вам необходимо напрямую создать экземпляры EmailMessage.

Примечание

Это особенность конструкции. send_mail() и связанные с ним функции изначально были единственным интерфейсом, предоставляемым Django. Однако список принимаемых ими параметров со временем медленно расширялся. Имело смысл перейти к более объектно-ориентированному дизайну сообщений электронной почты и сохранить исходные функции только для обратной совместимости.

EmailMessage отвечает за создание самого сообщения электронной почты. За отправку электронного письма отвечает email-сервер.

Для удобства EmailMessage предоставляет метод send() для отправки одного электронного письма. Если вам нужно отправить несколько сообщений, API-интерфейс электронной почты предоставляет альтернативу.

Объекты EmailMessage

class EmailMessage

Класс EmailMessage инициализируется со следующими параметрами. Все параметры являются необязательными и могут быть установлены в любое время до вызова метода send().

Первые четыре параметра могут передаваться как позиционные аргументы или аргументы ключевого слова, но если используются позиционные аргументы, они должны быть в заданном порядке:

  • subject: Тема письма.

  • body: Содержимое письма. Необходимо указать обычный текст.

  • from_email: Адрес отправителя. Можно использовать как fred@example.com, так и Fred <fred@example.com>. Если не указан, будет использовать значение настройки DEFAULT_FROM_EMAIL.

  • to: Список, или кортеж, получателей.

Следующие параметры должны быть указаны в качестве аргументов ключевого слова, если они используются:

  • cc: Список, или кортеж, получателей, которые будут указаны в заголовке «Cc».

  • bcc: Список, или кортеж, адресов, которые будут указаны в заголовке «Bcc».

  • reply_to: Список, или кортеж, получателей, которые будут указаны в заголовке «Reply-To».

  • attachments: список вложений, которые можно добавить к сообщению. Каждый из них может быть экземпляром MIMEPart или EmailAttachment, или кортежем с атрибутами (имя файла, содержимое, mimetype).

    Changed in Django 5.2:

    Добавлена ​​поддержка элементов EmailAttachment в вложениях.

    Changed in Django 6.0:

    Добавлена ​​поддержка объектов MIMEPart в списке attachments.

    Не рекомендуется, начиная с версии 6.0: Поддержка устаревших объектов Python MIMEBase во вложениях устарела. Вместо этого используйте MIMEPart.

  • headers: Словарь дополнительных заголовков. Ключами являются названия заголовков, значения – содержимое заголовка. Вы сами должны убедиться в правильности заголовков. Соответствующий атрибут – extra_headers.

  • connection: экземпляр email backend. Используйте этот параметр, если вы отправляете EmailMessage через send() и хотите использовать одно и то же соединение для нескольких сообщений. Если этот параметр опущен, новое соединение создается при вызове send(). Этот параметр игнорируется при использовании send_messages().

Не рекомендуется, начиная с версии 6.0: Передача всех параметров, кроме первых четырех, в качестве позиционных аргументов не рекомендуется.

Например:

from django.core.mail import EmailMessage

email = EmailMessage(
    subject="Hello",
    body="Body goes here",
    from_email="from@example.com",
    to=["to1@example.com", "to2@example.com"],
    bcc=["bcc@example.com"],
    reply_to=["another@example.com"],
    headers={"Message-ID": "foo"},
)

Класс содержит следующие методы:

send(fail_silently=False)

Отправляет сообщение. Если соединение было указано при создании электронного письма, оно будет использоваться. В противном случае будет создан и использован экземпляр серверной части по умолчанию. Если аргумент ключевого слова fail_silly равен True, исключения, возникшие при отправке сообщения, будут отменены. Пустой список получателей не вызовет исключения. Он вернет «1», если сообщение было отправлено успешно, в противном случае — «0».

message(policy=email.policy.default)

Создает и возвращает объект Python email.message.EmailMessage, представляющий отправляемое сообщение.

Аргумент ключевого слова policy позволяет указать набор правил для обновления и сериализации представления сообщения. Это должен быть объект email.policy.Policy. По умолчанию: data:email.policy.default. В некоторых случаях вы можете использовать SMTP, SMTPUTF8 или пользовательскую политику. Например, django.core.mail.backends.smtp.EmailBackend использует политику SMTP для обеспечения окончания строк \r\n, как того требует протокол SMTP.

Если вам когда-нибудь понадобится расширить класс EmailMessage Django, вы, вероятно, захотите переопределить этот метод, чтобы поместить нужное вам содержимое в объект Python EmailMessage.

Changed in Django 6.0:

Был добавлен аргумент ключевого слова policy, а тип возвращаемого значения был обновлен до экземпляра EmailMessage.

recipients()

Возвращает список всех получателей сообщения, независимо от того, записаны ли они в атрибутах to, cc или bcc. Это еще один метод, который вам может потребоваться переопределить при создании подклассов, поскольку SMTP-серверу необходимо сообщить полный список получателей при отправке сообщения. Если вы добавите другой способ указания получателей в своем классе, их также необходимо будет вернуть из этого метода.

attach(filename, content, mimetype)
attach(mimepart)

Создает новое вложение и добавляет его в сообщение. Есть два способа вызвать attach():

  • Вы можете передать ему три аргумента: filename, content и mimetype. filename — это имя вложения файла, которое будет отображаться в электронном письме, content – это данные, которые будут содержаться внутри вложения, а mimetype — это необязательный тип MIME для вложения. Если вы опустите mimetype, тип контента MIME будет угадываться по имени файла вложения.

    Например:

    message.attach("design.png", img_data, "image/png")
    

    Если вы укажете mimetype message/rfc822, content может быть django.core.mail.EmailMessage или email.message.EmailMessage или email.message.Message в Python.

    Для mimetype, начинающегося с text/, ожидается, что содержимое будет строкой. Двоичные данные будут декодированы с использованием UTF-8, и если это не удастся, тип MIME будет изменен на application/octet-stream и данные будут прикреплены без изменений.

  • Или для вложений, требующих дополнительных заголовков или параметров, вы можете передать attach() один объект Python MIMEPart. Это будет прикреплено непосредственно к полученному сообщению. Например, чтобы прикрепить встроенное изображение с Content-ID:

    import email.utils
    from email.message import MIMEPart
    from django.core.mail import EmailMultiAlternatives
    
    message = EmailMultiAlternatives(...)
    image_data_bytes = ...  # Load image as bytes
    
    # Create a random Content-ID, including angle brackets
    cid = email.utils.make_msgid()
    inline_image = email.message.MIMEPart()
    inline_image.set_content(
        image_data_bytes,
        maintype="image",
        subtype="png",  # or "jpeg", etc. depending on the image type
        disposition="inline",
        cid=cid,
    )
    message.attach(inline_image)
    # Refer to Content-ID in HTML without angle brackets
    message.attach_alternative(f'… <img src="cid:{cid[1:-1]}"> …', "text/html")
    

    Документация Python email.contentmanager.set_content() описывает поддерживаемые аргументы для MIMEPart.set_content().

    Changed in Django 6.0:

    Добавлена ​​поддержка вложений MIMEPart.

    Не рекомендуется, начиная с версии 6.0: Поддержка вложений email.mime.base.MIMEBase устарела. Вместо этого используйте MIMEPart.

attach_file(path, mimetype=None)

Создает новое вложение, используя файл из вашей файловой системы. Вызовите его, указав путь к прикрепляемому файлу и, при необходимости, тип MIME, который будет использоваться для вложения. Если тип MIME опущен, он будет угадываться по имени файла. Вы можете использовать его так:

message.attach_file("/images/weather_map.png")

Для типов MIME, начинающихся с text/, двоичные данные обрабатываются как в attach().

class EmailAttachment
New in Django 5.2.

Именованный кортеж для хранения вложений к электронному письму.

Именованный кортеж имеет следующие индексы:

  • имя файла

  • содержание

  • миметип

Отправка содержимого разного типа

Отправка нескольких версий контента

Может быть полезно включить в электронное письмо несколько версий контента; Классический пример — отправка как текстовой, так и HTML-версии сообщения. С помощью библиотеки электронной почты Django вы можете сделать это, используя класс EmailMultiAlternatives.

class EmailMultiAlternatives

Подкласс EmailMessage, который позволяет добавлять дополнительные версии тела сообщения в электронном письме с помощью метода attach_alternative(). Это напрямую наследует все методы (включая инициализацию класса) от EmailMessage.

alternatives

Список именованных кортежей EmailAlternative. Это особенно полезно в тестах:

self.assertEqual(len(msg.alternatives), 1)
self.assertEqual(msg.alternatives[0].content, html_content)
self.assertEqual(msg.alternatives[0].mimetype, "text/html")

Альтернативы следует добавлять только с помощью метода attach_alternative() или передавать конструктору.

Changed in Django 5.2:

В старых версиях «альтернативы» представляли собой список обычных кортежей, в отличие от именованных кортежей EmailAlternative.

attach_alternative(content, mimetype)

Прикрепите к письму альтернативное представление тела сообщения.

Например, чтобы отправить комбинацию текста и HTML, вы можете написать:

from django.core.mail import EmailMultiAlternatives

subject = "hello"
from_email = "from@example.com"
to = "to@example.com"
text_content = "This is an important message."
html_content = "<p>This is an <strong>important</strong> message.</p>"
msg = EmailMultiAlternatives(subject, text_content, from_email, [to])
msg.attach_alternative(html_content, "text/html")
msg.send()
body_contains(text)
New in Django 5.2.

Возвращает логическое значение, указывающее, содержится ли предоставленный текст в теле письма и во всех прикрепленных альтернативах MIME-типа text/*.

Это может быть полезно при тестировании электронной почты. Например:

def test_contains_email_content(self):
    subject = "Hello World"
    from_email = "from@example.com"
    to = "to@example.com"
    msg = EmailMultiAlternatives(subject, "I am content.", from_email, [to])
    msg.attach_alternative("<p>I am content.</p>", "text/html")

    self.assertIs(msg.body_contains("I am content"), True)
    self.assertIs(msg.body_contains("<p>I am content.</p>"), False)
class EmailAlternative
New in Django 5.2.

Именованный кортеж для хранения альтернативных версий содержимого электронной почты.

Именованный кортеж имеет следующие индексы:

  • содержание

  • миметип

Обновление типа контента по умолчанию

По умолчанию тип MIME параметра body в EmailMessage"text/plain". Рекомендуется оставить это в покое, поскольку это гарантирует, что любой получатель сможет прочитать электронное письмо, независимо от его почтового клиента. Однако, если вы уверены, что ваши получатели могут обрабатывать альтернативный тип контента, вы можете использовать атрибут content_subtype в классе EmailMessage, чтобы изменить основной тип контента. Основным типом всегда будет ``»текст», но вы можете изменить подтип. Например:

msg = EmailMessage(subject, html_content, from_email, [to])
msg.content_subtype = "html"  # Main content is now text/html
msg.send()

Бэкенды для отправки электронной почты

Непосредственная отправка электронного письма происходит в бэкенде.

Бэкенд содержит следующие методы:

  • open() создает длительное соединение.

  • close() закрывает текущее соединение.

  • send_messages(email_messages) отправляет список объектов EmailMessage. Если соединение не открыто, этот вызов неявно откроет соединение, а затем закроет его. Если соединение уже открыто, оно останется открытым после отправки почты.

Может использоваться как контекстный менеджер, автоматически вызывая open() и close() при необходимости:

from django.core import mail

with mail.get_connection() as connection:
    mail.EmailMessage(
        subject1,
        body1,
        from1,
        [to1],
        connection=connection,
    ).send()
    mail.EmailMessage(
        subject2,
        body2,
        from2,
        [to2],
        connection=connection,
    ).send()

Получаем экземпляр бэкенда для отправки электронной почты

Функция get_connection() в django.core.mail возвращает экземпляр почтового сервера, который вы можете использовать.

get_connection(backend=None, *, fail_silently=False, **kwargs)

По умолчанию вызов get_connection() вернет экземпляр бэкенда, указанного в EMAIL_BACKEND. Если указать аргумент backend, будет создан указанный бэкенд.

Аргумент fail_silly, содержащий только ключевые слова, управляет тем, как серверная часть должна обрабатывать ошибки. Если fail_silly имеет значение True, исключения во время процесса отправки электронной почты будут игнорироваться.

Все остальные аргументы ключевых слов передаются непосредственно конструктору серверной части электронной почты.

Django предоставляет несколько бэкендов. Эти бэкенды, кроме SMTP (который используется по умолчанию), полезны только при разработке или тестировании. Вы можете создать собственный бэкенд.

Не рекомендуется, начиная с версии 6.0: Передача fail_silly в качестве позиционного аргумента устарела.

SMTP бэкенд

class backends.smtp.EmailBackend(host=None, port=None, username=None, password=None, use_tls=None, fail_silently=False, use_ssl=None, timeout=None, ssl_keyfile=None, ssl_certfile=None, **kwargs)

Бэкенд по умолчанию. Электронные письма отправляются через SMTP сервер.

Значение аргумента берется из соответствующей настройки, если аругмент None:

SMTP бэкенд используется в Django по умолчанию. Если вы хотите указать его явно, добавьте в настройки:

EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"

Если не указано, таймаут по умолчанию будет предоставлен socket.getdefaulttimeout(), который по умолчанию равен None (таймаут отсутствует).

Консольный бэкенд

Вместо отправки письма, бэкенд выведет его в стандартный вывод. По умолчанию консольный синдром пишет в stdout. Вы можете использовать объекты-потоки, указав параметр stream при создании соединения.

Чтобы указать этот бэкенд, добавьте следующее в настройки:

EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"

Этот бэкенд не следует использовать на боевом сервере, он создавался для разработки.

Файловый бэкенд

Серверная часть файла записывает электронные письма в файл. Новый файл создается для каждого нового сеанса, открываемого на этом сервере. Каталог, в который записываются файлы, берется либо из настройки EMAIL_FILE_PATH, либо из ключевого слова file_path при создании соединения с помощью get_connection().

Чтобы указать этот бэкенд, добавьте следующее в настройки:

EMAIL_BACKEND = "django.core.mail.backends.filebased.EmailBackend"
EMAIL_FILE_PATH = "/tmp/app-messages"  # change this to a proper location

Этот бэкенд не следует использовать на боевом сервере, он создавался для разработки.

Бэкенд в памяти

Серверная часть locmem хранит сообщения в специальном атрибуте модуля django.core.mail. Атрибут исходящие создается при отправке первого сообщения. Это список с экземпляром EmailMessage для каждого отправляемого сообщения.

Чтобы указать этот бэкенд, добавьте следующее в настройки:

EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend"

Этот бэкенд не следует использовать на боевом сервере, он создавался для разработки.

Средство запуска тестов Django автоматически использует этот бэкэнд для тестирования.

Dummy бэкенд

Этот бэкенд ничего не делает с почтой. Чтобы указать этот бэкенд, добавьте следующее в настройки:

EMAIL_BACKEND = "django.core.mail.backends.dummy.EmailBackend"

Этот бэкенд не следует использовать на боевом сервере, он создавался для разработки.

Есть и решения, поддерживаемые сообществом!

У Django динамичная экосистема. На странице «Экосистема сообщества» выделены серверные части электронной почты. Пакеты Django Email Grid предлагают вам еще больше возможностей!

Создание собственного бэкенда

Вы можете создать собственный бэкенд для отправки почты. В настройка EMAIL_BACKEND необходимо указать путь для импорта класса вашего бэкенда.

Пользовательские почтовые серверы должны быть подклассом BaseEmailBackend, который находится в модуле django.core.mail.backends.base. Пользовательский сервер электронной почты должен реализовать метод send_messages(email_messages)``. Этот метод получает список экземпляров EmailMessage и возвращает количество успешно доставленных сообщений. Если в вашем бэкэнде есть концепция постоянного сеанса или соединения, вам также следует реализовать методы open() и close(). Обратитесь к smtp.EmailBackend для эталонной реализации.

Отправка нескольких писем

Создание и закрытие SMTP-соединения (или любого другого сетевого подключения) – это дорогой процесс. Если вам необходимо отправить большое количество писем, есть смысл использовать одно SMTP-соединения, а не создавать каждый раз новое.

Есть два способа указать бэкенду использовать одно подключение.

Во-первых, вы можете использовать метод send_messages() для соединения. Это берет список экземпляров EmailMessage (или подкласса) и отправляет их все, используя одно соединение. Как следствие, любое соединение <EmailMessage>`, установленное для отдельного сообщения, игнорируется.

Например, если у вас есть функция get_notification_email(), которая возвращает список объектов EmailMessage, представляющих некоторые периодические электронные письма, которые вы хотите отправлять, вы можете отправлять эти электронные письма, используя один вызов send_messages():

from django.core import mail

connection = mail.get_connection()  # Use default email connection
messages = get_notification_email()
connection.send_messages(messages)

В этом примере send_messages() откроет соединение, отправит письма, и закроет соединение.

Второй вариант – использовать методы open() и close(), чтобы явно контролировать соединение. send_messages() не будет создавать и закрывать соединение, если оно уже создано. Поэтому, если вы создадите соединение, вы можете контролировать, когда оно будет закрыто. Например:

from django.core import mail

connection = mail.get_connection()

# Manually open the connection
connection.open()

# Construct an email message that uses the connection
email1 = mail.EmailMessage(
    "Hello",
    "Body goes here",
    "from@example.com",
    ["to1@example.com"],
    connection=connection,
)
email1.send()  # Send the email

# Construct two more messages
email2 = mail.EmailMessage(
    "Hello",
    "Body goes here",
    "from@example.com",
    ["to2@example.com"],
)
email3 = mail.EmailMessage(
    "Hello",
    "Body goes here",
    "from@example.com",
    ["to3@example.com"],
)

# Send the two emails in a single call -
connection.send_messages([email2, email3])
# The connection was already open so send_messages() doesn't close it.
# We need to manually close the connection.
connection.close()

Настройка почты при разработке

Иногда вы не хотите, чтобы Django отправлял почту. Например, при разработке сайта. Вряд ли вы захотите отправлять тысячи писем, но при этом необходимо проверить, что код их отправляет правильным получателям с правильным содержимым.

Самый простой способ настроить электронную почту для локальной разработки — использовать console почтовый сервер. Этот бэкэнд перенаправляет всю электронную почту на stdout, позволяя вам проверять содержимое почты.

Также можно использовать file. Этот бэкенд сохраняет содержимое каждого SMTP-соединения в файл.

Другой подход — использовать «тупой» SMTP-сервер, который получает электронные письма локально и отображает их на терминале, но фактически ничего не отправляет. Пакет aiosmtpd предоставляет способ сделать это:

python -m pip install "aiosmtpd >= 1.4.5"

python -m aiosmtpd -n -l localhost:8025

Эта команда запустит минимальный SMTP-сервер, прослушивающий порт 8025 локального хоста. Этот сервер выводит в стандартный вывод все заголовки и тело электронного письма. Затем вам нужно только установить EMAIL_HOST и EMAIL_PORT соответственно. Более подробное обсуждение параметров SMTP-сервера см. в документации модуля aiosmtpd.

Информацию об отправке электронной почты при тестировании смотрите в разделе Сервисы для отправки писем.

Back to Top