Отказ от ответственности : я колебался в названии из-за широкого характера этого вопроса (см. Ниже ;-), другие варианты включены:
- Как отправить письмос локального хоста, используя только код Python?
- Как отправить электронное письмо из кода Python, без использования внешнего SMTP-сервера?
- Возможно ли отправить сообщение ПРЯМО в адрес назначения, используя localhost иТолько на Python?
Во-первых, немного контекста :Ради обучения я создаю сайт с функцией регистрации пользователей.Идея заключается в том, что после регистрации пользователь получит письмо со ссылкой для активации.Я хотел бы составить и отправить электронное письмо из кода Python, и это та часть, где я хотел бы попросить некоторые разъяснения.
Мое понимание, прежде чем я начал (очевидно,Наивный =) можно проиллюстрировать следующим образом (учитывая, что существует допустимый адрес электронной почты user@example.com):
После поиска примеров я наткнулся на некоторые вопросы и ответы по 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'] = 'me@example.com'
message['To'] = 'user@example.com'
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
), и этого будет достаточно для тестирования - это было не то, что я хотел (моей целью было - возможность отправлять почту на реальный адрес электронной почты с локального компьютера), используя только код Python).
Итак, следующим шагом будет настройка локального SMTP-сервера, способного отправлять электронную почту на внешний «реальный» адрес электронной почты (как я хотел сделать все этоиз кода Python, поэтому сам сервер лучше будет реализовывать и в Python).Я вспомнил, как читал в каком-то журнале (в начале 2000 года), что спамеры используют локальные серверы для отправки почты (в этой конкретной статье говорилось о Sambar , разработка которого закончилась в 2007 году и которая не была написана на Python:-) Я думал, что должно быть какое-то современное решение с подобной функциональностью.Поэтому я начал искать, я надеялся найти (в стеке или в другом месте) достаточно короткий фрагмент кода, который будет делать то, что я хотел.Я не нашел такого фрагмента кода, но натолкнулся на фрагмент под названием (Python) Отправить электронную почту без почтового сервера (который использует chilkat API), хотя все, что мне было нужно (предположительно) прямо там, в комментариях к коду, в первой строке было четко указано:
Действительно ли возможно отправлять электронную почту без подключения к почтовому серверу?Не совсем.
и несколько строк ниже:
Вот что происходит внутри тех других компонентов, которые утверждают, что им не нужен почтовый сервер: Компонент выполняет поиск 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 или G Suite требуется для аутентификации.
Но, если письмо на user@gmail.com
отправлено на SMTP-сервер, не принадлежащий gmail, то оноВы будете перенаправлены на один из серверов Gmail (напрямую или через шлюз / ретранслятор).В этом случае (я полагаю) отправителю электронной почты нужно будет пройти аутентификацию только при отправке почты, поэтому после этого сервер gmail будет принимать почту без аутентификации?
- Если да, что мешает мне «притворяться» таким шлюзом / ретранслятором и передавать сообщения электронной почты непосредственно на назначенные им SMTP?Тогда также должно быть довольно легко написать «прокси-SMTP», который будет просто искать соответствующий сервер через поиск MX и перенаправлять ему электронные письма, вроде как напрямую.
Документация по SMTP gmail , также упоминает aspmx.l.google.com
сервер, который не требует аутентификации, хотя:
Почту можно отправлять только пользователям Gmail или G Suite.
Учитывая вышесказанное, я предполагаю, что следующий фрагмент кода должен работать для отправки почты в почтовый ящик ExistingUser@gmail.com
:
import smtplib
from email.message import EmailMessage
message = EmailMessage()
message.set_content('Message test content')
message['Subject'] = 'Test mail!'
message['From'] = 'me@whatever.com'
message['To'] = 'ExistingUser@gmail.com'
smtp_server = smtplib.SMTP('aspmx.l.google.com:25')
smtp_server.send_message(message)
smtp_server.quit()
При запуске приведенный выше код (с заменой ExistingUser@gmail.com
действительной почтой) выдает OSError: [Errno 65] No route to host
.Все, что я хочу подтвердить, это то, что сообщение на aspmx.l.google.com
правильно обрабатывается в коде.