Отправка электронных писем
Хотя 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() и связанные обертки. Если вам нужны расширенные возможности, такие как адресата с кодированием 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: Список вложений для добавления к сообщению. Они могут быть экземплярамиemail.MIMEBase.MIMEBase, или кортежами(filename, content, mimetype). -
headers: Словарь дополнительных заголовков для добавления к сообщению. Ключи — имя заголовка, значения — значения заголовка. От вызывающей стороны требуется убедиться, что имена и значения заголовков имеют правильный формат для электронного сообщения. Соответствующий атрибут —extra_headers. -
cc: Список или кортеж адресов получателей, используемых в заголовке «Cc» при отправке письма. -
reply_to: Список или кортеж адресов получателей, используемых в заголовке «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(подкласс класса Pythonemail.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')Если вы укажете
mimetypemessage/rfc822, он также будет приниматьdjango.core.mail.EmailMessageиemail.message.Message.Кроме того, вложения
message/rfc822больше не будут кодироваться в base64 в нарушение RFC 2046#section-5.2.1, что может вызвать проблемы с отображением вложений в Evolution и Thunderbird.
- Вы можете передать ему один аргумент, который является экземпляром
-
attach_file()создает новое вложение, используя файл из вашей файловой системы. Вызовите его с путем к файлу для добавления и, необязательно, типом MIME для вложения. Если тип MIME опущен, он будет угадан по имени файла. Самый простой способ использования:message.attach_file('/images/weather_map.png')
Отправка альтернативных типов содержимого
Бывает полезно включать несколько версий содержимого в электронное письмо; классическим примером является отправка текстовой и 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(без таймаута).Параметры
ssl_keyfile, иssl_certfileи соответствующие настройки были добавлены. Возможность настроитьtimeoutс помощью настройки (EMAIL_TIMEOUT) была добавлена. -
Бэкенд консоли
Вместо отправки реальных писем бэкенд консоли просто записывает письма, которые должны быть отправлены в стандартный вывод. По умолчанию консольный бэкенд записывает в 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/1.9/topics/email/