Отправка электронной почты
Хотя 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.
Не все возможности класса 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(подкласс класса PythonMIMETextили объект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'
Этот бэкенд не предназначен для использования в производственной среде — он предоставляется в качестве удобства, которое можно использовать во время разработки и тестирования.
Бегунок тестов Django автоматически использует этот бэкенд для тестирования.
Бэкенд-заглушка
Как следует из названия, бэкенд-заглушка ничего не делает с вашими сообщениями. Чтобы указать этот бэкенд, поместите следующее в свои настройки:
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:1025END_OF_DOCUMENT_MARKER
Эта команда запустит минимальный 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/3.0/topics/email/