Отправка электронной почты¶
Хотя 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
: Дополнительный бэкенд электронной почты, который будет использоваться для отправки письма. Если не указано, будет использоваться экземпляр бэкенда по умолчанию. Более подробную информацию см. в документации по Email backends.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()
против 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] "
.
В заголовке «From:» письма будет значение параметра 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)
Предотвращение инъекции заголовков¶
Header injection - это эксплойт безопасности, при котором злоумышленник вставляет дополнительные заголовки электронной почты для управления «To:» и «From:» в сообщениях электронной почты, которые генерируют ваши скрипты.
Все функции электронной почты Django, описанные выше, защищают от инъекции заголовков, запрещая новые строки в значениях заголовков. Если какой-либо из символов subject
, from_email
или recipient_list
содержит новую строку (в стиле Unix, Windows или Mac), функция email (например, 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’ed получателей, вложения файлов или многокомпонентные письма, вам необходимо создать экземпляры EmailMessage
напрямую.
Примечание
Это особенность дизайна. send_mail()
и связанные с ним функции изначально были единственным интерфейсом, который предоставлял Django. Однако со временем список принимаемых ими параметров постепенно увеличивался. Имело смысл перейти к более объектно-ориентированному дизайну для почтовых сообщений и сохранить первоначальные функции только для обратной совместимости.
EmailMessage
отвечает за создание самого сообщения электронной почты. Затем email backend отвечает за отправку сообщения.
Для удобства EmailMessage
предоставляет метод send()
для отправки одного письма. Если вам нужно отправить несколько сообщений, API бэкенда электронной почты provides an alternative.
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)
sends the message. If a connection was specified when the email was constructed, that connection will be used. Otherwise, an instance of the default backend will be instantiated and used. If the keyword argumentfail_silently
isTrue
, exceptions raised while sending the message will be quashed. An empty list of recipients will not raise an exception. It will return1
if the message was sent successfully, otherwise0
.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()
Бэкенды электронной почты¶
Фактическая отправка электронного письма осуществляется бэкендом электронной почты.
Класс email backend имеет следующие методы:
open()
создает долгоживущее соединение для отправки электронной почты.close()
закрывает текущее соединение для отправки электронной почты.send_messages(email_messages)
sends a list ofEmailMessage
objects. If the connection is not open, this call will implicitly open the connection, and close the connection afterward. If the connection is already open, it will be left open after mail has been sent.
Его также можно использовать в качестве менеджера контекста, который будет автоматически вызывать 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, то исключения в процессе отправки письма будут молча игнорироваться.
Все остальные аргументы передаются непосредственно в конструктор почтового бэкенда.
Django поставляется с несколькими бэкендами для отправки электронной почты. За исключением бэкенда SMTP (который используется по умолчанию), эти бэкенды полезны только во время тестирования и разработки. Если у вас есть особые требования к отправке электронной почты, вы можете write your own email backend.
Бэкэнд 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 automatically uses this backend for testing.
Фиктивный бэкэнд¶
Как следует из названия, фиктивный бэкенд ничего не делает с вашими сообщениями. Чтобы указать этот бэкенд, пропишите в настройках следующее:
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 отправлял электронные письма вообще. Например, при разработке веб-сайта вы, вероятно, не захотите рассылать тысячи писем - но вы можете захотеть проверить, что письма будут отправлены нужным людям при правильных условиях, и что эти письма будут содержать правильное содержание.
The easiest way to configure email for local development is to use the
console email backend. This backend
redirects all email to stdout
, allowing you to inspect the content of mail.
Бэкенд электронной почты file также может быть полезен во время разработки - этот бэкенд сбрасывает содержимое каждого SMTP-соединения в файл, который можно просмотреть на досуге.
Another approach is to use a «dumb» SMTP server that receives the emails locally and displays them to the terminal, but does not actually send anything. The aiosmtpd package provides a way to accomplish this:
python -m pip install aiosmtpd
python -m aiosmtpd -n -l localhost:8025
This command will start a minimal SMTP server listening on port 8025 of
localhost. This server prints to standard output all email headers and the
email body. You then only need to set the EMAIL_HOST
and
EMAIL_PORT
accordingly. For a more detailed discussion of SMTP
server options, see the documentation of the aiosmtpd module.
Информацию о модульном тестировании отправки электронной почты в вашем приложении см. в разделе Услуги электронной почты документации по тестированию.