Оба начина повезивања преносе исту поруку на исти налог релеја, а разлика је у томе где почиње TLS, а не у томе шта се шаље. Један се отвара у чистом тексту и надограђује се унутар канала; други је шифрован од првог бајта. Та једна разлика одлучује шта ће строга политика релеја прихватити, шта посредни уређај може приметити и коју поруку о грешци ћете провести поподне читајући. Ево како бирам између њих када апликација на приватној мрежи предаје поруку интерној услузи за слање.

Где се два начина заиста разилазе

Задатак је исти у оба случаја: аутентификовати се као одобрени налог, навести дозвољеног пошиљаоца, навести примаоце и чекати да релеј преузме одговорност. Мења се редослед операција. Порт 587 почиње као SMTP сесија у чистом тексту, објављује STARTTLS у EHLO одговору и надограђује се само ако клијент затражи. Порт 465 очекује TLS руковање пре него што се изговори иједна SMTP наредба.

Слање и релеј су различити послови, зато бројеви портова нису заменљиве навике. RFC 6409 описује слање порука као сопствену услугу, а RFC 8314 покрива варијанту имплицитног TLS-а коју већина модерних релеја излаже на 465. Ако ваш релеј документује један од два, та документација надјачава сваку преференцију стечену код претходног послодавца.

Шта вам STARTTLS на 587 даје

Надоградња се дешава унутар SMTP разговора, па релеј може да је објави, а клијент може одбити да настави без ње. У Python-у starttls() подиже изузетак када сервер не нуди то проширење, што покушај деградације претвара у видљив неуспех уместо тихог пријављивања у чистом тексту. То понашање је главни аргумент за овај начин и вреди се на њега намерно ослонити, а не случајно.

Прозор изложености је мали али стваран: почетна EHLO размена је читљива и ништа пре надоградње не носи акредитиве. На приватном путу између подмреже апликације и интерног релеја тај прозор је обично прихватљив. На путу који не контролишете, управо је то разлог зашто неки тимови инсистирају на другом начину.

Уређај за пресретање који уклања могућност STARTTLS производи неуспело слање, а не повратак на старо. То је исход који желите, а уједно и најбржи начин да откријете да нешто преписује SMTP на путу.

Шта имплицитни TLS на 465 мења

Фазе чистог текста уопште нема. Клијент изводи TLS руковање чим се сокет отвори, проверава сертификат према свом складишту поверења и тек онда размењује EHLO, AUTH и поруку. Ништа не може да деградира сесију јер не постоји стање чистог текста из којег би се преговарало, и то уклања целу класу неуспеха пресретања.

Трговина је могућност дијагностике. Релеј који одговара на 465 чистим SMTP-ом, или балансер оптерећења који завршава TLS са погрешним именом сертификата, пада на руковању и даје вам SSL грешку уместо поштанске. Када се то догоди, проблем је испод апликације и никакво састављање поруке га неће поправити.

Једна функција за слање, два транспорта

Код се једва разликује између начина, зато одлуку треба донети на основу политике релеја, а не погодности библиотеке. Прво извезите поставке, а затим покрените једну скрипту која бира транспорт према конфигурисаном порту.

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() проверава ланац и име хоста, па се приватни CA мора инсталирати у складиште поверења, а не заобићи непровереним контекстом. send_message() враћа речник прималаца које је релеј одбио; празан речник значи да је прихватио све. Петнаестосекундни тајмаут је почетна тачка, а не подешена вредност за вашу мрежу.

Држите лозинку изван слике и изван записа. Тајна монтирана у време извршавања и прочитана у окружење је у реду; пресликавање окружења у линију записа није, као ни debug траг AUTH размене.

Бирајте према политици релеја и путу, а не према навици

Три услова одлучују. Прво, шта релеј заиста објављује: услуга која слуша само на 587 са STARTTLS не може се достићи на 465, колико год преферирали имплицитни TLS. Друго, да ли је пут између апликације и релеја довољно поуздан да прихвати читљиву EHLO размену. Треће, да ли нешто у средини преписује или проксира SMTP, јер то одлучује да ли је ризик деградације теоријски или стваран.

Када релеј нуди оба, узимам 465 за услугу која ради без надзора и 587 за ону где човек гледа прво постављање, само зато што поруке о неуспеху указују на различите слојеве. Та преференција је моја и није политика.

Шта год да изаберете, забележите порт, материјал поверења и домен пошиљаоца уз постављање. Затим пошаљите једну овлашћену тестну поруку и потврдите да ју је релеј прихватио, чувајући резултат слања и сваки каснији извештај о достави као одвојене записе. Успешно предавање релеју је крај одговорности апликације, а не доказ да је порука стигла у пријемно сандуче.

Повезани чланци