Настройка отправки писем email в Django для mail, яндекс, gmail

22 сентября 2015 г. 20:49

В зависимости от того, какой SMPT сервер хотим использовать для отправки писем с сайта, нужно указывать соответствующий хост и порт этого сервера. В Django нужно прописать настройки в settings.py:

mail.ru

EMAIL_HOST = 'smtp.mail.ru'
EMAIL_PORT = 2525
EMAIL_HOST_USER = "your@mail.ru"
EMAIL_HOST_PASSWORD = "password"
EMAIL_USE_TLS = True
EMAIL_USE_SSL = False

gmail.com

EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_HOST_USER = "your@gmail.com"
EMAIL_HOST_PASSWORD = "password"
EMAIL_USE_TLS = True
EMAIL_USE_SSL = False

yandex.ru

EMAIL_HOST = 'smtp.yandex.ru'
EMAIL_PORT = 465
EMAIL_HOST_USER = "your@yandex.ru"
EMAIL_HOST_PASSWORD = "password"
EMAIL_USE_TLS = False
EMAIL_USE_SSL = True

При использовании другой службы электронной почты посмотрите, какой хост и порт у этой службы. Например, для Google почты данная информация находится здесь: support.google.com/a/answer/176600?hl=ru#zippy=%2Cкак-использовать-smpt-сервер-gmail

Внимание: для получения писем об ошибках сайта для Яндекс и mail (и других почтовых служб) обязательно нужно указывать SERVER_EMAIL такой же адрес электронной почты, какой указывается в EMAIL_HOST_USER. Если не будет совпадать, то письма не будут посылаться! Поэтому вне зависимости от используемой службы добавьте ещё две следующие строчки в settings.py для отправки сообщений (трейсбека) админам при возникновении ошибок на сайте:

SERVER_EMAIL = EMAIL_HOST_USER
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER

Отправить сообщение в Django

Чтобы послать письмо, нужно лишь в коде где-нибудь, например, во views.py вызвать команду send_mail:

from django.conf import settings
from django.core.mail import send_mail

send_mail('Тема', 'Тело письма', settings.EMAIL_HOST_USER, ['to@example.com'])

Обратите внимание, что для предотвращения ошибки 501 sender address must match authenticated user нужно использовать адрес отправителя такой же, как EMAIL_HOST_USER (адрес пользователя при подключении к SMPT серверу). Более подробно об этой ошибки в статье: Error: SMTPRecipientsRefused 501 - sender address must match authenticated user

Если вы хотите добавить имя отправителя (или какое-либо название), то используйте headers:

headers = {'To': '{} <{}>'.format(user.get_full_name(), 'to@example.com')}
send_mail('Тема', 'Тело письма' , settings.EMAIL_HOST_USER, ['to@example.com'], headers=headers)

Обратите внимание, что в headers электронная почта получателя (в коде: to@example.com) должна совпадать.

Если вы хотите использовать html-теги в теле письма, то удобно создать отдельный файл и использовать render_to_string():

from django.conf import settings
from django.core.mail import send_mail
from django.template.loader import render_to_string

msg = render_to_string('path/to/template.html', {'test_variable': 'xxx'})
send_mail('Тема', msg, settings.EMAIL_HOST_USER, ['to@example.com'], html_message=msg)

Расширенный пример использования send_mail с помощью post_office

Приведу простой пример, но с более гибкими возможностями отправки писем с сайта. Предложенный в этом разделе код отправляет письма:

  • нескольким эл. почтам,
  • с вложением,
  • через некоторый временной интервал (это нужно, чтобы, например, сразу 100 писем не посылались с сайта, так как у некоторых почтовых служб есть ограничение в максимальной отправке писем в минуту).

Для начала поставим пакет post_office:

$ pip install django-post-office

В settings.py добавьте:

INSTALLED_APPS = (
    ...
    'post_office',
)

EMAIL_BACKEND = 'post_office.EmailBackend'

Теперь добавьте код, например, во views.py примерно такой:

emails = ['email_1@gmail.com', 'email_2@gmail.com', 'email_3@gmail.com']


me = 'Название компании <{}>'.format(settings.EMAIL_HOST_USER)
subject = 'Тестовое письмо'

attachments = {
    'Тестовое вложение.pdf': join(settings.MEDIA_ROOT, 'test_attachment.pdf')
}

now = timezone.now()
delta_sec = -70  # Нужно, чтобы первое письмо было отправлено сразу же

for email in emails:
    delta_sec += random.randint(60, 70)
    scheduled_time = now + timedelta(seconds=delta_sec)

    message = render_to_string('my_app/email.html', {'email': email, 'some_var': 'xxx'})
    headers = {'To': 'Получатель письма от компании <{}>'.format(email)}
    send(email, me, subject=subject,
         message=message, html_message=message,
         scheduled_time=scheduled_time, headers=headers, attachments=attachments)

Список emails может формироваться разным способом. Такой список может быть получает с базы данных, например, с некоторой модели MyModel: MyModel.objects.all(). Или может быть с формы поля CharField или Textarea.

В delta_sec += random.randint(60, 70) определяем через какое время посылать следующее письмо. Я использую рандомное число от 60 до 70 секунд, чтобы не через ровно одинаковый интервал посылались письма, а чуть более произвольный в рамках 65 +-5 секунд. Это число я беру с запасом, чтобы в уменьшить вероятность попадания письма в спам, вы можете уменьшить данное значение.

Данным кодом я довольно часто пользуюсь, когда нужно отправить письмо несколько людям.

У post-office метод send сам не отправляет сразу письмо получателю, а только создаёт его в базе данных.

Это полезно не только для возможности отправлять письма в определённое время, но и чтобы отправка письма не занимала много времени: проще сохранить письмо в базе данных, а затем его отправить (например, через cron), чем, находясь на сайте и кликнув на кнопку "Отправить" ждать пока отправятся письма. Отправка письма - всегда долгое по времени задача. Это особенно актуально, когда посетители отправляют форму с сайта.

Чтобы отправить письма, нужно в cron добавить команду send_queued_mail. В linux для этого вызываем редактор cron:

$ crontab -e

а затем добавляем вызов команды send_queued_mail, прописывая путь до manage.py вашего проекта:

*/2 * * * * python /project/path/to/manage.py send_queued_mail

Эта команда каждые две минуты проверяет, есть ли в базе данных письма в очереди на отправку. Если есть то, отправляет.

Решение ошибок при отправке почты

Зачастую ошибки происходят не в написанном коде, а в том, что письма не доходят до получателя. Например, в google можно получить следующую ошибку:

SMTP error code 535 Username and Password not accepted. Learn more at https://support.google.com/mail/?p=BadCredentials

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

Если вы подключаетесь через другую почтовую службу, то поищите соответствующую информацию.

Дополнительный материал

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

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

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

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

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

Автор статьи

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

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

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

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

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

Anton Emel
Anton Emel

13.09.2018 6:18 #

Подскажите, как сделать так чтоб настройки EMAIL_HOST, EMAIL_PORT, EMAIL_HOST_USE R и т.д. указывать в админке и при этом все работало?

Ответить

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

11.02.2021 21:19 #

Антон, добрый день!
Посмотрите мою статью https://vivazzi.pro/it/send-email-from-different-account-django/
В ней я расписал, как это можно сделать.

Ответить

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

14.09.2018 23:50 #

Антон, посмотрите, как сделано в файле: /django/core/mail/backends/smtp.py

А именно вот эти строки:

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

И определить свой Бекэнд (можно как пример посмотреть у приложения post_office как сделано: /post_office/backends.py) как-то так:

from django.core.mail.backends.base import 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)

        my_mail = MailHost.objects.get(id=1)
        self.host = my_mail.host
        self.port = my_mail.port
        // и т. д.

В settings.py добавить EMAIL_BACKEND = 'my_app.EmailBackend'

Примерно так. Сам я ни разу не задавался такой задачей. Попробуйте, вышеприведённый код тоже не тестировал, но по идее должно работать. Оно будет работать если при отправки письма каждый раз инициализируется бекэнд, если же он только один раз при запуске проекта, то тут конечно думать надо уже конкретно код писать.

И в гугле сходу я не нашёл. Только вот https://stackoverflow.com/questions/15187697/django-sending-email-with-dynamic-smtp-settings/15187806 - но там просто отсылка на документацию на создание своего бекэнда без конкретного кода.

Ответить

zenoviy
zenoviy

24.01.2019 14:07 #

Подскажите пожалуйста как кастомизировать вид самого письма отправленого на почту

Ответить

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

25.01.2019 8:36 #

Зеновый, здравствуйте!

Например, так:


from django.conf import settings
msg = render_to_string('path\to\template.html', {'test_variable': 'xxx'})
send_mail('Тема', msg , settings.EMAIL_HOST_USER, ['to@example.com'])

А файл path\to\template.html может содержать теги.

Ответить

Артем
Артем

19.04.2019 10:39 #

Здравствуйте!
А в качестве settings.EMAIL_HOST_USER я могу указать любую строку ? я хочу чтобы в письме отображался отправитель в качестве любого слова а не заданного email

Ответить

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

21.04.2019 2:23 #

Артём, здравствуйте!
При использовании метода send_mail('Тема', msg , settings.EMAIL_HOST_USER, ['to@example.com']) вам нужно использовать settings.EMAIL_HOST_USER. Но чтобы добавить имя отправителю нужно сделать так:

headers = {'To': '{}  <{}>'.format(user.get_full_name(), user.email)}
send_mail('Тема', msg , settings.EMAIL_HOST_USER, ['to@example.com'], headers=headers)

Ответить

Deca
Deca

19.07.2019 7:52 #

from django.conf import setting s send_mail('Тема', 'Тело письма', settings.EMAIL_HOST_USER, ['to@example.com'] ) Подскажите куда это вписывать?

Ответить

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

19.07.2019 19:34 #

Да можно в любом месте писать, где нужно его выполнить. Допустим, во view.py в методе, который выполняется, когда пользователь переходит по url

Ответить

Гость
Гость

21.08.2019 13:02 #

kak v django reset password

Ответить

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

23.08.2019 20:49 #

Ответить

Гость
Гость

27.08.2019 14:46 #

А что можно сделать, чтобы сообщения не банили из-за подозрения на спам? Использую рассылку от yandex

Ответить

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

27.08.2019 22:57 #

Общие рекомендации:

  • поэкспериментировать с интервалом рассылки, например, 1 письмо в минуту.
  • не использовать слова типа "деньги, вложение, инвестирование, заработок и т. д."

то есть нужно проверить текст на спам-слова.
Точных инструкций я, если честно, не знаю.

А лучше, как многие советуют, использовать сторонний сервис рассылок - там должно быть настроено, чтобы письма в спам не попадали, но не факт, конечно.

Ответить

Гость
Гость

12.09.2019 14:50 #

Отлично ! при EMAIL_USE_TLS = True через Яндекс не уходило. Исправил на SSL теперь все работает . Спасибо!

Ответить

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

14.09.2019 6:06 #

Рад, что статья оказалась для вас полезной!

Ответить

Дмитрий М
Дмитрий М

07.05.2021 10:15 #

Спасибо, тебе, добрый человек) ! Все расписал как надо.

Ответить

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

10.05.2021 1:36 #

Рад стараться :)

Ответить

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

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

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

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

Отправить

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

Попробуйте

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