Spec-Zone.ru › Django 5.1

Отправка электронных писем

Хотя 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 send_mail() и send_mass_mail() — это фактически тонкие обёртки, которые используют класс EmailMessage.

Не все возможности класса EmailMessage доступны через функции send_mail() и связанные с ними обертки. Если вы хотите использовать расширенные возможности, такие как получатели с копии, вложения файлов или многочастьные электронные письма, вам нужно создать экземпляры 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: Список вложений для добавления в сообщение. Они могут быть экземплярами 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 (подкласс Python's MIMEText class) или объект 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.

class EmailMultiAlternatives [source]

Подкласс EmailMessage с дополнительным методом attach_alternative() для включения дополнительных версий тела сообщения в электронное письмо. Все остальные методы (включая инициализацию класса) унаследованы непосредственно от EmailMessage.

attach_alternative(content, mimetype) [source]

Прикрепить альтернативное представление тела сообщения в электронное письмо.

Например, чтобы отправить текст и HTML, можно написать:

from django.core.mail import EmailMultiAlternatives

subject = "hello"
from_email = "from@example.com"
to = "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

Этот бэкенд не предназначен для использования в рабочей среде – он предоставляется для удобства использования во время разработки.

Бэкенд памяти

Бэкенд памяти хранит сообщения в специальном атрибуте модуля 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/5.1/topics/email/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API