Отправка электронного письма
Хотя 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: Строка. ЕслиNone, Django будет использовать значение настройкиDEFAULT_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’s 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, исключения, возникшие во время отправки сообщения, будут подавлены. Пустой список получателей не вызовет исключения. Он вернет1если сообщение было успешно отправлено, в противном случае0. -
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')Если вы укажете тип MIME message/rfc822, он также примет
django.core.mail.EmailMessageиemail.message.Message.Для типов MIME, начинающихся с 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-сервера, который принимает письма локально и отображает их в терминале, но фактически ничего не отправляет. Пакет aiosmtpd предоставляет способ достижения этого:
python -m pip install aiosmtpd python -m aiosmtpd -n -l localhost:8025
Эта команда запустит минимальный SMTP-сервер, прослушивающий порт 8025 на localhost. Этот сервер выводит в стандартный вывод все заголовки электронного письма и тело письма. Вам нужно лишь соответствующим образом установить EMAIL_HOST и EMAIL_PORT. Более подробное обсуждение параметров SMTP-сервера см. в документации модуля aiosmtpd.
Сведения об тестировании отправки электронных писем в вашем приложении см. в разделе Услуги электронной почты документации по тестированию.
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/4.1/topics/email/