Python SMTP-beküldés: STARTTLS az 587-es vagy TLS a 465-ös porton?
Az 587-es STARTTLS és a 465-ös implicit TLS egyaránt továbbítja a Python-beküldést, de csak az egyik illik a relayéhez. Hasonlítsa össze a kézfogást és a hibaformákat.
Mindkét kapcsolódási mód ugyanazt az üzenetet viszi ugyanarra a relay-fiókra, és a különbség abban van, hol kezdődik a TLS, nem abban, mit küldünk. Az egyik nyílt szövegben nyílik és a kapcsolaton belül frissül; a másik az első bájttól titkosított. Ez az egyetlen különbség dönti el, mit fogad el egy szigorú relay-szabályzat, mit figyelhet meg egy köztes eszköz, és melyik hibaüzenetet fogja egy délután olvasni. Így választok közöttük, amikor egy privát hálózaton futó alkalmazás üzenetet ad át egy belső beküldő szolgáltatásnak.
Ahol a két mód valóban elválik
A feladat mindkét esetben ugyanaz: hitelesítés jóváhagyott fiókként, engedélyezett feladó megnevezése, a címzettek felsorolása és annak kivárása, hogy a relay átvállalja a felelősséget. Ami változik, az a műveletek sorrendje. Az 587-es port nyílt szövegű SMTP-munkamenetként indul, az EHLO-válaszban hirdeti a STARTTLS-t, és csak akkor frissül, ha az ügyfél kéri. A 465-ös port TLS-kézfogást vár, mielőtt bármilyen SMTP-parancs elhangzana.
A beküldés és a továbbítás külön feladatok, ezért a portszámok nem felcserélhető szokások. A RFC 6409 az üzenetbeküldést önálló szolgáltatásként írja le, az RFC 8314 pedig az implicit TLS változatát fedi le, amelyet a legtöbb modern relay a 465-ös porton kínál. Ha a relayje a kettő közül az egyiket dokumentálja, az a dokumentáció minden olyan preferencia fölé kerül, amelyet egy korábbi munkahelyén szerzett.
Mit ad Önnek a STARTTLS az 587-es porton
A frissítés az SMTP-beszélgetésen belül történik, így a relay hirdetheti, az ügyfél pedig megtagadhatja a folytatást nélküle. Pythonban a starttls() kivételt dob, ha a kiszolgáló nem kínálja a kiterjesztést, ami a visszasorolási kísérletet látható hibává teszi a csendes nyílt szövegű bejelentkezés helyett. Ez a viselkedés a mód fő érve, és érdemes szándékosan, nem véletlenül támaszkodni rá.
A kitettségi ablak kicsi, de valós: a kezdeti EHLO-csere olvasható, és semmi nem hordoz hitelesítő adatokat a frissítés előtt. Egy privát útvonalon az alkalmazás alhálózata és egy belső relay között ez az ablak általában elfogadható. Egy olyan útvonalon, amelyet nem ellenőriz, ez az oka annak, hogy egyes csapatok a másik módot követelik.
Az a lehallgató eszköz, amely eltávolítja a STARTTLS képességét, sikertelen beküldést eredményez, nem visszaesést. Ez a kívánt eredmény, és ez a leggyorsabb módja annak felfedezésére, hogy valami átírja az SMTP-t az útvonalon.
Mit változtat az implicit TLS a 465-ös porton
Egyáltalán nincs nyílt szövegű szakasz. Az ügyfél TLS-kézfogást végez, amint a socket megnyílik, ellenőrzi a tanúsítványt a saját megbízhatósági tárolója ellen, és csak ezután cseréli ki az EHLO-t, az AUTH-ot és az üzenetet. Semmi nem tudja visszasorolni a munkamenetet, mert nincs nyílt szövegű állapot, amelyből tárgyalni lehetne, és ez a lehallgatási hibák egész osztályát szünteti meg.
A csere a diagnosztizálhatóság. Egy relay, amely a 465-ös porton nyílt szövegű SMTP-vel válaszol, vagy egy terheléselosztó, amely rossz tanúsítványnévvel fejezi be a TLS-t, a kézfogásnál meghibásodik, és SSL-hibát ad a levélhiba helyett. Amikor ez megtörténik, a probléma az alkalmazás alatt van, és az üzenet felépítése semmilyen mértékben nem javítja meg.
Egy beküldő függvény, két szállítási mód
A kód alig tér el a módok között, ezért a választást a relay szabályzata, nem a könyvtár kényelme alapján kell meghozni. Először exportálja a beállításokat, majd futtasson egyetlen szkriptet, amely a beállított port alapján választja ki a szállítási módot.
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)
A create_default_context() ellenőrzi a láncot és a gazdagépnevet, ezért a privát CA-t a megbízhatósági tárolóba kell telepíteni, nem pedig ellenőrizetlen környezettel megkerülni. A send_message() szótárt ad vissza azokról a címzettekről, akiket a relay elutasított; az üres szótár azt jelenti, hogy mindegyiket elfogadta. A tizenöt másodperces időtúllépés kiindulópont, nem a hálózatára hangolt érték.
Tartsa a jelszót a rendszerképzől és a naplókon kívül. A futásidőben csatolt és a környezetbe beolvasott titok rendben van; a környezet naplósorba írása nem az, és az AUTH-csere hibakeresési nyoma sem.
A relay szabályzata és az útvonal szerint válasszon, ne szokás szerint
Három feltétel dönti el. Először, mit hirdet a relay valójában: egy szolgáltatás, amely csak az 587-es porton figyel STARTTLS-szel, a 465-ös porton nem érhető el, bármennyire is kedveli az implicit TLS-t. Másodszor, hogy az alkalmazás és a relay közötti útvonal elég megbízható-e egy olvasható EHLO-csere elfogadásához. Harmadszor, hogy valami a kettő között átírja-e vagy proxizálja-e az SMTP-t, mert ez dönti el, hogy a visszasorolási kockázat elméleti-e vagy valós.
Amikor a relay mindkettőt kínálja, a 465-öst választom a felügyelet nélkül futó szolgáltatáshoz, az 587-est pedig ahhoz, ahol egy ember figyeli az első telepítést, kizárólag azért, mert a hibaüzenetek különböző rétegekre mutatnak. Ez a preferencia az enyém, és nem szabályzat.
Bármit is választ, rögzítse a portot, a megbízhatósági anyagot és a feladó tartományát a telepítés mellett. Ezután küldjön egy engedélyezett tesztüzenetet, és erősítse meg, hogy a relay elfogadta, a beküldési eredményt és minden későbbi kézbesítési jelentést külön nyilvántartásként kezelve. A relaynek való sikeres átadás az alkalmazás felelősségének vége, nem annak bizonyítéka, hogy az üzenet elérte a postaládát.