Abu ryšio režimai perduoda tą patį pranešimą į tą pačią relay paskyrą, o skirtumas yra tai, kur prasideda TLS, o ne tai, kas siunčiama. Vienas atsidaro atviru tekstu ir pakeliamas kanalo viduje; kitas šifruojamas nuo pirmojo baito. Šis vienintelis skirtumas nulemia, ką priims griežta relay politika, ką gali pastebėti tarpinis įrenginys ir kurią klaidos žinutę praleisite visą popietę skaitydami. Štai kaip renkuosi tarp jų, kai programėlė privačiame tinkle perduoda pranešimą vidinei siuntimo tarnybai.

Kur du režimai iš tikrųjų išsiskiria

Užduotis abiem atvejais ta pati: autentifikuotis kaip patvirtinta paskyra, nurodyti leistiną siuntėją, išvardyti gavėjus ir laukti, kol relay prisiims atsakomybę. Keičiasi operacijų tvarka. 587 prievadas pradedamas kaip atviro teksto SMTP sesija, EHLO atsakyme skelbia STARTTLS ir pakeliamas tik jei klientas to paprašo. 465 prievadas tikisi TLS rankos paspaudimo prieš ištariant bet kokią SMTP komandą.

Siuntimas ir relay yra skirtingi darbai, todėl prievadų numeriai nėra keičiami įpročiai. RFC 6409 aprašo pranešimų siuntimą kaip atskirą tarnybą, o RFC 8314 apima implicitinio TLS variantą, kurį dauguma šiuolaikinių relay teikia 465 prievade. Jei jūsų relay dokumentuoja vieną iš dviejų, ta dokumentacija viršija bet kokį pasirinkimą, įgytą pas ankstesnį darbdavį.

Ką STARTTLS 587 prievade jums duoda

Pakėlimas vyksta SMTP pokalbio viduje, todėl relay gali jį paskelbti, o klientas gali atsisakyti tęsti be jo. Python programoje starttls() išmeta išimtį, kai serveris nesiūlo šio plėtinio, ir tai pavertimo sumažinimą matomu gedimu, o ne tylia prisijungimu atviru tekstu. Ši elgsena yra pagrindinis šio režimo argumentas, ir ja verta pasikliauti sąmoningai, o ne atsitiktinai.

Poveikio langas mažas, bet realus: pradinis EHLO apsikeitimas yra skaitomas, ir niekas prieš pakėlimą neneša prisijungimo duomenų. Privačiame kelyje tarp programėlės potinklio ir vidinio relay šis langas paprastai priimtinas. Kelyje, kurio nekontroliuojate, būtent tai yra priežastis, kodėl kai kurios komandos reikalauja kito režimo.

Pasiklausymo įrenginys, pašalinantis STARTTLS galimybę, sukelia nepavykusį siuntimą, o ne atsarginį variantą. Tai yra norimas rezultatas, ir tai taip pat greičiausias būdas sužinoti, kad kažkas kelyje perrašo SMTP.

Ką keičia implicitinis TLS 465 prievade

Atviro teksto fazės visai nėra. Klientas atlieka TLS rankos paspaudimą vos atsidarius lizdui, patikrina sertifikatą savo patikimumo saugykloje ir tik tada apsikeičia EHLO, AUTH ir pranešimu. Niekas negali sumažinti sesijos, nes nėra atviro teksto būsenos, iš kurios būtų galima derėtis, ir tai pašalina visą pasiklausymo gedimų klasę.

Mainais gaunama diagnostika. Relay, kuris 465 prievade atsako atviru SMTP, arba apkrovos balansuotojas, kuris užbaigia TLS su neteisingu sertifikato vardu, nepavyksta per rankos paspaudimą ir duoda jums SSL klaidą vietoj pašto klaidos. Kai taip nutinka, problema yra žemiau programėlės, ir joks pranešimo kūrimas to neištaisys.

Viena siuntimo funkcija, du transportai

Kodas tarp režimų beveik nesiskiria, todėl pasirinkimas turėtų būti daromas pagal relay politiką, o ne pagal bibliotekos patogumą. Pirmiausia eksportuokite nustatymus, tada paleiskite vieną scenarijų, kuris parenka transportą pagal sukonfigūruotą prievadą.

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() tikrina grandinę ir pagrindinio kompiuterio vardą, todėl privatus CA turi būti įdiegtas patikimumo saugykloje, o ne apeinamas nepatikrintu kontekstu. send_message() grąžina žodyną gavėjų, kurių relay atsisakė; tuščias žodynas reiškia, kad jis priėmė visus. Penkiolikos sekundžių laiko limitas yra pradinis taškas, o ne jūsų tinklui suderinta reikšmė.

Laikykite slaptažodį už vaizdo ir už žurnalų. Paslaptis, įtvirtinta vykdymo metu ir perskaityta aplinkoje, yra gerai; aplinkos atspindėjimas žurnalo eilutėje nėra gerai, kaip ir AUTH apsikeitimo derinimo pėdsakas.

Rinkitės pagal relay politiką ir kelią, o ne pagal įprotį

Trys sąlygos tai nulemia. Pirma, ką relay iš tikrųjų skelbia: tarnyba, kuri klausosi tik 587 prievade su STARTTLS, nepasiekiama 465 prievade, kad ir kaip norėtumėte implicitinio TLS. Antra, ar kelias tarp programėlės ir relay pakankamai patikimas, kad priimtų skaitomą EHLO apsikeitimą. Trečia, ar kas nors viduryje perrašo arba proxizuoja SMTP, nes tai nulemia, ar sumažinimo rizika teorinė, ar reali.

Kai relay siūlo abu, imu 465 prievadą tarnybai, kuri veikia be priežiūros, ir 587 tarnybai, kurioje žmogus stebi pirmąjį diegimą, vien todėl, kad gedimų žinutės nurodo skirtingus sluoksnius. Tas pasirinkimas yra mano ir tai ne politika.

Kad ir ką pasirinktumėte, užrašykite prievadą, patikimumo medžiagą ir siuntėjo domeną kartu su diegimu. Tada nusiųskite vieną įgaliotą bandomąjį pranešimą ir patvirtinkite, kad relay jį priėmė, siuntimo rezultatą ir bet kurią vėlesnę pristatymo ataskaitą laikydami atskirais įrašais. Sėkmingas perdavimas relay yra programėlės atsakomybės pabaiga, o ne įrodymas, kad pranešimas pasiekė gautųjų dėžutę.

Susiję straipsniai