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 جہاں کوئی شخص پہلی تعیناتی دیکھ رہا ہو، صرف اس لیے کہ ناکامی کے پیغام مختلف تہوں کی طرف اشارہ کرتے ہیں۔ وہ ترجیح میری ہے اور وہ پالیسی نہیں۔
آپ جو بھی منتخب کریں، پورٹ، اعتماد کا مواد اور بھیجنے والے کا ڈومین تعیناتی کے ساتھ درج کریں۔ پھر ایک مجاز آزمائشی پیغام بھیجیں اور تصدیق کریں کہ ریلے نے اسے قبول کیا، جمع کرانے کا نتیجہ اور بعد کی کوئی بھی ترسیل رپورٹ الگ ریکارڈ کے طور پر رکھیں۔ ریلے کو کامیاب حوالگی ایپلیکیشن کی ذمہ داری کا اختتام ہے، پیغام کے اِن باکس تک پہنچنے کا ثبوت نہیں۔