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

Хотя 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 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 , исключения, возникающие при отправке сообщения, будут отменены. Пустой список получателей не вызовет исключения.

  • 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 ©2020 All rights reserved