Отправка электронной почты

Хотя Python предоставляет интерфейс для отправки почты через smtplib модуль, Django предоставляет пару легких оберток над ним. Эти оболочки предназначены для ускорения отправки электронной почты, для помощи в тестировании отправки электронной почты во время разработки и для обеспечения поддержки платформ, которые не могут использовать SMTP.

Код живет в django.core.mailмодуле.

Быстрый пример

В двух строках:

from django.core.mail import send_mail

send_mail(
    'Subject here',
    'Here is the message.',
    '[email protected]',
    ['[email protected]'],
    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( При условии , сообщение , FROM_EMAIL , recipient_list , fail_silently не = False , AUTH_USER = нет , auth_password = нет , соединение = нет , 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предусмотрено, полученное по электронной почте будет многочастному / альтернативный адрес электронной почты с messageкак текст / обычный тип контента и html_messageкак текст / 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', '[email protected]', ['[email protected]', '[email protected]'])
message2 = ('Another Subject', 'Here is another message', '[email protected]', ['[email protected]'])
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( тема , сообщение , fail_silently = False , connection = None , html_message = None )

django.core.mail.mail_admins()- это ярлык для отправки электронной почты администраторам сайта, как определено в ADMINSнастройках.

mail_admins()ставит префикс темы значением EMAIL_SUBJECT_PREFIXпараметра, который установлен по умолчанию."[Django] "

Заголовок «От:» электронного письма будет значением SERVER_EMAILнастройки.

Этот метод существует для удобства и удобочитаемости.

Если html_messageпредусмотрено, полученное по электронной почте будет многочастному / альтернативный адрес электронной почты с messageкак текст / обычный тип контента и html_messageкак текст / html типа контента.

mail_managers()

mail_managers( тема , сообщение , 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.',
    '[email protected]',
    ['[email protected]', '[email protected]'],
)

Это отправляет сообщение john @ example . com и jane @ example . com , и они оба получат отдельное электронное письмо:

datatuple = (
    ('Subject', 'Message.', '[email protected]', ['[email protected]']),
    ('Subject', 'Message.', '[email protected]', ['[email protected]']),
)
send_mass_mail(datatuple)

Предотвращение внедрения заголовка

Внедрение заголовков - это средство защиты, при котором злоумышленник вставляет дополнительные заголовки электронной почты для управления полями «Кому:» и «От:» в сообщениях электронной почты, создаваемых вашими сценариями.

Все функции электронной почты Django, описанные выше, защищают от внедрения заголовков, запрещая символы новой строки в значениях заголовков. Если какой - либо subject, from_emailили recipient_listсодержит символ перевода строки (в любой Unix, Windows или Mac стиль), функция электронной почты (например send_mail()) будет поднимать django.core.mail.BadHeaderError(подкласс ValueError) и, следовательно, не будет посылать по электронной почте. Вы обязаны проверить все данные перед их передачей функциям электронной почты.

Если a messageсодержит заголовки в начале строки, заголовки будут напечатаны как первый бит сообщения электронной почты.

Вот пример мнение , что берет subject, messageи from_email из данных POST по просьбе, в посылает , что админ @ пример . 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, ['[email protected]'])
        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()функции-оболочки и связанные с ними функции-оболочки. Если вы хотите использовать расширенные функции, такие как получатели с скрытой копией, вложения файлов или электронное письмо, состоящее из нескольких частей, вам необходимо создать EmailMessageэкземпляры напрямую.

Примечание

Это особенность дизайна. send_mail()и связанные с ним функции изначально были единственным интерфейсом, предоставляемым Django. Однако список принимаемых ими параметров со временем медленно расширялся. Имеет смысл перейти к более объектно-ориентированному дизайну сообщений электронной почты и сохранить исходные функции только для обратной совместимости.

EmailMessageотвечает за создание самого сообщения электронной почты. Электронный бэкенд затем отвечает за отправку по электронной почте.

Для удобства EmailMessageпредоставляет send() способ отправки одного электронного письма. Если вам нужно отправить несколько сообщений, альтернативный API-интерфейс электронной почты предоставляет альтернативу .

EmailMessageОбъекты

класс EmailMessage

EmailMessageКласс инициализируется со следующими параметрами (в указанном порядке, если используются позиционные аргументы). Все параметры необязательны и могут быть установлены в любое время до вызова send()метода.

  • subject: Тема письма.
  • body: Основной текст. Это должно быть текстовое сообщение.
  • from_email: Адрес отправителя. Как [email protected]и формы законны. Если не указано, используется настройка."Fred" <[email protected]>DEFAULT_FROM_EMAIL
  • to: Список или кортеж адресов получателей.
  • bcc: Список или кортеж адресов, используемых в заголовке «Скрытая копия» при отправке электронного письма.
  • connection: Серверный экземпляр электронной почты. Используйте этот параметр, если вы хотите использовать одно и то же соединение для нескольких сообщений. Если не указано, при send()вызове создается новое соединение .
  • attachments: Список вложений, которые нужно вложить в сообщение. Это могут быть как MIMEBaseэкземпляры, так и тройки.(filename, content, mimetype)
  • headers: Словарь дополнительных заголовков, добавляемых к сообщению. Ключи - это имя заголовка, значения - это значения заголовка. Вызывающий абонент должен убедиться, что имена и значения заголовков имеют правильный формат для сообщения электронной почты. Соответствующий атрибут - extra_headers.
  • cc: Список или кортеж адресов получателей, используемых в заголовке «Копия» при отправке электронного письма.
  • reply_to: Список или кортеж адресов получателей, используемых в заголовке «Reply-To» при отправке электронного письма.

Например:

from django.core.mail import EmailMessage

email = EmailMessage(
    'Hello',
    'Body goes here',
    '[email protected]',
    ['[email protected]', '[email protected]'],
    ['[email protected]'],
    reply_to=['[email protected]'],
    headers={'Message-ID': 'foo'},
)

В классе есть следующие методы:

  • send(fail_silently=False)отправляет сообщение. Если соединение было указано при создании электронного письма, оно будет использоваться. В противном случае будет создан и использован экземпляр серверной части по умолчанию. Если аргумент ключевого слова fail_silentlyравен True, исключения, возникающие при отправке сообщения, будут аннулированы. Пустой список получателей не вызовет исключения. Он вернется, 1если сообщение было отправлено успешно, в противном случае 0.

  • message()создает django.core.mail.SafeMIMETextобъект (подкласс класса Python MIMEText) или 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в сообщении / rfc822 , он также будет принимать django.core.mail.EmailMessageи email.message.Message.

      Для mimetypeначала с текста / ожидается, что содержимое будет строкой. Двоичные данные будут декодированы с использованием 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', '[email protected]', '[email protected]'
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, исключения в процессе отправки электронной почты будут игнорироваться.

Все остальные аргументы передаются непосредственно конструктору серверной части электронной почты.

Django поставляется с несколькими серверными модулями для отправки электронной почты. За исключением бэкэнда SMTP (который используется по умолчанию), эти бэкэнды полезны только во время тестирования и разработки. Если у вас есть особые требования к отправке электронной почты, вы можете написать свой собственный сервер электронной почты .

Серверная часть SMTP

classbackends.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:

Серверная часть 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 3.1:

Поддержка pathlib.Pathбыла добавлена.

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

В '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',
    '[email protected]',
    ['[email protected]'],
    connection=connection,
)
email1.send() # Send the email

# Construct two more messages
email2 = mail.EmailMessage(
    'Hello',
    'Body goes here',
    '[email protected]',
    ['[email protected]'],
)
email3 = mail.EmailMessage(
    'Hello',
    'Body goes here',
    '[email protected]',
    ['[email protected]'],
)

# 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 отправлял электронные письма. Например, при разработке веб-сайта вы, вероятно, не захотите рассылать тысячи электронных писем, но вы можете убедиться, что электронные письма будут отправлены нужным людям при правильных условиях и что эти электронные письма будут содержать правильный контент. .

Самый простой способ настроить электронную почту для локальной разработки - использовать серверную часть электронной почты консоли . Этот бэкэнд перенаправляет всю электронную почту на стандартный вывод, позволяя вам проверять содержимое почты.

Бэкэнд файловой электронной почты также может быть полезен во время разработки - этот бэкэнд выгружает содержимое каждого SMTP-соединения в файл, который можно проверить на досуге.

Другой подход - использовать «тупой» SMTP-сервер, который принимает электронные письма локально и отображает их на терминал, но на самом деле ничего не отправляет. В Python есть встроенный способ сделать это с помощью одной команды:

python -m smtpd -n -c DebuggingServer localhost:1025

Эта команда запустит минимальный SMTP-сервер, прослушивающий порт 1025 localhost. Этот сервер выводит на стандартный вывод все заголовки и тело письма. Затем вам нужно только установить EMAIL_HOSTи EMAIL_PORTсоответственно. Более подробное обсуждение параметров SMTP-сервера см. В документации Python к smtpdмодулю.

Информацию о модульном тестировании отправки электронных писем в вашем приложении см. В разделе « Службы электронной почты » документации по тестированию.

Copyright ©2021 All rights reserved