Как отправить письмо с сайта с разных почт Django

11 февраля 2021 г. 21: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_HOSTEMAIL_PORTEMAIL_HOST_USEREMAIL_HOST_PASSWORDEMAIL_USE_TLSEMAIL_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__.pydef send_mail()
  • /django/core/mail/__init__.pydef get_connection()
  • /django/core/mail/backends/smtp.pyclass 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_HOSTEMAIL_PORT и т. д. А второй будет использовать настройки EMAIL_HOST_2EMAIL_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, и подменили значения hostport и др. на settings.EMAIL_HOST_2settings.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

Здесь в зависимости от полученного рандомного числа используются соответствующие настройки. В реальности, конечно, следует по-другому делать (определять какому бекенду отправлять письма, исходя из нагрузки), но для простоты примера подойдёт.

Или можно хранить данные hostportusernamepassworduse_tlsuse_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 не только создавал в БД письмо с указанным бекендом, но и происходило сохранение в отдельной таблице соответствия писем и хостов, с помощью которых нужно обработать эти данные. Это пример сложнее, поэтому в этой статье не рассматривается. Если вы поняли, как работают выше примеры, то сможете реализовать и это (если уж кому это надо будет и не сможете разобраться, то пишите в комментах).

Оцените статью

0 из 5 (всего 0 оценок)

captcha
Поля, отмеченные звёздочкой ( * ) , являются обязательными.

Спасибо за ваш отзыв!

После нажатия кнопки "Отправить" ваше сообщение будет доставлено мне на почту.

Автор статьи

Мальцев Артём

Веб-разработчик, владеющий знаниями языка программирования Python, фреймворка Django, системы управления содержимым сайта Django CMS, платформы для создания интернет-магазина Django Shop и многих различных приложений, использующих эти технологии.

Права на использование материала, расположенного на этой странице https://vivazzi.pro/it/send-email-from-different-account-django/:

Разрешается копировать материал с указанием её автора и ссылки на оригинал без использования параметра rel="nofollow" в теге <a>. Использование:

Автор статьи: Мальцев Артём
Ссылка на статью: <a href="https://vivazzi.pro/it/send-email-from-different-account-django/">https://vivazzi.pro/it/send-email-from-different-account-django/</a>

Подробнее: Правила использования сайта

Комментариев: 0

Вы можете оставить комментарий как незарегистрированный пользователь.

Но зарегистрировавшись, вы сможете:

  • получать оповещения об ответах
  • просматривать свои комментарии
  • иметь возможность использовать все функции разработанных сервисов

Для комментрирования от своего имени, войдите или зарегистрируйтесь обычным способом или через социальные сети:

Отправить

На данный момент нет специального поиска, поэтому я предлагаю воспользоваться обычной поисковой системой, например, Google, добавив "vivazzi" после своего запроса.

Попробуйте

Выберите валюту для отображения денежных единиц