Spec-Zone.ru › Django 1.11

Отправка электронной почты

Хотя 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 send_mail, BadHeaderError
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 send_mail() и send_mass_mail() на самом деле являются тонкими оболочками, использующими класс EmailMessage.

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

Примечание

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

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

Для удобства класс 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: Список вложений для добавления к сообщению. Они могут быть экземплярами email.MIMEBase.MIMEBase, или кортежами из (filename, content, mimetype).
  • headers: Словарь дополнительных заголовков для добавления к сообщению. Ключи — это имя заголовка, значения — значения заголовка. От пользователя требуется убедиться, что имена и значения заголовков имеют правильный формат для электронного письма. Соответствующий атрибут — extra_headers.
  • cc: Список или кортеж адресов получателей, используемых в заголовке «Cc» при отправке электронного письма.
  • 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 email.MIMEText.MIMEText) или объект django.core.mail.SafeMIMEMultipart, содержащий отправляемое сообщение. Если вам когда-либо понадобится расширить класс EmailMessage, вам, вероятно, придётся переопределить этот метод, чтобы поместить в объект MIME необходимый контент.
  • recipients() возвращает список всех получателей сообщения, независимо от того, указаны ли они в атрибутах to, cc или bcc. Этот метод вам может потребоваться переопределить при наследовании, так как SMTP-серверу необходимо сообщить полный список получателей при отправке сообщения. Если вы добавите другой способ указания получателей в свой класс, они также должны быть возвращены этим методом.
  • attach() создаёт новое вложение файла и добавляет его к сообщению. Метод attach() можно вызвать двумя способами:

    • Вы можете передать ему один аргумент, который является экземпляром email.MIMEBase.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().

Изменено в Django 1.11:

Добавлена поддержка типа MIME application/octet-stream по умолчанию при невозможности декодировать двоичные данные для вложения text/*.

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

Полезно включать несколько версий контента в электронное письмо; классический пример — отправка текстовой и 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()

Почтовые бэкенды

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

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

  • 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, *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'

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

Бэкенд Dummy

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

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

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

Бэкенд электронной почты файла также может быть полезен во время разработки — этот бэкенд сохраняет содержимое каждого 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/1.11/topics/email/

Spec-Zone.ru

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