Spec-Zone.ru › Django 2.1

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

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

END_OF_DOCUMENT_MARKER

Не все возможности класса 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 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()

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

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

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

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

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

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

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

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/2.1/topics/email/

Spec-Zone.ru

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