Spec-Zone.ru › Django 2.0

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

Хотя 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() по сравнению с 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.

Не все возможности класса EmailMessage доступны через функции send_mail() и связанные обертки. Если вы хотите использовать расширенные возможности, такие как получатели с адресом BCC, вложения файлов или электронные письма с несколькими частями, вам нужно создать экземпляры 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: Список вложений для добавления к сообщению. Это могут быть экземпляры 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().

Изменено в 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

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

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

Бэкенд памяти хранит сообщения в специальном атрибуте модуля 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.0/topics/email/

Spec-Zone.ru

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