Python SMTP relesi: 587 portunda STARTTLS, yoxsa 465 portunda TLS?
587 portunda STARTTLS və 465-də gizli TLS hər ikisi Python göndərişini daşıyır, lakin yalnız biri sizin relenizə uyğundur. Əl sıxışmasını və uğursuzluq rejimlərini müqayisə edin.
Hər iki qoşulma rejimi eyni mesajı eyni rele hesabına daşıyır və fərq TLS-in nə vaxt başlamasındadır, nə göndərildiyində deyil. Biri açıq mətndə açılır və kanal daxilində yüksəlir; digəri ilk baytdan şifrələnir. Bu tək fərq sərt rele siyasətinin nəyi qəbul edəcəyini, aralıq qurğunun nəyi müşahidə edə biləcəyini və hansı xəta mesajını bütün günü oxuyacağınızı müəyyən edir. Şəxsi şəbəkədəki tətbiq mesajı daxili göndərmə xidmətinə təhvil verəndə ikisi arasında necə seçdiyim belədir.
İki rejim əslində harada ayrılır
Tapşırıq hər iki halda eynidir: təsdiqlənmiş hesab kimi autentifikasiya olun, icazəli göndərəni göstər, alıcıları siyahıya al və relenin məsuliyyəti qəbul etməsini gözlə. Dəyişən əməliyyatların sırasıdır. 587 portu açıq mətnli SMTP sessiyası kimi başlayır, EHLO cavabında STARTTLS elan edir və yalnız müştəri istəsə yüksəlir. 465 portu isə hər hansı SMTP əmri deyilməzdən əvvəl TLS əl sıxışması gözləyir.
Göndərmə və rele fərqli işlərdir, buna görə port nömrələri bir-birini əvəz edən vərdişlər deyil. RFC 6409 mesaj göndərməni ayrı xidmət kimi təsvir edir, RFC 8314 isə müasir relerin əksəriyyətinin 465-də təqdim etdiyi gizli TLS variantını əhatə edir. Əgər releniz ikisindən birini sənədləşdirirsə, həmin sənədlər əvvəlki iş yerinizdən gələn hər hansı üstünlükdən üstündür.
587 portunda STARTTLS sizə nə verir
Yüksəltmə SMTP söhbətinin içində baş verir, ona görə rele onu elan edə bilər və müştəri onsuz davam etməkdən imtina edə bilər. Python-da starttls() server uzantını təklif etmədikdə istisna atır, bu da aşağı salma cəhdini səssiz açıq mətn girişi əvəzinə görünən uğursuzluğa çevirir. Bu davranış rejimin əsas arqumentidir və ona təsadüfən deyil, qəsdən güvənməyə dəyər.
Məruz qalma pəncərəsi kiçik, lakin realdır: ilkin EHLO mübadiləsi oxuna biləndir və yüksəltmədən əvvəl heç nə etimad məlumatı daşımır. Tətbiq alt şəbəkəsi ilə daxili rele arasındakı şəxsi yolda bu pəncərə adətən məqbuldur. Nəzarət etmədiyiniz yolda isə bu, bəzi komandaların digər rejimdə təkid etməsinin səbəbidir.
STARTTLS imkanını silən müdaxilə qurğusu geri çəkilmə deyil, uğursuz göndərmə yaradır. Bu, istədiyiniz nəticədir və yolda nəyinsə SMTP-ni yenidən yazdığını aşkar etməyin ən sürətli yoludur.
465 portunda gizli TLS nəyi dəyişir
Ümumiyyətlə açıq mətn mərhələsi yoxdur. Müştəri soket açılan kimi TLS əl sıxışması aparır, sertifikatı öz etimad anbarına qarşı yoxlayır və yalnız bundan sonra EHLO, AUTH və mesajı mübadilə edir. Sessiyanı heç nə aşağı sala bilməz, çünki danışıq üçün açıq mətn vəziyyəti yoxdur və bu, bütöv bir müdaxilə uğursuzluğu sinfini aradan qaldırır.
Güzəşt diaqnostika qabiliyyətidir. 465-də açıq mətnli SMTP ilə cavab verən rele və ya TLS-i səhv sertifikat adı ilə sonlandıran yük balanslaşdırıcısı əl sıxışmasında uğursuz olur və sizə poçt xətası yerinə SSL xətası verir. Bu baş verəndə problem tətbiqin altındadır və heç bir mesaj qurma səyi onu düzəltməyəcək.
Bir göndərmə funksiyası, iki nəqliyyat
Kod rejimlər arasında demək olar ki, fərqlənmir, buna görə seçim kitabxana rahatlığından deyil, rele siyasətindən edilməlidir. Əvvəlcə parametrləri ixrac edin, sonra nəqliyyatı konfiqurasiya edilmiş portdan seçən tək skript işlədin.
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() zənciri və host adını yoxlayır, buna görə şəxsi CA etimad anbarına quraşdırılmalıdır, yoxlanılmamış kontekstlə yan keçilməməlidir. send_message() relenin rədd etdiyi alıcıların lüğətini qaytarır; boş lüğət onların hamısını qəbul etdiyini bildirir. On beş saniyəlik timeout başlanğıc nöqtəsidir, şəbəkəniz üçün tənzimlənmiş dəyər deyil.
Parolu obrazdan və jurnallardan kənarda saxlayın. İşləmə vaxtı quraşdırılan və mühitə oxunan sirr yaxşıdır; mühiti jurnal sətrinə əks etdirmək deyil, AUTH mübadiləsinin sazlama izi də deyil.
Vərdişə görə deyil, rele siyasətinə və yola görə seçin
Üç şərt bunu həll edir. Birincisi, relenin əslində nə elan etdiyi: yalnız 587-də STARTTLS ilə dinləyən xidmətə 465-də çatmaq mümkün deyil, nə qədər gizli TLS üstünlük versəniz də. İkincisi, tətbiqlə rele arasındakı yolun oxuna bilən EHLO mübadiləsini qəbul etmək üçün kifayət qədər etibarlı olub-olmadığı. Üçüncüsü, ortada nəyinsə SMTP-ni yenidən yazıb-yazmadığı və ya proksiləşdirdiyi, çünki bu, aşağı salma riskinin nəzəri və ya real olduğunu müəyyən edir.
Rele hər ikisini təklif edəndə nəzarətsiz işləyən xidmət üçün 465-i, ilk yerləşdirməyə insan baxdığı xidmət üçün 587-ni seçirəm, sadəcə xəta mesajları fərqli qatları göstərdiyi üçün. Bu üstünlük mənimdir və bu siyasət deyil.
Nə seçsəniz də, portu, etimad materialını və göndərən domenini yerləşdirmə ilə birlikdə qeyd edin. Sonra bir icazəli sınaq mesajı göndərin və relenin onu qəbul etdiyini təsdiqləyin; göndərmə nəticəsini və sonrakı çatdırılma hesabatını ayrı qeydlər kimi saxlayın. Relenə uğurlu təhvil tətbiqin məsuliyyətinin sonudur, mesajın gələnlər qutusuna çatdığının sübutu deyil.