Albei verbindingsmodusse dra dieselfde boodskap na dieselfde relaisrekening, en die verskil is waar TLS begin, nie wat gestuur word nie. Die een open in helder teks en gradeer in die band op; die ander is van die eerste greep geënkripteer. Daardie enkele verskil bepaal wat 'n streng relaisbeleid sal aanvaar, wat 'n middelbox kan waarneem, en watter foutboodskap jy 'n middag lank sal lees. Hier is hoe ek tussen hulle kies wanneer 'n toepassing op 'n private netwerk 'n boodskap aan 'n interne indieningsdiens oorhandig.

Waar die twee modusse werklik verskil

Die taak is in albei gevalle dieselfde: verifieer as 'n goedgekeurde rekening, noem 'n toegelate afsender, lys ontvangers en wag tot die relais verantwoordelikheid aanvaar. Wat verander, is die volgorde van bewerkings. Poort 587 begin as 'n helderteks-SMTP-sessie, adverteer STARTTLS in sy EHLO-antwoord en gradeer slegs op as die kliënt dit vra. Poort 465 verwag 'n TLS-handdruk voordat enige SMTP-opdrag gepraat word.

Indiening en relais is verskillende take, en daarom is die poortnommers nie uitruilbare gewoontes nie. RFC 6409 beskryf boodskapindiening as sy eie diens, en RFC 8314 dek die implisiete-TLS-variant wat die meeste moderne relais op 465 blootlê. As jou relais een van die twee dokumenteer, oorheers daardie dokumentasie enige voorkeur wat jy by 'n vorige werkgewer geleer het.

Wat STARTTLS op 587 jou gee

Die opgradering gebeur binne die SMTP-gesprek, so die relais kan dit adverteer en die kliënt kan weier om sonder dit voort te gaan. In Python gooi starttls() 'n uitsondering wanneer die bediener nie die uitbreiding bied nie, wat 'n poging tot afgradering in 'n sigbare fout omskep eerder as 'n stil helderteks-aanmelding. Daardie gedrag is die hoofargument vir die modus, en dit is die moeite werd om doelbewus daarop te staatmaak eerder as per ongeluk.

Die blootstellingsvenster is klein maar werklik: die aanvanklike EHLO-uitruiling is leesbaar, en niks voor die opgradering dra geloofsbriewe nie. Op 'n private pad tussen 'n toepassingsubnet en 'n interne relais is daardie venster gewoonlik aanvaarbaar. Op 'n pad wat jy nie beheer nie, is dit die rede waarom sommige spanne op die ander modus aandring.

'n Onderskeppingsapparaat wat die STARTTLS-vermoë stroop, lewer 'n mislukte indiening, nie 'n terugval nie. Dit is die uitkoms wat jy wil hê, en dit is ook die vinnigste manier om te ontdek dat iets SMTP op die pad herskryf.

Wat implisiete TLS op 465 verander

Daar is glad geen helderteksfase nie. Die kliënt voer 'n TLS-handdruk uit sodra die sokket oopgaan, valideer die sertifikaat teen sy vertrouensbewaarplek, en ruil eers daarna EHLO, AUTH en die boodskap uit. Niks kan die sessie afgradeer nie, want daar is geen helderteks-toestand om van te onderhandel nie, wat 'n hele klas onderskeppingsfoute verwyder.

Die ruil is diagnoseerbaarheid. 'n Relais wat op 465 met helderteks-SMTP antwoord, of 'n lasbalanseerder wat TLS met die verkeerde sertifikaatnaam beëindig, misluk by die handdruk en gee jou 'n SSL-fout eerder as 'n posfout. Wanneer dit gebeur, is die probleem onder die toepassing, en geen hoeveelheid boodskapkonstruksie sal dit regstel nie.

Een indieningsfunksie, twee vervoermiddels

Die kode verskil skaars tussen die modusse, en daarom moet die keuse uit relaisbeleid gemaak word eerder as uit biblioteekgerief. Eksporteer eers die instellings, en hardloop dan 'n enkele script wat die vervoer uit die gekonfigureerde poort kies.

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() verifieer die ketting en die gasheernaam, so 'n private CA moet in die vertrouensbewaarplek geïnstalleer word eerder as om dit met 'n ongeverifieerde konteks te omseil. send_message() gee 'n woordeboek terug van ontvangers wat die relais van die hand gewys het; 'n leë woordeboek beteken dit het almal aanvaar. Die vyftien-sekonde-tydsverloop is 'n beginpunt, nie 'n ingestelde waarde vir jou netwerk nie.

Hou die wagwoord uit die beeld en uit die logs. 'n Geheim wat tydens looptyd gemonteer en in die omgewing ingelees word, is goed; om die omgewing in 'n logreël te eggo is nie, en 'n debug-spoor van die AUTH-uitruiling ook nie.

Kies volgens relaisbeleid en pad, nie volgens gewoonte nie

Drie voorwaardes beslis dit. Eerste, wat die relais werklik adverteer: 'n diens wat net op 587 met STARTTLS luister, kan nie op 465 bereik word nie, maak nie saak hoe graag jy implisiete TLS verkies nie. Tweede, of die pad tussen die toepassing en die relais vertrou genoeg is om 'n leesbare EHLO-uitruiling te aanvaar. Derde, of iets in die middel SMTP herskryf of volmagtig, want dit bepaal of die afgraderingsrisiko teoreties of werklik is.

Wanneer die relais albei bied, neem ek 465 vir 'n diens wat onbewaak loop en 587 vir een waar 'n mens na die eerste ontplooiing kyk, bloot omdat die foutboodskappe na verskillende lae wys. Daardie voorkeur is myne en dit is nie 'n beleid nie.

Wat jy ook kies, teken die poort, die vertrouensmateriaal en die afsenderdomein saam met die ontplooiing aan. Stuur dan een gemagtigde toetsboodskap en bevestig dat die relais dit aanvaar het, terwyl jy die indieningsresultaat en enige latere afleweringsverslag as afsonderlike rekords hou. 'n Suksesvolle oorhandiging aan die relais is die einde van die toepassing se verantwoordelikheid, nie bewys dat die boodskap 'n inkassie bereik het nie.

Verwante artikels