Отказ от ответственности: я колебался в названии, из-за широкого характера этого вопроса (см. Ниже ;-), другие варианты включены:
- Как отправить письмо с localhost, используя только код Python?
- Как отправить письмо из кода Python, без использования внешнего SMTP-сервера?
- Можно ли отправить электронное письмо ПРЯМО в это место назначения, используя только localhost и Python?
Сначала немного контекста:
Ради обучения я создаю сайт с функцией регистрации пользователей. Идея заключается в том, что после регистрации пользователь получит письмо со ссылкой для активации. Я хотел бы составить и отправить электронное письмо из кода Python, и это та часть, где я хотел бы попросить некоторые разъяснения.
Мое понимание до того, как я начал (очевидно, наивный =), можно проиллюстрировать следующим образом (учитывая, что существует законный адрес электронной почты [email protected]):
После поиска примеров я наткнулся на некоторые вопросы и ответы по stackoverflow (1, 2, 3, 4). Из этого я извлек следующий фрагмент кода, чтобы составить и отправить электронное письмо из кода Python:
import smtplib
from email.message import EmailMessage
message = EmailMessage()
message.set_content('Message content here')
message['Subject'] = 'Your subject here'
message['From'] = '[email protected]'
message['To'] = '[email protected]'
smtp_server = smtplib.SMTP('smtp.server.address:587')
smtp_server.send_message(message)
smtp_server.quit()
Следующий (очевидный) вопрос заключался в том, что передать smtplib.SMTP()
вместо 'smtp.server.address:587'
. Из комментариев к этому ответу я обнаружил, что локальный SMTP-сервер (хотя и для целей тестирования) можно запустить через python3 -m smtpd -c DebuggingServer -n localhost:1025
, затем smtp_server = smtplib.SMTP('smtp.server.address:587')
может быть изменен на smtp_server = smtplib.SMTP('localhost:1025')
и все отправленные электронные письма будут отображаться в консоли (откуда python3 -m smtpd -c DebuggingServer -n localhost:1025
Команда python3 -m smtpd -c DebuggingServer -n localhost:1025
была выполнена), этого было достаточно для тестирования - это было не то, что я хотел (моя цель была - возможность отправлять почту на "реальный" адрес электронной почты с локальной машины, используя только код Python).
Итак, следующим шагом будет настройка локального SMTP-сервера, способного отправлять электронную почту на внешний "реальный" адрес электронной почты (как я хотел сделать все это из кода Python, так что сам сервер лучше реализовать в Питон тоже). Я вспомнил, как читал в каком-то журнале (в начале 2000 года), что спамеры используют локальные серверы для отправки почты (эта конкретная статья говорила о Sambar, разработка которого закончилась в 2007 году, и которая не была написана на Python :-) Я думал там должно быть какое-то современное решение с аналогичной функциональностью. Поэтому я начал искать, я надеялся найти (в стеке или в другом месте) достаточно короткий фрагмент кода, который будет делать то, что я хотел. Я не нашел такого фрагмента кода, но натолкнулся на фрагмент под названием (Python) "Отправить электронную почту без почтового сервера" (который использует API-интерфейс chilkat), хотя все, что мне было нужно (предположительно), было прямо там, в комментариях к коду, В первой строке четко указано:
Реально ли отправлять электронную почту без подключения к почтовому серверу? На самом деле, нет.
и несколько строк ниже:
Вот что происходит внутри тех других компонентов, которые утверждают, что им не нужен почтовый сервер: Компонент выполняет поиск DNS MX, используя адрес электронной почты получателя, чтобы найти почтовый сервер (т.е. SMTP-сервер) для этого домена. Затем он подключается к этому серверу и доставляет электронную почту. Вы все еще подключаетесь к SMTP-серверу, но не к ВАШЕМУ серверу.
Прочитав это, я понял - мне явно не хватало некоторых деталей в моем понимании (как показано на картинке выше) процесса. Чтобы исправить это, я прочитал весь RFC на SMTP.
После прочтения RFC моё лучшее понимание процесса может быть изображено так:
Из этого понимания пришли реальные вопросы, которые я хотел бы уточнить:
- Можно ли считать мое "улучшенное понимание" правильным, как общую картину?
-
Какие именно адреса возвращаются поиском MX?
-
используя
host -t mx gmail.com
(предложенную этим ответом), я смог получить следующее:gmail.com mail is handled by 10 alt1.gmail-smtp-in.l.google.com. gmail.com mail is handled by 20 alt2.gmail-smtp-in.l.google.com. gmail.com mail is handled by 40 alt4.gmail-smtp-in.l.google.com. gmail.com mail is handled by 30 alt3.gmail-smtp-in.l.google.com. gmail.com mail is handled by 5 gmail-smtp-in.l.google.com.
- но ничего из этого не упоминается в официальных документах (см.
smtp-relay.gmail.com
,smtp.gmail.com
,aspmx.l.google.com
)
-
-
Всегда ли требуется аутентификация для передачи электронной почты на SMTP-сервер установленного почтового сервиса (скажем, gmail)?
-
Я понимаю, что для использования, скажем,
smtp.gmail.com
для отправки почты вам понадобится, независимо от того, есть у@gmail
адрес@gmail
или нет (как указано в документации):Ваш полный адрес электронной почты Gmail или G Suite необходим для аутентификации.
-
Но если электронное письмо на адрес
[email protected]
будет отправлено на SMTP-сервер, не принадлежащий gmail, оно будет перенаправлено на один из серверов gmail (напрямую или через шлюз/ретранслятор). В этом случае (я полагаю) отправителю электронной почты нужно будет пройти аутентификацию только при отправке почты, поэтому после этого сервер gmail будет принимать почту без аутентификации?- Если да, что мешает мне "притворяться" таким шлюзом/ретранслятором и передавать сообщения электронной почты непосредственно назначенным SMTP? Тогда также должно быть довольно легко написать "прокси-SMTP", который будет просто искать соответствующий сервер через поиск MX и перенаправлять ему электронные письма, вроде как напрямую.
-
-
В документации по SMTP gmail также упоминается сервер
aspmx.l.google.com
, который не требует аутентификации, хотя:Почту можно отправлять только пользователям Gmail или G Suite.
Учитывая это, я предполагаю, что следующий фрагмент должен работать для отправки почты на почтовый ящик
[email protected]
:import smtplib from email.message import EmailMessage message = EmailMessage() message.set_content('Message test content') message['Subject'] = 'Test mail!' message['From'] = '[email protected]' message['To'] = '[email protected]' smtp_server = smtplib.SMTP('aspmx.l.google.com:25') smtp_server.send_message(message) smtp_server.quit()
При
OSError: [Errno 65] No route to host
приведенный выше код (с заменой[email protected]
действительной почтой) выдаетOSError: [Errno 65] No route to host
. Все, что я хочу подтвердить, это то, что сообщениеaspmx.l.google.com
правильно обрабатывается в коде.