Python SMTP orqali yuborish: 587-portda STARTTLS yoki 465-portda TLS?
587-portdagi STARTTLS va 465-portdagi yashirin TLS ikkalasi ham Python yuborishini tashiydi, lekin faqat bittasi sizning relayingizga mos keladi. Qo'l berish va xatolik usullarini solishtiring.
Ikkala ulanish rejimi ham bir xil xabarni bir xil relay hisobiga yetkazadi, farq TLS qayerda boshlanishida, nima yuborilishida emas. Biri ochiq matnda ochilib, kanal ichida ko'tariladi; ikkinchisi birinchi baytdan shifrlangan. Aynan shu bitta farq qat'iy relay siyosati nimani qabul qilishini, oraliq qurilma nimani kuzatishi mumkinligini va qaysi xato xabarini yarim kun o'qib chiqishingizni belgilaydi. Xususiy tarmoqdagi dastur xabarni ichki yuborish xizmatiga topshirganda men bu ikkisi orasida qanday tanlashimni keltiraman.
Ikki rejim aslida qayerda ajraladi
Ikkala holatda ham vazifa bir xil: tasdiqlangan hisob sifatida autentifikatsiya qilish, ruxsat etilgan jo'natuvchini ko'rsatish, qabul qiluvchilarni sanash va relay javobgarlikni olishini kutish. O'zgaradigan narsa — amallar tartibi. 587-port ochiq matnli SMTP sessiyasi sifatida boshlanadi, EHLO javobida STARTTLS e'lon qiladi va faqat mijoz so'rasa ko'tariladi. 465-port har qanday SMTP buyrug'i aytilishidan oldin TLS qo'l berishini kutadi.
Yuborish va relay — turli ishlar, shuning uchun port raqamlari almashtiriladigan odatlar emas. RFC 6409 xabar yuborishni alohida xizmat sifatida tavsiflaydi, RFC 8314 esa zamonaviy relaylarning ko'pchiligi 465-portda taqdim etadigan yashirin-TLS variantini qamrab oladi. Agar sizning relayingiz ikkisidan birini hujjatlashtirsa, o'sha hujjat avvalgi ish beruvchidan olingan har qanday afzallikdan ustun turadi.
587-portdagi STARTTLS sizga nima beradi
Ko'tarilish SMTP suhbati ichida sodir bo'ladi, shuning uchun relay uni e'lon qilishi mumkin, mijoz esa usiz davom etishdan bosh tortishi mumkin. Python'da starttls() server bu kengaytmani taklif qilmasa, istisno tashlaydi, bu pasaytirish urinishini jim ochiq matnli kirish o'rniga ko'rinadigan muvaffaqiyatsizlikka aylantiradi. Aynan shu xatti-harakat ushbu rejimning asosiy dalilidir va unga tasodifan emas, ataylab tayanishga arziydi.
Ta'sir oynasi kichik, ammo haqiqiy: dastlabki EHLO almashinuvi o'qiladi va ko'tarilishdan oldin hech narsa hisob ma'lumotlarini tashimaydi. Dastur quyi tarmog'i va ichki relay o'rtasidagi xususiy yo'lda bu oyna odatda maqbuldir. Siz nazorat qilmaydigan yo'lda esa aynan shu sabab ba'zi jamoalar boshqa rejimda turib olishadi.
STARTTLS imkoniyatini olib tashlaydigan tutib olish qurilmasi muvaffaqiyatsiz yuborish keltiradi, orqaga qaytish emas. Bu — siz xohlagan natija, hamda yo'lda biror narsa SMTP'ni qayta yozayotganini aniqlashning eng tez usuli.
465-portdagi yashirin TLS nimani o'zgartiradi
Ochiq matn bosqichi umuman yo'q. Mijoz soket ochilishi bilanoq TLS qo'l berishini amalga oshiradi, sertifikatni o'z ishonch omboriga qarab tekshiradi va shundan keyingina EHLO, AUTH va xabarni almashadi. Seansni hech narsa pasaytira olmaydi, chunki muzokara uchun ochiq matn holati yo'q, va bu tutib olishdagi muvaffaqiyatsizliklarning butun bir sinfini yo'qotadi.
Buning evaziga diagnostika olinadi. 465-portda ochiq matnli SMTP bilan javob beradigan relay yoki TLS'ni noto'g'ri sertifikat nomi bilan tugatadigan yuk balanslagich qo'l berishda muvaffaqiyatsizlikka uchraydi va sizga pochta xatosi o'rniga SSL xatosini beradi. Bu sodir bo'lganda, muammo dastur ostida bo'ladi va qancha xabar qurish ham uni tuzatmaydi.
Bitta yuborish funksiyasi, ikki transport
Kod rejimlar orasida deyarli farq qilmaydi, shuning uchun tanlov kutubxona qulayligidan emas, relay siyosatidan qilinishi kerak. Avval sozlamalarni eksport qiling, so'ng konfiguratsiya qilingan portdan transportni tanlaydigan bitta skriptni ishga tushiring.
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() zanjir va xost nomini tekshiradi, shuning uchun xususiy CA ishonch omboriga o'rnatilishi kerak, tekshirilmagan kontekst bilan chetlab o'tilmasligi kerak. send_message() relay rad etgan qabul qiluvchilarning lug'atini qaytaradi; bo'sh lug'at uning barchasini qabul qilganini bildiradi. O'n besh soniyalik taymaut boshlang'ich nuqta, tarmog'ingiz uchun sozlangan qiymat emas.
Parolni obrazdan va jurnallardan tashqarida saqlang. Ish vaqtida o'rnatilgan va muhitga o'qilgan sir yaxshi; muhitni jurnal satriga aks ettirish yaxshi emas, AUTH almashinuvining disk raskadrovka izi ham emas.
Odatga ko'ra emas, relay siyosati va yo'liga ko'ra tanlang
Uch shart hal qiladi. Birinchisi, relay aslida nimani e'lon qiladi: faqat 587-portda STARTTLS bilan tinglaydigan xizmatga 465-portdan yetib bo'lmaydi, yashirin TLS'ni qanchalik yoqtirsangiz ham. Ikkinchisi, dastur va relay o'rtasidagi yo'l o'qiladigan EHLO almashinuvini qabul qilish uchun yetarlicha ishonchlimi. Uchinchisi, o'rtada biror narsa SMTP'ni qayta yozadimi yoki proksilaydimi, chunki bu pasaytirish xavfi nazariy yoki real ekanini belgilaydi.
Relay ikkalasini taklif qilganda, men nazoratsiz ishlaydigan xizmat uchun 465-ni, birinchi joylashtirishni odam kuzatayotgan xizmat uchun 587-ni olaman, faqat xatolik xabarlari turli qatlamlarga ishora qilgani uchun. Bu afzallik meniki va u siyosat emas.
Nimani tanlasangiz ham, portni, ishonch materialini va jo'natuvchi domenini joylashtirish bilan birga yozib qo'ying. So'ng bitta ruxsat etilgan sinov xabarini yuboring va relay uni qabul qilganini tasdiqlang, yuborish natijasi va keyingi har qanday yetkazib berish hisobotini alohida yozuvlar sifatida saqlang. Relayga muvaffaqiyatli topshirish — dastur javobgarligining oxiri, xabar kiruvchi qutiga yetib borganining dalili emas.