Как отправить письмо с сайта с разных почт 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) ?
Ответить