Python SMTP रिले सबमिशन: 587 पर STARTTLS या 465 पर TLS?
587 पर STARTTLS और 465 पर अंतर्निहित TLS दोनों Python सबमिशन ले जाते हैं, लेकिन आपके रिले से केवल एक ही मेल खाता है। हैंडशेक और विफलता के तरीकों की तुलना करें।
दोनों कनेक्शन मोड वही संदेश उसी रिले खाते तक पहुँचाते हैं, और अंतर यह है कि TLS कहाँ शुरू होता है, यह नहीं कि क्या भेजा जाता है। एक स्पष्ट टेक्स्ट में खुलता है और बैंड के भीतर ही अपग्रेड होता है; दूसरा पहले बाइट से ही एन्क्रिप्टेड रहता है। यही एक अंतर तय करता है कि कठोर रिले नीति क्या स्वीकार करेगी, कोई मध्यवर्ती उपकरण क्या देख सकता है, और कौन-सा त्रुटि संदेश आप पूरी दोपहर पढ़ेंगे। निजी नेटवर्क पर कोई एप्लिकेशन जब आंतरिक सबमिशन सेवा को संदेश सौंपता है, तब मैं इन दोनों में से कैसे चुनता हूँ, यह रहा।
दोनों मोड वास्तव में कहाँ अलग होते हैं
दोनों स्थितियों में कार्य एक ही है: स्वीकृत खाते के रूप में प्रमाणित हों, अनुमत प्रेषक का नाम दें, प्राप्तकर्ताओं की सूची बनाएँ, और प्रतीक्षा करें कि रिले ज़िम्मेदारी स्वीकार करे। जो बदलता है वह है संचालनों का क्रम। पोर्ट 587 स्पष्ट-टेक्स्ट SMTP सत्र के रूप में शुरू होता है, EHLO उत्तर में STARTTLS की घोषणा करता है, और केवल तभी अपग्रेड होता है जब क्लाइंट माँगे। पोर्ट 465 कोई भी SMTP आदेश बोले जाने से पहले TLS हैंडशेक की अपेक्षा करता है।
सबमिशन और रिले अलग काम हैं, इसीलिए पोर्ट संख्याएँ अदल-बदल करने योग्य आदतें नहीं हैं। RFC 6409 संदेश सबमिशन को अपनी अलग सेवा के रूप में वर्णित करता है, और RFC 8314 उस अंतर्निहित-TLS प्रकार को समेटता है जिसे अधिकांश आधुनिक रिले 465 पर प्रस्तुत करते हैं। यदि आपका रिले दोनों में से एक का दस्तावेज़ीकरण करता है, तो वह दस्तावेज़ पिछले नियोक्ता से मिली किसी भी पसंद से ऊपर है।
587 पर STARTTLS आपको क्या देता है
अपग्रेड SMTP बातचीत के भीतर होता है, इसलिए रिले इसकी घोषणा कर सकता है और क्लाइंट इसके बिना आगे बढ़ने से मना कर सकता है। Python में, starttls() अपवाद उठाता है जब सर्वर वह एक्सटेंशन प्रस्तुत नहीं करता, जो डाउनग्रेड के प्रयास को मौन स्पष्ट-टेक्स्ट लॉगिन के बजाय दृश्य विफलता में बदल देता है। वही व्यवहार इस मोड का मुख्य तर्क है, और उस पर संयोग से नहीं, जानबूझकर भरोसा करना उचित है।
जोखिम की खिड़की छोटी पर वास्तविक है: शुरुआती EHLO विनिमय पठनीय है, और अपग्रेड से पहले कुछ भी क्रेडेंशियल नहीं ले जाता। एप्लिकेशन सबनेट और आंतरिक रिले के बीच निजी मार्ग पर वह खिड़की आमतौर पर स्वीकार्य है। जिस मार्ग को आप नियंत्रित नहीं करते, वहाँ यही कारण है कि कुछ टीमें दूसरे मोड पर ज़ोर देती हैं।
STARTTLS क्षमता हटाने वाला इंटरसेप्शन उपकरण विफल सबमिशन उत्पन्न करता है, फ़ॉलबैक नहीं। यही वह परिणाम है जो आप चाहते हैं, और यह पता लगाने का सबसे तेज़ तरीका भी है कि मार्ग पर कुछ SMTP को फिर से लिख रहा है।
465 पर अंतर्निहित TLS क्या बदलता है
स्पष्ट टेक्स्ट का कोई चरण ही नहीं है। सॉकेट खुलते ही क्लाइंट 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 जहाँ कोई व्यक्ति पहली तैनाती देख रहा हो, केवल इसलिए कि विफलता संदेश अलग-अलग परतों की ओर इंगित करते हैं। वह पसंद मेरी है और वह नीति नहीं है।
आप जो भी चुनें, पोर्ट, ट्रस्ट सामग्री और प्रेषक डोमेन को तैनाती के साथ दर्ज करें। फिर एक अधिकृत परीक्षण संदेश भेजें और पुष्टि करें कि रिले ने उसे स्वीकार किया, सबमिशन परिणाम और किसी भी बाद की डिलीवरी रिपोर्ट को अलग रिकॉर्ड के रूप में रखते हुए। रिले को सफल हस्तांतरण एप्लिकेशन की ज़िम्मेदारी का अंत है, संदेश के इनबॉक्स तक पहुँचने का प्रमाण नहीं।