Spec-Zone.ru › Django 2.2

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

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

Код находится в модуле django.core.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,
)

Письмо отправляется с использованием 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) [source]

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

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

  • subject: Строка.
  • message: Строка.
  • from_email: Строка.
  • recipient_list: Список строк, каждая из которых — адрес электронной почты. Каждый участник recipient_list увидит других получателей в поле «Кому» сообщения электронной почты.
  • 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) [source]

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 увидят все остальные адреса в поле «Кому» сообщений электронной почты.

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

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() vs. 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) [source]

django.core.mail.mail_admins() — это сокращение для отправки электронного письма администраторам сайта, как определено в настройке ADMINS.

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

Заголовок «От кого» электронного письма будет иметь значение настройки 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) [source]

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

Примеры

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

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)

Предотвращение внедрения заголовков

Внедрение заголовков — это эксплойт, в котором злоумышленник вставляет дополнительные заголовки электронной почты для управления полями «Кому» и «От кого» в сообщениях электронной почты, генерируемых вашими скриптами.

Все описанные выше функции 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

Django’s send_mail() и send_mass_mail() функции фактически являются тонкими оболочками, которые используют класс EmailMessage.

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

Примечание

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

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

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

EmailMessage Объекты

class EmailMessage [source]

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

  • subject: Тема электронного письма.
  • body: Текст тела. Это должно быть простое текстовое сообщение.
  • from_email: Адрес отправителя. Допустимы как форматы fred@example.com , так и "Fred" <fred@example.com>. Если опущен, используется настройка DEFAULT_FROM_EMAIL.
  • to: Список или кортеж адресов получателей.
  • bcc: Список или кортеж адресов, используемых в заголовке «Bcc» при отправке электронного письма.
  • connection: Экземпляр бэкэнда электронной почты. Используйте этот параметр, если вы хотите использовать одно и то же соединение для нескольких сообщений. Если опущен, новое соединение создается при вызове send().
  • attachments: Список вложений, которые нужно добавить к сообщению. Это могут быть экземпляры 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_silently=False) отправляет сообщение. Если при создании электронного письма было указано соединение, будет использовано это соединение. В противном случае будет создан и использован экземпляр бэкэнда по умолчанию. Если ключевой аргумент fail_silently равен True, исключения, возникающие во время отправки сообщения, будут подавлены. Пустой список получателей не вызовет исключения.
  • message() строит объект django.core.mail.SafeMIMEText (подкласс класса Python’s MIMEText ) или объект django.core.mail.SafeMIMEMultipart, содержащий сообщение, которое нужно отправить. Если вам когда-либо нужно расширить класс EmailMessage, вы, вероятно, захотите переопределить этот метод, чтобы поместить в объект MIME нужный вам контент.
  • recipients() возвращает список всех получателей сообщения, вне зависимости от того, записаны ли они в атрибутах to, cc или bcc. Это еще один метод, который вам, возможно, придется переопределить при наследовании, поскольку SMTP-серверу нужно сообщить полный список получателей при отправке сообщения. Если вы добавите другой способ указания получателей в свой класс, они также должны возвращаться из этого метода.
  • attach() создает новое вложение файла и добавляет его к сообщению. Существует два способа вызова attach():

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

      Например:

      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 для использования вложения. Если тип MIME опущен, он будет угадан из имени файла. Самый простой способ использования:

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

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

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

Бывает полезно включать несколько версий содержимого в электронное письмо; классический пример — отправка текстовой и HTML-версий сообщения. В библиотеке электронной почты Django это можно сделать, используя класс EmailMultiAlternatives. Этот подкласс EmailMessage имеет метод attach_alternative() для включения дополнительных версий тела сообщения в электронном письме. Все остальные методы (включая инициализацию класса) наследуются непосредственно от EmailMessage.

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

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()

Email бэкэнды

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

Класс бэкэнда электронной почты имеет следующие методы:

  • 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() в EMAIL_HOST возвращает экземпляр бэкенда электронной почты, который вы можете использовать.

get_connection(backend=None, fail_silently=False, *args, **kwargs) [source]

По умолчанию вызов 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:

  • host: EMAIL_HOST
  • port: EMAIL_PORT
  • username: EMAIL_HOST_USER
  • password: EMAIL_HOST_PASSWORD
  • use_tls: EMAIL_USE_TLS
  • use_ssl: EMAIL_USE_SSL
  • timeout: EMAIL_TIMEOUT
  • ssl_keyfile: EMAIL_SSL_KEYFILE
  • ssl_certfile: EMAIL_SSL_CERTFILE

Бэкенд 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

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

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

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

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

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

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

Бэкенд-заглушка

Как следует из названия, бэкенд-заглушка ничего не делает с вашими сообщениями. Чтобы указать этот бэкенд, добавьте следующее в ваши настройки:

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

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

Определение пользовательского бэкенда электронной почты

Если вам нужно изменить способ отправки писем, вы можете написать свой собственный бэкенд электронной почты. Настройка EMAIL_BACKEND в файле настроек — это путь импорта Python для вашего класса бэкенда.

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

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

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

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

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

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

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

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

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

Эта команда запустит простой SMTP-сервер, прослушивающий порт 1025 на localhost. Этот сервер просто выводит в стандартный вывод все заголовки писем и тело письма. Вам нужно только соответствующим образом установить EMAIL_HOST и EMAIL_PORT. Более подробное обсуждение параметров SMTP-сервера см. в документации Python для модуля smtpd.

Для получения информации о тестировании отправки электронных писем в вашем приложении, см. раздел Услуги электронной почты документации по тестированию.

© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/2.2/topics/email/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API