Как отправить письмо с сайта с разных почт Django
12 февраля 2021 г. 2:18
В этой статье я покажу самый простой способ, как использовать разные эл. почты для отправки писем с сайта в двух примерах: стандартным бекендом Django django.core.mail.backends.smtp.EmailBackend
и с помощью пакета post-office.
Стандартный способ отправки письма с разных почт
Допустим, у вас есть две эл. почты email_1@mail.ru
и email_2@gmail.com
, и в зависимости от задач вы выбираете через какую электронную почту отправить сообщение на эл. адреса.
Для начала добавим почтовые настройки по умолчанию в settings.py
. У каждой почтовой службы свой хост и порт для подключения, в нашем примере "mail.ru", поэтому используем соответствующие настройки:
EMAIL_HOST = 'smtp.mail.ru' EMAIL_PORT = 2525 EMAIL_HOST_USER = "email_1@mail.ru" EMAIL_HOST_PASSWORD = "password" EMAIL_USE_TLS = True EMAIL_USE_TLS = False SERVER_EMAIL = EMAIL_HOST_USER DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
Более подробно как настраивать отправку писем с сайта Django смотрите в статье Настройка отправки писем email в Django для mail, яндекс, gmail.
Теперь создадим представление в views.py:
from django.conf import settings from django.core.mail import send_mail def send(request): send_mail('Test', 'Test messsage', settings.EMAIL_HOST_USER, ['recipient@gmail.com'])
После выполнения данного кода получатель recipient@gmail.com увидит в своей электронной почте сообщение "Test messsage" с темой письма "Test" от email_1@mail.ru.
Метод send_mail()
принимает необязательный аргумент connection
, отвечающий за настройку подключения к почте, через которую будет осуществляться отправка сообщения. Если connection
не задан, как у нас в коде выше, то connection
использует в качестве подключения EMAIL_HOST
, EMAIL_PORT
, EMAIL_HOST_USER
, EMAIL_HOST_PASSWORD
, EMAIL_USE_TLS
, EMAIL_USE_SSL
, взятые в settings.py
.
Чтобы использовать произвольные параметры подключения, нужно добавить connection
:
from django.core.mail import send_mail, get_connection def send(request): connection = get_connection( host='smtp.gmail.com', port=587, username='email_2@gmail.com', password='password', use_tls=True, use_ssl=False, ) send_mail('Test', 'Test messsage', 'email_2@gmail.com', ['recipient@gmail.com'], connection=connection)
Теперь получатель recipient@gmail.com увидит в своей электронной почте сообщение "Test messsage" с темой письма "Test" от email_2@gmail.com.
Практическое применение данной возможности заключается в том, что вы можете хранить настройки подключения в базе данных и в зависимости от нужд использовать тот или иной адрес почты, через которую будет посылаться электронное сообщение на почту получателя:
def send(request): my_mail = MailHost.objects.get(id=1) # или использовать .filter() по какому-то условию connection = get_connection( host=my_mail.host, port=my_mail.port, username=my_mail.username, password=my_mail.password, use_tls=my_mail.use_tls, use_ssl=my_mail.use_ssl, ) send_mail('Test', 'Test messsage', my_mail.username, ['recipient@gmail.com'], connection=connection)
Если хотите лучше разобраться, как создаётся подключение, то посмотрите в исходных файлах mail бекенда Django:
/django/core/mail/__init__.py
:def send_mail()
/django/core/mail/__init__.py
:def get_connection()
/django/core/mail/backends/smtp.py
:class EmailBackend()
Отправка писем с сайта с разных почт с помощью post-office
Так как логика отправки писем у post-office отличается от стандартной отправки писем в Django, то нужно будет чуть больше произвести настроек для решения нашей задачи. Сначала рассмотрим простой пример, а затем перейдём к более сложному.
Допустим, у нас есть всё те же две эл. почты email_1@mail.ru
и email_2@gmail.com
.
Для начала добавим почтовые настройки по умолчанию в settings.py
для email_1@mail.ru
. Данная почта от "mail.ru", поэтому используем соответствующие настройки подключения:
INSTALLED_APPS = ( ... 'post_office', ) EMAIL_BACKEND = 'post_office.EmailBackend' EMAIL_HOST = 'smtp.mail.ru' EMAIL_PORT = 2525 EMAIL_HOST_USER = "email_1@mail.ru" EMAIL_HOST_PASSWORD = "password" EMAIL_USE_TLS = True EMAIL_USE_SSL = False SERVER_EMAIL = EMAIL_HOST_USER DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
Более подробно как настраивать отправку писем с сайта Django смотрите в статье Настройка отправки писем email в Django для mail, яндекс, gmail.
Теперь создадим представление в views.py:
from post_office.mail import send def send_1(request): send([recipient@gmail.com], settings.EMAIL_HOST_USER, subject='Test', message='Test message') return HttpResponse('ok')
Как видно, второй аргумент должнен содержать адрес электронной почты, с которой будет производиться отправка сообщения. На данный момент используется settings.EMAIL_HOST_USER
. Если мы используем другое значение (к чему мы и стремимся), то письмо не будет отправлено.
Давайте для начала добавим в settings.py
настройки для email_2@mail.ru
:
EMAIL_HOST_2 = 'smtp.mail.ru' EMAIL_PORT_2 = 2525 EMAIL_HOST_USER_2 = "email_2@mail.ru" EMAIL_HOST_PASSWORD_2 = "password" EMAIL_USE_TLS_2 = True
Отправка письма всегда происходит с помощью backend
, поэтому мы ранее в settings.py
уже установили EMAIL_BACKEND = 'post_office.EmailBackend'
бекенд от post-office. По сути post_office.EmailBackend
- это простая обёртка обычного django.core.mail.backends.smtp.EmailBackend
- вы это ниже увидите у post-office бекенд по умолчанию: default
. Сам post-office позволяет конфигурировать несколько бекендов и использовать их в более удобном способе. Давайте сконфигурируем два бекенда, где первый будет по умолчанию, который будет использовать стандартные настройки EMAIL_HOST
, EMAIL_PORT
и т. д. А второй будет использовать настройки EMAIL_HOST_2
, EMAIL_PORT_2
и т. д.:
POST_OFFICE = { 'BACKENDS': { 'default': 'django.core.mail.backends.smtp.EmailBackend', 'my_backend_2': 'my_app.backends.EmailBackend', } }
Теперь добавим сам файл my_app/backends.py
:
from django.conf import settings from django.core.mail.backends.smtp import EmailBackend as BaseEmailBackend class EmailBackend(BaseEmailBackend): def __init__(self, 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): super(EmailBackend, self).__init__(fail_silently=fail_silently) self.host = host or settings.EMAIL_HOST_2 self.port = port or settings.EMAIL_PORT_2 self.username = settings.EMAIL_HOST_USER_2 if username is None else username self.password = settings.EMAIL_HOST_PASSWORD_2 if password is None else password self.use_tls = settings.EMAIL_USE_TLS_2 if use_tls is None else use_tls
Как видите, мы просто создали класс, унаследованный от django.core.mail.backends.smtp.EmailBackend
, и подменили значения host
, port
и др. на settings.EMAIL_HOST_2
, settings.EMAIL_PORT_2
и др. соответственно.
Это будет работать, так как ещё раз повторюсь, post-office по сути является обёрткой и сам использует стандартный джанговский бекенд django.core.mail.backends.smtp.EmailBackend
.
Теперь осталось создать второе представление и использовать второй наш бекенд, например так:
from post_office.mail import send def send_2(request): send([recipient@gmail.com], settings.EMAIL_HOST_USER, subject='Test', message='Test message', backend='my_backend_2') return HttpResponse('ok')
Теперь при выполнении представления send_2
получатель resipient@gmail.com
получит письмо уже от settings.EMAIL_HOST_2
.
Как видите, мы жёстко прописываем в settings.py
необходимые параметры подключения и для большинства случаев этого достаточно.
Более сложные случаи определения параметров email host и port
Когда сама суть понятна, как используются mail-бекенды в django, можно уже более интересные вещи делать. Например, самый наипростейший балансировщик отправки эл. почты:
import random from django.conf import settings from django.core.mail.backends.smtp import EmailBackend as BaseEmailBackend class EmailBackend(BaseEmailBackend): def __init__(self, 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): super(EmailBackend, self).__init__(fail_silently=fail_silently) if random.randint(0, 1) == 0: self.host = host or settings.EMAIL_HOST self.port = port or settings.EMAIL_PORT self.username = settings.EMAIL_HOST_USER if username is None else username self.password = settings.EMAIL_HOST_PASSWORD if password is None else password self.use_tls = settings.EMAIL_USE_TLS if use_tls is None else use_tls else: self.host = host or settings.EMAIL_HOST_2 self.port = port or settings.EMAIL_PORT_2 self.username = settings.EMAIL_HOST_USER_2 if username is None else username self.password = settings.EMAIL_HOST_PASSWORD_2 if password is None else password self.use_tls = settings.EMAIL_USE_TLS_2 if use_tls is None else use_tls
Здесь в зависимости от полученного рандомного числа используются соответствующие настройки. В реальности, конечно, следует по-другому делать (определять какому бекенду отправлять письма, исходя из нагрузки), но для простоты примера подойдёт.
Или можно хранить данные host
, port
, username
, password
, use_tls
, use_ssl
в базе данных и использовать по соответствующему правилу: например, для балансировки это может быть что-то вроде:
from django.core.mail.backends.smtp import EmailBackend as BaseEmailBackend from my_app.models import EmailHost class EmailBackend(BaseEmailBackend): def __init__(self, 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): super(EmailBackend, self).__init__(fail_silently=fail_silently) email_host = EmailHost.objects.order_by('?')[0] self.host = email_host.host self.port = email_host.port self.username = email_host.username self.password = email_host.password self.use_tls = email_host.use_tls self.use_ssl = email_host.use_ssl
Или другой пример: можно также хранить информацию о том, какой host должен обработать email в БД. Так как post-office не хранит в БД данные о том, какие host, port и т. д. использовать, то нужно будет кастомизировать метод создания письма send у post-office (или лучше использовать сигнал post_office.signals.email_queued
), чтобы post-office не только создавал в БД письмо с указанным бекендом, но и происходило сохранение в отдельной таблице соответствия писем и хостов, с помощью которых нужно обработать эти данные. Это пример сложнее, поэтому в этой статье не рассматривается. Если вы поняли, как работают выше примеры, то сможете реализовать и это (если уж кому это надо будет и не сможете разобраться, то пишите в комментах).
Представляю вашему вниманию книгу, написанную моим близким другом Максимом Макуриным: Секреты эффективного управления ассортиментом.
Книга предназначается для широкого круга читателей и, по мнению автора, будет полезна специалистам отдела закупок и логистики, категорийным и финансовым менеджерам, менеджерам по продажам, аналитикам, руководителям и директорам, в компетенции которых принятие решений по управлению ассортиментом.
Комментарии: 3
03.02.2022 11:56 #
На сайте написанном на React есть форма, ввожу name и phone, данные приходят в джанго в бд и апи. Как автоматом отправлять на почту ???
Ответить
04.02.2022 4:57 #
Если письма куда-то сохраняются в БД, то можно создать management команду, в которой реализовать метод отправки почты, и по cron-у вызывать эту команду. Если использовать готовый пакет, например, post-office, то там уже есть команда, которая отправляет письма send_queued_mail. Её и по крону вызывают в простейшем случае. В более сложном - можно использовать Celery для мгновенной отправки письма
Ответить
05.04.2024 9:35 #
как принмать емэйлы. библиотека imap вроде в джангой не дружит. некуда там backend-параметр вставлять. Вопрос как с нескольких емйлов с разных хостов принимать (с разными TSL) ?
Ответить