Отправка электронных писем
Хотя 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)
В большинстве случаев вы можете отправить электронное письмо с помощью 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)
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)
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)
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
Класс 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)
По умолчанию вызов get_connection() вернёт экземпляр бекенда электронной почты, указанный в EMAIL_BACKEND. Если вы укажете аргумент backend, будет создан экземпляр этого бекенда.
Аргумент fail_silently управляет тем, как бекенд обрабатывает ошибки. Если fail_silently имеет значение True, исключения во время процесса отправки электронного письма будут молча игнорироваться.
Все остальные аргументы передаются напрямую в конструктор бекенда электронной почты.
END_OF_DOCUMENT_MARKERDjango поставляется с несколькими бэкендами для отправки электронной почты. За исключением бэкенда 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.2/topics/email/