Отправка электронных писем
Хотя 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 отвечает за создание самого электронного сообщения. Затем, 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: Список вложений, которые нужно добавить к сообщению. Это могут быть экземплярыemail.MIMEBase.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(подкласс класса 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(без таймаута). -
Бэкэнд консоли
Вместо отправки реальных писем бэкэнд консоли просто выводит письма, которые должны быть отправлены в стандартный вывод. По умолчанию бэкэнд консоли записывает в 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/1.10/topics/email/