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