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

23 сентября 2015 г. 0:49

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

Имейте ввиду, что большинство почтовых служ требуют в качестве пароля в параметре EMAIL_HOST_PASSWORD не пароль от аккаунта, а специально сгенерированный пароль приложения.

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

 Инструкция по генерации пароля приложения: https://help.mail.ru/mail/security/protection/external

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

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

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.6 из 5 (всего 18 оценок)

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

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

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

Автор статьи

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

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

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

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

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

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

Представляю вашему вниманию книгу, написанную моим близким другом Максимом Макуриным: Секреты эффективного управления ассортиментом.

Книга предназначается для широкого круга читателей и, по мнению автора, будет полезна специалистам отдела закупок и логистики, категорийным и финансовым менеджерам, менеджерам по продажам, аналитикам, руководителям и директорам, в компетенции которых принятие решений по управлению ассортиментом.

Комментарии: 26

Anton Emel
Anton Emel

13.09.2018 10:18 #

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

Ответить

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

12.02.2021 2:19 #

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

Ответить

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

15.09.2018 3: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 19:07 #

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

Ответить

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

25.01.2019 13: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 14:39 #

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

Ответить

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

21.04.2019 6: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 11:52 #

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

Ответить

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

19.07.2019 23:34 #

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

Ответить

Гость
Гость

21.08.2019 17:02 #

kak v django reset password

Ответить

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

24.08.2019 0:49 #

Ответить

Гость
Гость

27.08.2019 18:46 #

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

Ответить

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

28.08.2019 2:57 #

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

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

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

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

Ответить

Гость
Гость

12.09.2019 18:50 #

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

Ответить

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

14.09.2019 10:06 #

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

Ответить

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

07.05.2021 14:15 #

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

Ответить

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

10.05.2021 5:36 #

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

Ответить

Иван
Иван

18.06.2022 8:30 #

Спасибо тебе, друг!

Ответить

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

17.07.2022 17:01 #

Пожалуйста!)) рад, что статья была полезной! :)

Ответить

Гость
Гость

13.07.2022 12:03 #

Здравствуйте!
У меня есть блог сайт и я должен рассылать письма в случае если автору поста пишут комментарий. Подскажите пожалуйста как я могу это сделать?

Ответить

K.xusan_2003
K.xusan_2003

13.07.2022 12:05 #

сайт загружен на heroku и подключен к send grid*

Ответить

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

17.07.2022 16:58 #

Добрый день! Я с хероку не работал ни разу... но в доках к хероку есть инструкции. Что именно не получается?

Ответить

Гость
Гость

19.08.2023 20:30 #

Привет, как добавить кнопку "Разослать" в админку Django и привязать ее к этому view из статьи?

Ответить

Гость
Гость

02.04.2024 15:04 #

И как ты собрался не из под venv стучаться в manage.py, умник?

Ответить

Гость
Гость

02.04.2024 15:10 #

Это я же . Для всех адекватных, в крон надо пихать вот так: source path/to/activate && path/to/manage.py send_queued_mail

Ответить

Гость
Гость

02.04.2024 15:30 #

Дополню, пожалуй, что автор не написал кучу импортов : import rando m from datetime import timedelt a from django.utils import timezone

Ответить

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

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

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

Для комментирования от своего имени войдите или зарегистрируйтесь на сайте Vuspace

Отправить

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

Попробуйте

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