Django 5 для начинающих

Прогресс по курсу:  9/1004

6.4 Рекомендация постов по электронной почте
4 из 7 шагов пройдено
0 из 9 баллов  получено

Мы реализовали представление отображения формы на странице и передачи формы на обработку. Теперь мы научимся отправлять электронные письма с помощью Django и затем добавим эту функциональность в представление post_share.

Отправка электронных писем с помощью Django

Отправка электронных писем в Django очень проста. Для того чтобы отправлять электронные письма с помощью Django, необходимо иметь локальный SMTP-сервер(работающий по простому протоколу передачи почты) либо обращаться к внешнему SMTP-серверу, например к своему поставщику услуг электронной почты.

Следующие ниже настроечные параметры позволяют определять конфигурацию SMTP, чтобы отправлять электронные письма с помощью Django:

  • EMAIL_HOST: хост SMTP-сервера; по умолчанию используется localhost;
  • EMAIL_PORT: SMTP-порт; по умолчанию равен 25;
  • EMAIL_HOST_USER: пользовательское имя для SMTP-сервера;
  • EMAIL_HOST_PASSWORD: пароль для SMTP-сервера;
  • EMAIL_USE_TLS: следует ли использовать защищенное соединение транспортного слоя (TLS)2;
  • EMAIL_USE_SSL: следует ли использовать неявное защищенное соединение TLS.

В этом примере мы будем использовать SMTP-сервер Google со стандартной учетной записью Gmail.

Если у вас есть учетная запись Gmail, то отредактируйте файл settings.py проекта, добавив следующий ниже исходный код:

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'

# Конфигурация сервера электронной почты
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_HOST_USER = 'your_account@gmail.com'
EMAIL_HOST_PASSWORD = ''
EMAIL_PORT = 587
EMAIL_USE_TLS = True

Замените your_account@gmail.com своей реальной учетной записью Gmail. Если у вас нет учетной записи Gmail, то можете использовать конфигурацию SMTP-сервера своего поставщика услуг электронной почты.

Вместо Gmail также можно использовать профессиональный масштабируемый почтовый сервис, который позволяет отправлять электронные письма по протоколу SMTP, используя ваш собственный домен.

Например, SendGrid(https://sendgrid.com/) или простой почтовый сервис Amazon(https://aws.amazon.com/ses/). Оба сервиса потребуют подтверждения домена и учетных записей электронной почты отправителя и предоставят учетные данные SMTP для отправки электронных писем.

Приложения Django django-sendgrid и django-ses упрощают задачу добавления сервисов SendGrid или Amazon SES в свой проект. Инструкции по установке django-sendgrid находятся на странице https://github.com/sklarsa/django-sendgrid-v5, инструкции по установке django-ses расположены на странице https://github.com/django-ses/django-ses.

Если вы не можете использовать SMTP-сервер, то можно сообщить Django, что нужно писать электронные письма в консоль, добавив в файл settings.py следующий ниже настроечный параметр:

EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

Используя этот параметр, Django будет выводить все электронные письма в оболочку, не отправляя их. Это бывает очень удобно при тестировании своего приложения без SMTP-сервера.

Завершая конфигурирование Gmail, необходимо ввести пароль для SMTP-сервера. Поскольку Google использует двухэтапный процесс верификации и дополнительные меры безопасности, вы не сможете использовать пароль своей учетной записи Google напрямую.

Вместо этого Google позволяет создавать конкретно-прикладные пароли в вашем аккаунте. Пароль приложения – это 16-значный код доступа, который дает менее защищенному приложению или устройству разрешение на доступ к вашей учетной записи Google.

Пройдите по URL-адресу https://myaccount.google.com/ в своем браузере. Введем в поиске:

Далее выбираем Приложение - Другое:

Вводим название my_blog и получаем наш пароль:

Или следуйте инструкции - https://support.google.com/accounts/answer/185833.

Скопируйте сгенерированный пароль приложения. Отредактируйте файл settings.py проекта, добавив пароль приложения в настроечный параметр EMAIL_HOST_PASSWORD, как показано ниже:

# Конфигурация сервера электронной почты
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_HOST_USER = 'your_account@gmail.com'
EMAIL_HOST_PASSWORD = 'xxxxxxxxxxxxxxxx'
EMAIL_PORT = 587
EMAIL_USE_TLS = True

Откройте оболочку Python, выполнив следующую ниже команду в командной строке системной оболочки:

python manage.py shell

Исполните следующий ниже исходный код в оболочке Python:

from django.core.mail import send_mail
send_mail('Django mail',
          'This e-mail was sent with Django.',
          'Ваш e-mail, как и в настройках Django',
          ['e-mail куда отправить письмо'],
          fail_silently=False)

Функция send_mail() принимает тему, сообщение, отправителя и список получателей в качестве требуемых аргументов. Устанавливая опциональный аргумент fail_silently=False, мы сообщаем ей, что если электронное письмо невозможно отправить, нужно вызывать исключение.

Если результат, который вы видите, равен 1, значит, ваше электронное письмо было успешно отправлено:

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

В следующем шаге мы добавим эту функциональность в представление post_share.

Более подробная информация об отправке электронных писем с помощью Django находится на странице https://docs.djangoproject.com/en/5.0/topics/email/.


  • Комментариев
Будьте вежливы и соблюдайте наши принципы сообщества. Пожалуйста, не оставляйте решения и подсказки в комментариях, для этого есть отдельный форум.
Оставить комментарий

Фуф. Так легко идет Django и с таким трудом ушло письмо) С mail.ru совсем не получилось, с яндекс - со второй попытки. Оказалось, по умолчанию IMAP отключен, надо включить. Потом почитала комментарии - и там уже есть решение, с картинками) Обидно) Вывод: если что-то не получается - сначала читай комментарии, быстрее будет.

Благодаря Антонио Меле эти знания уже есть, но освежить не помешает :-)

Настройки для yandex: https://proghunter.ru/articles/setting-up-the-smtp-mail-service-for-yandex-in-django

После настройки перезапустите shell.

Изменен Александр Павлов

У меня есть вопрос. Я пытался создать файл config.py и добавил его в Gitignore и пытался импортировать из него переменные в файл settings.py

EMAIL_HOST = config.email_host
EMAIL_HOST_USER = config.email_host_user
EMAIL_HOST_PASSWORD = config.email_host_paswors

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

@Николай_Глазков, посмотрите этот шаг https://stepik.org/lesson/1005422/step/3, там есть решение с использованием python-dotenv.

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

@Руслан_Гафаров, нет, все работает и можно создавать. Единственное, что нужно включить, это двухэтапную аутентификацию. Я думаю можно такое же сделать и у Mail.RU и у Yandex

'from@example.com'

вместо этой строки нужно вставить тот же gmail который писали в settings

['to@example.com']

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

@Никита_Ильин, Поправили в лекции, чтобы было понятнее.

Здравствуйте, возникла проблема. Cледовал инструкции, получил 16-значный пароль, при попытке отправить email возникла ошибка 'ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1006)'
 

У вас макос? Если да, то выполните команду: pip install --upgrade certifi

@Илья_Перминов, Да, у меня mac os. Выполнил pip install --upgrade certifi. (Requirement already satisfied: certifi in /Users/mantsv/PycharmProjects/pythonProject12/venv/lib/python3.11/site-packages (2023.7.22)) Ошибка осталась.(

Изменен Vasily Mantsagov

@Vasily_Mantsagov, А выполнили в основном терминале? И после вроде нужно перезагрузить систему.

@Илья_Перминов,  После этой команды все заработало

/Applications/Python\ 3.11/Install\ Certificates.command

Соответственно в основном выполнил pip install --upgrade certifi
После в основном терминале команда: /Applications/Python\ 3.11/Install\ Certificates.command

И выдает заветную 1)

Еще один вопрос, в письме как и было задумано 'This e-mail was sent with Django.', но пришло еще письмо от Mail Delivery Subsystem <mailer-daemon@googlemail.com>

Полученный ответ:

DNS Error: DNS type 'mx' lookup of mantsagov83.com responded with code NXDOMAIN Domain name not found: mantsagov83.com Learn more at https://support.google.com/mail/?p=BadRcptDomain

Так и должно быть на данном этапе?

@Vasily_Mantsagov, нет, а что за домен mantsagov83.com ? Может быть у вас к вашей почте привязан еще какой-то почтовый сервер?

@Илья_Перминов, к почте не привязан больше никакой почтовый сервер. 

@Vasily_Mantsagov, а что за домен mantsagov83.com ? Это ваш может когда-то был? Почему-то gmail обращается к этому домену в поисках MX записи в DNS.

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

@Vasily_Mantsagov, я наверное понял в чем ошибка. Попробуйте выполнить в шеле команду, заполнив верно адреса для сообщений:

from django.core.mail import send_mail
send_mail('Django mail',
          'This e-mail was sent with Django.',
          'Ваш e-mail, как и в настройках Django',
          ['e-mail куда отправить письмо'],
          fail_silently=False)

Я так понял, что вы пытаетесь отправить с почты, которой нет в настройках Django, поэтому она ищет MX сервера, которые она подставляет через SITE_ID.

Изменен Илья Перминов

Здравствуйте, возникла проблема. Вроде, следовал инструкции, получил 16-значный пароль, при попытке отправить email возникла ошибка 'ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:992)'.

@Сак_Валентин, отправьте свой проект Илье на почту perminoff-ilya@yandex.ru, он посмотрит.

Нужна помощь, есть гугл-аккаунт, но нет почты gmail (давным-давно вроде бы ее удалил), поэтому пытался сделать через почту mail.ru, соответственно в settings прописывал данные этой почты - в результате ошибка, просит пароль, хотя приложение я создал и пароль сохранил в EMAIL_HOST_PASSWORD. И, кстати, с помощью этого сгенерированного пароля зайти в аккаунт у меня не выходило. Что может быть не так ?

 

При создании новой gmail почты, создался новый гугл-аккаунт, но у него почему-то нет в меню пункта "пароли приложений" 

Изменен Дмитрий Чекмасов

@Дмитрий_Чекмасов, По поводу гугла, скорее всего нужно включить двухэтапную аутентификацию. По поводу мейла, тут не подскажу, нужны данные доступа, чтобы попробовать самому.

Изменен Илья Перминов

@Илья_Перминов, после включения двухэтапной аут-ии все заработало, спасибо

>>> from django.core.mail import send_mail
>>> send_mail('Django mail',
...           'This e-mail was sent with Django.',
...           'terbik123255@gmail.com',
...           ['terbik44@gmail.com'],
...           fail_silently=False)
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "S:\JetBrains\projects\DjangoBlog\venv\Lib\site-packages\django\core\mail\__init__.py", line 87, in send_mail
           ^^^^^^^^^^^
  File "S:\JetBrains\projects\DjangoBlog\venv\Lib\site-packages\django\core\mail\message.py", line 298, in send
    return self.get_connection(fail_silently).send_messages([self])
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "S:\JetBrains\projects\DjangoBlog\venv\Lib\site-packages\django\core\mail\backends\smtp.py", line 127, in send_messages
    new_conn_created = self.open()
                       ^^^^^^^^^^^
  File "S:\JetBrains\projects\DjangoBlog\venv\Lib\site-packages\django\core\mail\backends\smtp.py", line 94, in open
    self.connection.login(self.username, self.password)
  File "C:\Users\terbi\AppData\Local\Programs\Python\Python311\Lib\smtplib.py", line 716, in login    
    raise SMTPNotSupportedError(
smtplib.SMTPNotSupportedError: SMTP AUTH extension not supported by server.
>>> >>> from django.core.mail import send_mail
  File "<console>", line 1
    >>> from django.core.mail import send_mail
    ^^
SyntaxError: invalid syntax
>>> >>> send_mail('Django mail',
  File "<console>", line 1
    >>> send_mail('Django mail',
    ^^
SyntaxError: invalid syntax
>>> ...           'This e-mail was sent with Django.',
  File "<console>", line 1
    ...           'This e-mail was sent with Django.',
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SyntaxError: invalid syntax
>>> ...           'terbik123255@gmail.com',
  File "<console>", line 1
    ...           'terbik123255@gmail.com',
                  ^^^^^^^^^^^^^^^^^^^^^^^^
SyntaxError: invalid syntax
>>> ...           ['terbik44@gmail.com'],
<console>:1: SyntaxWarning: 'ellipsis' object is not subscriptable; perhaps you missed a comma?       
Traceback (most recent call last):
  File "<console>", line 1, in <module>
TypeError: 'ellipsis' object is not subscriptable
>>> ...           fail_silently=False)
  File "<console>", line 1
    ...           fail_silently=False)
                                     ^
SyntaxError: unmatched ')'
>>> Traceback (most recent call last):
  File "<console>", line 1
    Traceback (most recent call last):
               ^^^^^^^^^^^
SyntaxError: invalid syntax. Perhaps you forgot a comma?
>>>   File "<console>", line 1, in <module>
  File "<console>", line 1
    File "<console>", line 1, in <module>
IndentationError: unexpected indent
>>>   File "S:\JetBrains\projects\DjangoBlog\venv\Lib\site-packages\django\core\mail\__init__.py", line 87, in send_mail
  File "<console>", line 1
    File "S:\JetBrains\projects\DjangoBlog\venv\Lib\site-packages\django\core\mail\__init__.py", line 87, in send_mail
IndentationError: unexpected indent
>>>     return mail.send()
  File "<console>", line 1
    return mail.send()
IndentationError: unexpected indent
>>>            ^^^^^^^^^^^
  File "<console>", line 1
    ^^^^^^^^^^^
IndentationError: unexpected indent
>>>   File "S:\JetBrains\projects\DjangoBlog\venv\Lib\site-packages\django\core\mail\message.py", line 298, in send
  File "<console>", line 1
    File "S:\JetBrains\projects\DjangoBlog\venv\Lib\site-packages\django\core\mail\message.py", line 298, in send
IndentationError: unexpected indent
>>>     return self.get_connection(fail_silently).send_messages([self])
  File "<console>", line 1
    return self.get_connection(fail_silently).send_messages([self])
IndentationError: unexpected indent
>>>            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<console>", line 1
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
IndentationError: unexpected indent
>>>   File "S:\JetBrains\projects\DjangoBlog\venv\Lib\site-packages\django\core\mail\backends\smtp.py", line 127, in send_messages
  File "<console>", line 1
    File "S:\JetBrains\projects\DjangoBlog\venv\Lib\site-packages\django\core\mail\backends\smtp.py", line 127, in send_messages
IndentationError: unexpected indent
>>>     new_conn_created = self.open()
  File "<console>", line 1
    new_conn_created = self.open()
IndentationError: unexpected indent
>>>                        ^^^^^^^^^^^
  File "<console>", line 1
    ^^^^^^^^^^^
IndentationError: unexpected indent
>>>   File "S:\JetBrains\projects\DjangoBlog\venv\Lib\site-packages\django\core\mail\backends\smtp.py", line 94, in open
  File "<console>", line 1
    File "S:\JetBrains\projects\DjangoBlog\venv\Lib\site-packages\django\core\mail\backends\smtp.py", line 94, in open
IndentationError: unexpected indent
>>>     self.connection.login(self.username, self.password)
  File "<console>", line 1
    self.connection.login(self.username, self.password)
IndentationError: unexpected indent
>>>   File "C:\Users\terbi\AppData\Local\Programs\Python\Python311\Lib\smtplib.py", line 716, in login

  File "<console>", line 1
    File "C:\Users\terbi\AppData\Local\Programs\Python\Python311\Lib\smtplib.py", line 716, in login  
IndentationError: unexpected indent
>>>     raise SMTPNotSupportedError(
  File "<console>", line 1
    raise SMTPNotSupportedError(
IndentationError: unexpected indent
>>> smtplib.SMTPNotSupportedError: SMTP AUTH extension not supported by server.

почему может не работать?

@Vlad_Kirnats, Проверяйте настройки почты в settings.py, похоже что не может авторизоваться на сервере SMTP.

terbik123255@gmail.com это ваш емейл?

здравствуйте, мне вместо сообщения пришла какая то ошибка на почту

@Владислав_Пирогов, Распишите пожалуйста при каких обстоятельствах вы получили данное сообщение, чтобы мы могли сымитировать ее. Я уже что только не делал, но так ничего не приходит.

@Владислав_Пирогов, Методом тыка я похоже понял, попробуйте выполнить в шеле команду, заполнив верно адреса для сообщений:

from django.core.mail import send_mail
send_mail('Django mail',
          'This e-mail was sent with Django.',
          'e-mail куда отправить письмо',
          ['Ваш e-mail, как и в настройках Django'],
          fail_silently=False)

@Илья_Перминов, всё заработало, в какой раз поддержка на высоте, спасибо большое!

>>> from django.core.mail import send_mail
>>> send_mail('Django mail',
...           'This e-mail was sent with Django.',
...           'from@example.com',
...           ['to@example.com'],
...           fail_silently=False)
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "G:\PyProjects\Study\mysite\venv\Lib\site-packages\django\core\mail\__init__.py", line 87, in send_mail
    return mail.send()
           ^^^^^^^^^^^
  File "G:\PyProjects\Study\mysite\venv\Lib\site-packages\django\core\mail\message.py", line 298, in send
    return self.get_connection(fail_silently).send_messages([self])
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "G:\PyProjects\Study\mysite\venv\Lib\site-packages\django\core\mail\backends\smtp.py", line 127, in send_messages
    new_conn_created = self.open()
                       ^^^^^^^^^^^
  File "G:\PyProjects\Study\mysite\venv\Lib\site-packages\django\core\mail\backends\smtp.py", line 85, in open
    self.connection = self.connection_class(
                      ^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Python\Python311\Lib\smtplib.py", line 255, in __init__
    (code, msg) = self.connect(host, port)
                  ^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Python\Python311\Lib\smtplib.py", line 341, in connect
    self.sock = self._get_socket(host, port, self.timeout)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Python\Python311\Lib\smtplib.py", line 312, in _get_socket
    return socket.create_connection((host, port), timeout,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Python\Python311\Lib\socket.py", line 827, in create_connection
    for res in getaddrinfo(host, port, 0, SOCK_STREAM):
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Python\Python311\Lib\socket.py", line 962, in getaddrinfo
    for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
socket.gaierror: [Errno 11001] getaddrinfo failed
 

@Григорий_Кожанов, проверьте конфигурацию SMTP в Джанго, особенно настройку EMAIL_HOST.
Если с ней всё в порядке, то тогда выполните пинг используемого SMTP сервера, выполните в командной строке:

ping smtp.gmail.com

 Если не пингуется, то проблема не в Джанго.

@Дмитрий_Селезнев, Опечатался в названии хоста, исправил, заработало. Спасибо!!!

[WinError 10061] Подключение не установлено, т.к. конечный компьютер отверг запрос на подключение
 

@Михаил_Зайнутдинов, выполните в командной строке:

telnet smtp.gmail.com 587

Если ошибок не будет, то причина в настройках Джанго или аккаунта Гмейл.

@Дмитрий_Селезнев, Спасибо, проблема была на стороне сети

Не понимаю зачем в send_mail прописывать from_email=from@example.com, если отправитель у нас указан в настройках проекта EMAIL_HOST_USER. Есть сценарии при которых эти два параметра различаются? 
Тест: Я попробовал в from_email передать несуществующую электронную почту. Письмо дошло до адресата, в качестве отправителя указан EMAIL_HOST_USER.
PS: Под капотом нашел, что можно задать DEFAULT_FROM_EMAIL и он будет использоваться в качестве отправителя по умолчанию.

Изменен Антон Глухенко

@Антон_Глухенко, в Джанго можно задать отправителя только двумя способами или в from_email или в DEFAULT_FROM_EMAIL, если они не заданы, то отправитель в заголовке письма будет webmaster@localhost, который затем будет переписан гугловским smtp сервером на значение из вашей учётной записи = EMAIL_HOST_USER.