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

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

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

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

Примеры

In two lines:

from django.core.mail import send_mail

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

Письмо отправлено через 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, т.к. функция отправляет только одно письмо).

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_silently, auth_user и auth_password аналогичны параметрам send_mail().

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

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

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)

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

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.

mail_managers()

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

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

Примеры

Отправляет одно письмо 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()) вызовет исключение django.core.mail.BadHeaderError (дочерний класс ValueError), и ничего не оправит. Это ваша ответственность проверять все данные перед тем, как передать в функцию.

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

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

from django.core.mail import BadHeaderError, 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 BadHeaderError:
            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.')

Класс EmailMessage

Функции send_mail() и send_mass_mail() на самом деле обертки, которые используют класс EmailMessage.

Не все возможности EmailMessage доступны через send_mail() и остальные функции. Если вы хотите использовать дополнительные возможности, такие как получатели в BCC, отправка файла, или «multi-part» письмо, вам следует использовать непосредственно EmailMessage.

Примечание

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

EmailMessage отвечает за создание электронного письма. Бэкенд отправки писем отвечает за отправку писем.

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

Объекты EmailMessage

class EmailMessage

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

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

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

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

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

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

  • connection: An email backend instance. Use this parameter if you want to use the same connection for multiple messages. If omitted, a new connection is created when send() is called.

  • attachments: Список вложений. Могут быть экземпляры email.MIMEBase.MIMEBase, или кортежи (filename, content, mimetype).

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

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

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

Например:

from django.core.mail import EmailMessage

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

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

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

  • message() создает объект django.core.mail.SafeMIMEText (дочерний класс email.MIMEText.MIMEText), или django.core.mail.SafeMIMEMultipart, который содержит письмо для отправки. Если вам понадобиться переопределить класс EmailMessage, скорее всего вы переопределите этот метод, чтобы изменить MIME объект.

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

  • attach() создает новый вложенный файл и добавляет его к письму. Есть два способа вызвать attach():

    • Можно передать экземпляр email.MIMEBase.MIMEBase. Он будет добавлен непосредственно в письмо.

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

      Например:

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

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

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

      Кроме того, вложения message/rfc822 больше не будут закодированы в формате Base64 в нарушение RFC 2046 Section 5.2.1, что может вызвать проблемы с отображением вложений в Evolution и Thunderbird.

  • attach_file() создает новое вложения, используя файл с файловой системы. Вызовите, указав путь к файлу. Опционально можно указать MIME тип вложения. Если вы не укажите mimetype, он будет построен по названию файла. Самый простой пример использования:

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

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

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

It can be useful to include multiple versions of the content in an email; the classic example is to send both text and HTML versions of a message. With Django’s email library, you can do this using the EmailMultiAlternatives class. This subclass of EmailMessage has an attach_alternative() method for including extra versions of the message body in the email. All the other methods (including the class initialization) are inherited directly from EmailMessage.

To send a text and HTML combination, you could write:

from django.core.mail import EmailMultiAlternatives

subject, from_email, to = 'hello', 'from@example.com', '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()

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

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) sends a list of EmailMessage objects. If the connection is not open, this call will implicitly open the connection, and close the connection afterwards. If the connection is already open, it will be left open after mail has been sent.

Может использоваться как контекстный менеджер, автоматически вызывая 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, *args, **kwargs)

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

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

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

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

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'

Если timeout не указан, будет использоваться результат 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

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

Changed in Django 3.1:

Support for pathlib.Path was added.

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

Бэкенд 'locmem' сохраняет почту в специальном атрибуте модуля django.core.mail. Атрибут outbox создается при первой отправке письма. Это список экземпляров EmailMessage отправленных писем.

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

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

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

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

Dummy бэкенд

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

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

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

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

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

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

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

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

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

Firstly, you can use the send_messages() method. send_messages() takes a list of EmailMessage instances (or subclasses), and sends them all using a single connection.

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

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 отправлял почту. Например, при разработке сайта. Вряд ли вы захотите отправлять тысячи писем, но при этом необходимо проверить, что код их отправляет правильным получателям с правильным содержимым.

The easiest way to configure email for local development is to use the console email backend. This backend redirects all email to stdout, allowing you to inspect the content of mail.

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

Another approach is to use a «dumb» SMTP server that receives the emails locally and displays them to the terminal, but does not actually send anything. Python has a built-in way to accomplish this with a single command:

python -m smtpd -n -c DebuggingServer localhost:1025

This command will start a minimal SMTP server listening on port 1025 of localhost. This server prints to standard output all email headers and the email body. You then only need to set the EMAIL_HOST and EMAIL_PORT accordingly. For a more detailed discussion of SMTP server options, see the Python documentation for the smtpd module.

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

Back to Top