שני מצבי החיבור נושאים את אותה הודעה לאותו חשבון ממסר, וההבדל הוא היכן 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() מחזיר מילון של נמענים שהממסר דחה; מילון ריק משמעו שהוא קיבל את כולם. פסק הזמן של חמש עשרה שניות הוא נקודת מוצא, לא ערך מכוונן לרשת שלך.

שמור את הסיסמה מחוץ לתמונה ומחוץ ליומנים. סוד שמעוגן בזמן ריצה ונקרא לסביבה הוא בסדר; הדפסת הסביבה לשורת יומן אינה בסדר, וכך גם עקיבת ניפוי של חילופי ה-AUTH.

בחר לפי מדיניות הממסר והנתיב, לא לפי הרגל

שלושה תנאים מכריעים. ראשית, מה הממסר באמת מכריז: שירות שמאזין רק בפורט 587 עם STARTTLS אינו נגיש בפורט 465, עד כמה שתעדיף TLS מרומז. שנית, האם הנתיב בין היישום לממסר מהימן מספיק כדי לקבל חילופי EHLO קריאים. שלישית, האם משהו באמצע משכתב או מתווך SMTP, כי זה קובע אם סיכון ההורדה בדרגה הוא תאורטי או ממשי.

כשהממסר מציע את שניהם, אני לוקח 465 לשירות שרץ ללא השגחה ו-587 לזה שאדם צופה בפריסה הראשונה, רק מפני שהודעות הכשל מצביעות על שכבות שונות. ההעדפה הזו שלי והיא אינה מדיניות.

מה שתבחר, רשום את הפורט, חומר האמון ותחום השולח לצד הפריסה. לאחר מכן שלח הודעת בדיקה מורשית אחת ואמת שהממסר קיבל אותה, תוך שמירת תוצאת השליחה וכל דוח מסירה מאוחר יותר כרשומות נפרדות. מסירה מוצלחת לממסר היא סוף האחריות של היישום, לא הוכחה שההודעה הגיעה לתיבת דואר.

מאמרים קשורים