Python арқылы SMTP жіберу: 587 портында STARTTLS әлде 465 портында TLS?
587 портындағы STARTTLS және 465 портындағы жасырын TLS екеуі де Python жіберілімін тасымалдайды, бірақ сіздің релеге тек біреуі сәйкес келеді. Қол алысуды және ақау режимдерін салыстырыңыз.
Екі қосылу режимі де бірдей хабарламаны бірдей реле есептік жазбасына жеткізеді, ал айырмашылық TLS қай жерде басталатынында, нені жіберуде емес. Біреуі ашық мәтінмен ашылып, арнаның ішінде жаңарады; екіншісі бірінші байттан бастап шифрланған. Осы бір айырмашылық қатаң реле саясаты нені қабылдайтынын, аралық құрылғы нені байқай алатынын және қандай қате хабарламасын түстен кешке дейін оқитыныңызды анықтайды. Жеке желідегі қолданба хабарламаны ішкі жіберу қызметіне тапсырғанда мен осы екеуінің арасында қалай таңдайтынымды келтіремін.
Екі режим шын мәнінде қай жерде ажырайды
Екі жағдайда да міндет бірдей: бекітілген есептік жазба ретінде аутентификациялау, рұқсат етілген жіберушіні атау, алушыларды тізімдеу және реленің жауапкершілікті өз мойнына алуын күту. Өзгеретіні — операциялардың реті. 587 порты ашық мәтінді SMTP сессиясы ретінде басталады, EHLO жауабында STARTTLS жариялайды және клиент сұраса ғана жаңарады. 465 порты кез келген SMTP командасы айтылмай тұрып TLS қол алысуды күтеді.
Жіберу мен реле — түрлі жұмыстар, сондықтан порт нөмірлері алмастыруға келетін әдеттер емес. RFC 6409 хабарлама жіберуді жеке қызмет ретінде сипаттайды, ал RFC 8314 қазіргі релелердің көбісі 465 портында ұсынатын жасырын TLS нұсқасын қамтиды. Егер сіздің реле екеуінің біреуін құжаттаса, сол құжат бұрынғы жұмыс берушіден алған кез келген таңдаудан жоғары тұрады.
587 портындағы STARTTLS сізге не береді
Жаңару SMTP әңгімесінің ішінде болады, сондықтан реле оны жариялай алады, ал клиент онсыз жалғастырудан бас тарта алады. Python-да starttls() сервер бұл кеңейтімді ұсынбағанда ерекше жағдай лақтырады, бұл төмендету әрекетін тыныш ашық мәтінді кіру орнына көрінетін сәтсіздікке айналдырады. Бұл мінез-құлық режимнің басты дәлелі, және оған кездейсоқ емес, әдейі сүйенген жөн.
Әсер ету терезесі кішкентай, бірақ шынайы: бастапқы EHLO алмасуы оқылады, ал жаңаруға дейін ештеңе тіркелгі деректерін тасымалдамайды. Қолданбаның ішкі желісі мен ішкі реле арасындағы жеке жолда бұл терезе әдетте қолайлы. Өзіңіз бақыламайтын жолда дәл осы себеп кейбір топтардың басқа режимді талап етуіне әкеледі.
STARTTLS мүмкіндігін жоятын ұстап қалу құрылғысы сәтсіз жіберуді тудырады, кері шегінуді емес. Бұл — қалаған нәтиже, әрі жолда бірдеңе SMTP-ны қайта жазып жатқанын анықтаудың ең жылдам жолы.
465 портындағы жасырын TLS нені өзгертеді
Ашық мәтін кезеңі мүлде жоқ. Клиент сокет ашыла салысымен TLS қол алысуды орындайды, сертификатты өз сенім қоймасына қарсы тексереді, содан кейін ғана EHLO, AUTH және хабарламаны алмасады. Сессияны ештеңе төмендете алмайды, өйткені келіссөз жүргізетін ашық мәтін күйі жоқ, және бұл ұстап қалу ақауларының тұтас бір класын жояды.
Айырбас — диагностикалық мүмкіндік. 465 портында ашық мәтінді SMTP-мен жауап беретін реле немесе TLS-ті дұрыс емес сертификат атымен аяқтайтын жүктеме теңгерушісі қол алысуда сәтсіздікке ұшырайды және пошта қатесінің орнына SSL қатесін береді. Бұл болғанда, мәселе қолданбаның астында, және хабарлама құрудың ешбір мөлшері оны түзетпейді.
Бір жіберу функциясы, екі көлік
Код режимдер арасында әрең ерекшеленеді, сондықтан таңдау кітапхана ыңғайлылығынан емес, реле саясатынан жасалуы керек. Алдымен параметрлерді экспорттаңыз, содан кейін конфигурацияланған порттан көлікті таңдайтын бір скриптті іске қосыңыз.
export SMTP_HOST=smtp.relay.internal export SMTP_PORT=587 export SMTP_USER=svc-notify export [email protected] export [email protected] export SMTP_PASSWORD="$(cat /run/secrets/smtp_password)"
import os, smtplib, ssl
from email.message import EmailMessage
ctx = ssl.create_default_context()
msg = EmailMessage()
msg["From"] = os.environ["MAIL_FROM"]
msg["To"] = os.environ["MAIL_TEST_TO"]
msg["Subject"] = "relay submission test"
msg.set_content("One authorized test message from the app.")
host = os.environ["SMTP_HOST"]
port = int(os.environ.get("SMTP_PORT", "587"))
if port == 465:
client = smtplib.SMTP_SSL(host, port, context=ctx, timeout=15)
else:
client = smtplib.SMTP(host, port, timeout=15)
client.ehlo()
client.starttls(context=ctx)
client.ehlo()
with client:
client.login(os.environ["SMTP_USER"], os.environ["SMTP_PASSWORD"])
refused = client.send_message(msg)
print("refused:", refused)
create_default_context() тізбекті және хост атын тексереді, сондықтан жеке CA сенім қоймасына орнатылуы керек, тексерілмеген контекстпен айналып өтуге болмайды. send_message() реле қабылдамаған алушылардың сөздігін қайтарады; бос сөздік оның барлығын қабылдағанын білдіреді. Он бес секундтық таймаут — бастау нүктесі, желіңіз үшін реттелген мән емес.
Құпия сөзді бейнеден және журналдардан тыс ұстаңыз. Орындалу кезінде тіркеліп, ортаға оқылатын құпия дұрыс; ортаны журнал жолына көшіру дұрыс емес, AUTH алмасуының жөндеу ізі де емес.
Әдет бойынша емес, реле саясаты мен жол бойынша таңдаңыз
Үш шарт шешеді. Біріншіден, реле шын мәнінде нені жариялайды: тек 587 портында STARTTLS-пен тыңдайтын қызметке 465 портынан жету мүмкін емес, жасырын TLS-ті қаншалықты қаласаңыз да. Екіншіден, қолданба мен реле арасындағы жол оқылатын EHLO алмасуын қабылдауға жеткілікті сенімді ме. Үшіншіден, ортада бірдеңе SMTP-ны қайта жазады немесе проксилейді ме, өйткені бұл төмендету тәуекелінің теориялық па әлде нақты ма екенін анықтайды.
Реле екеуін де ұсынғанда, қадағалаусыз жұмыс істейтін қызмет үшін 465-ті, ал бірінші орналастыруды адам бақылайтын қызмет үшін 587-ні аламын, тек қате хабарламалары түрлі қабаттарға нұсқайтындықтан. Бұл таңдау — менің жеке қалауым, ол саясат емес.
Не таңдасаңыз да, портты, сенім материалын және жіберуші доменін орналастырумен бірге жазып қойыңыз. Содан кейін бір рұқсат етілген сынақ хабарламасын жіберіп, реленің оны қабылдағанын растаңыз, жіберу нәтижесі мен кез келген кейінгі жеткізу есебін бөлек жазбалар ретінде сақтаңыз. Релеге сәтті тапсыру — қолданба жауапкершілігінің соңы, хабарламаның кіріс жәшігіне жеткенінің дәлелі емес.