دليل · smtp python

كيف ينفّذ فريق المنتج SMTP باستخدام Python بأمان؟

نفّذ SMTP في Python من عامل خلفي مصرّح به، لا مباشرةً من طلب ويب. ابنِ الرسالة بـ EmailMessage، واستخدم SMTP_SSL لـ TLS الضمني أو رقِّ الاتصال صراحةً بـ STARTTLS عندما يتطلب عقد المزوّد الحالي ذلك، وصادِق باستخدام سر على الخادم، واستدعِ send_message بمهلات محدودة. خزّن المهمة قبل الاتصال، وسجّل أدلة رفض كل مستلِم، وطابِق حالات قطع الاتصال الملتبسة، وميّز قبول SMTP عن التسليم اللاحق والوصول إلى صندوق الوارد.

فوّض الإرسال وخزّنه قبل SMTP

ابدأ بحدث تطبيق مشروع مثل إيصال أو تنبيه أمني أو تحقق مطلوب أو إشعار حساب. صادق على المستدعي وفوّض المستأجر وفئة الرسالة وهوية From الظاهرة والمستلِم وإصدار القالب. اكتب مهمة صادرة دائمة بمفتاح حدث عمل ثابت قبل فتح أي اتصال SMTP. ينبغي أن يمنع هذا المفتاح عاملين من إنشاء الرسالة المنطقية نفسها بشكل مستقل. يجب ألا تختار مدخلات المتصفح مضيف SMTP أو المنفذ أو اسم المستخدم أو مُرسِل الظرف أو مستلِمين تعسفيين أو ترويسات أو سياسة TLS. أبقِ هذه القيم في إعدادات خادم خضعت للمراجعة. ينبغي لعامل الطابور أن يستحوذ على مهمة واحدة، ويعيد فحص المنع والتفويض وقت الإرسال، ويسجل كل محاولة، ويحرر المهمة أو ينهيها عبر حالات صريحة. تنقل مكتبة SMTP في Python الرسالة المُعدّة؛ لكنها لا توفر تفويض المستأجر ولا الموافقة ولا عدم التكرار (idempotency) ولا سياسة المنع.

ابنِ الرسالة باستخدام EmailMessage

استخدم email.message.EmailMessage بدلًا من ربط الترويسات والمتون الخام. اضبط From وTo وSubject وDate وMessage-ID مولَّدًا وفق نموذج التطبيق المعتمد، ثم استخدم set_content للنص وadd_alternative لـ HTML عند الحاجة. تحقق من كائنات العناوين، وحدّ عدد المستلِمين والمرفقات، وارفض حقن الأسطر الجديدة في القيم، وهرِّب (escape) بيانات القالب بحسب سياق الإخراج. ولّد النص وHTML من إصدار قالب واحد غير قابل للتغيير. أبقِ الأسرار والبيانات الشخصية غير الضرورية خارج الموضوعات والترويسات المخصصة وأسماء الملفات وحقول التشخيص والسجلات. افصل ترويسة From الظاهرة عن مُرسِل ظرف SMTP عن قصد لأن المصادقة ومعالجة الارتداد قد تعتمدان على هويات مختلفة. خزّن إصدار المحتوى أو تجزئة آمنة للخصوصية للتدقيق بدلًا من الاحتفاظ بمتون الرسائل الكاملة دون حاجة محددة.

اختر TLS الضمني أو STARTTLS صراحةً

يوثّق Python الصنف SMTP_SSL للاتصالات المشفّرة منذ البداية والدالة SMTP.starttls لترقية اتصال قائم. اتبع اسم المضيف والمنفذ والشهادة وعقد الإرسال الحالي لدى المزوّد بدلًا من التخمين من قائمة منافذ عامة. أنشئ سياق SSL افتراضيًا موثَّقًا ولا تعطّل فحوص الشهادة أو اسم المضيف. بالنسبة إلى STARTTLS، اتصل وأصدر EHLO عند الحاجة واستدعِ starttls مع السياق ثم أصدر EHLO مرة أخرى لأن الإضافات المعلَنة قد تتغير بعد الترقية. لا ترسل أبدًا بيانات الاعتماد أو محتوى رسائل العملاء عبر اتصال بنص عادي. يوصي RFC 8314 بالإرسال المحمي بـ TLS ويعدّ الوصول بالنص العادي متقادمًا. تعامل مع فشل الشهادة أو عدم تطابق اسم المضيف أو غياب STARTTLS المطلوب أو تغيّر القدرات غير المتوقع على أنها إخفاقات حادة تتطلب تحقيقًا بدلًا من الرجوع الصامت.

أبقِ بيانات اعتماد SMTP ضمن حدود أسرار ضيقة

حمّل اسم المستخدم وكلمة المرور أو الرمز المميّز (token) من خدمة أسرار مُدارة على جهة الخادم وقت التشغيل. لا تضع بيانات الاعتماد في الشيفرة المصدرية أو حزم العميل أو تفريغات البيئة أو عناوين URL أو تتبعات الاستثناءات أو التحليلات أو دفاتر الملاحظات أو لقطات الشاشة أو المطالبات (prompts) أو الملفات التجريبية المودعة. حدّد نطاق كل بيانات اعتماد بأصغر بيئة وعبء عمل يدعمهما المزوّد، وافصل التطوير عن الإنتاج. صادق فقط بعد ترسيخ حالة TLS المطلوبة. تمرّن على التدوير بمستلِمين خاضعين للتحكم: وفّر البديل عبر الإدارة المعتمدة، وحدّث العامل، وتأكد من المصادقة ودورة حياة الأحداث كاملة، ثم ألغِ القيمة القديمة. ينبغي أن يوقف تكرار فشل المصادقة المسار المتأثر بدلًا من أن يطلق حلقة إعادة محاولة سريعة. تتفاوض دالة login في Python بين الآليات التي يعلنها الخادم، لكن آلية المزوّد الفعلية وسياسة الحساب وأذونات الرمز المميّز وسلوك التدوير تتطلب أدلة حديثة.

استخدم دالة إرسال محدودة في Python

أبقِ محوّل المزوّد صغيرًا وأعد أدلة منظَّمة إلى آلة حالات المهمة. يُنشئ التدفق المعتاد سياق SSL ويفتح SMTP_SSL(host, port, timeout=10) باسم smtp لـ TLS الضمني، ثم يستدعي smtp.login(username, secret)، ثم يستدعي smtp.send_message(message, from_addr=envelope_from, to_addrs=recipients). أما للمزوّد الذي يتطلب ترقية صريحة، فاستخدم SMTP مع مهلة، وehlo، وstarttls(context=context)، وehlo، ثم login. لا تقدّم أسماء المضيفين أو المنافذ الواردة في الأمثلة على أنها قيم افتراضية عامة. مرّر قائمة مستلِمين مطبَّعة بدلًا من الاعتماد على تحليل ترويسات غير موثوقة. سجّل فئة الاستثناء ورمز رد SMTP ونصًا تشخيصيًا محدودًا عند توفره، مع حجب العناوين وبيانات الاعتماد والمحتوى. قِس مراحل الاتصال وTLS والمصادقة والظرف والبيانات والإنهاء (quit) على حدة حتى تبقى الأعطال التشغيلية قابلة للتشخيص.

فسّر نتائج المستلِمين في send_message بدقة

يوثّق Python أن sendmail وsend_message تعودان بشكل طبيعي عند قبول البريد لمستلِم واحد على الأقل وتُعيدان قاموسًا للمستلِمين المرفوضين؛ والقاموس الفارغ يعني أنه لم يُرفض أي مستلِم في تلك المرحلة. احتفظ بهذه النتيجة على مستوى المستلِم بدلًا من وسم المهمة كلها بأنها سُلِّمت. وإذا رُفض كل المستلِمين، تُطلق المكتبة الاستثناء SMTPRecipientsRefused. أما الاستثناءات الأخرى فتميّز رفض المُرسِل ورفض DATA والمصادقة والاتصال والبروتوكول والأخطاء ذات الصلة. اربط الأدلة الدقيقة بحالات التطبيق: مقبولة من خادم الإرسال، أو مرفوضة بشكل دائم، أو مرفوضة مؤقتًا، أو غير معروفة. العودة الطبيعية تثبت فقط نتيجة الإرسال عبر SMTP ضمن نطاقها. ولا تثبت قبول الخادم الوجهة أو الوصول النهائي إلى صندوق البريد أو القراءة أو التفاعل. ويجب ربط إشعارات حالة التسليم اللاحقة أو أحداث المزوّد بشكل منفصل.

أعد المحاولة فقط عندما يكون خطر التكرار مضبوطًا

صنّف الإخفاقات قبل جدولة محاولة أخرى. تحتاج إخفاقات العنوان أو المُرسِل أو المصادقة أو السياسة أو المحتوى الدائمة عمومًا إلى تصحيح أو منع بدلًا من التكرار الآلي. ويمكن إعادة محاولة ردود 4xx المؤقتة بتراجع أُسّي مع jitter وسقف للمحاولات وانتهاء صلاحية وميزانية لكل وجهة. وقد يكون إعادة ضبط الاتصال أو المهلة بعد بيانات الرسالة ملتبسًا: فقد يكون الخادم قبل الرسالة بينما فات العميل ردّه النهائي. أبقِ تلك المحاولة في حالة غير معروفة، وافحص نشاط المزوّد أو الأحداث اللاحقة عبر ربط آمن للخصوصية، وتجنّب إعادة الإرسال العمياء الفورية. لا يوفّر SMTP مفتاح عدم تكرار عامًا للتطبيقات. يمنع مفتاح حدث العمل الدائم محاولات التطبيق المتزامنة لكنه لا يستطيع إجبار خادم SMTP بعيد على إزالة تكرار إرسالين مقبولين. صعّد النتائج الملتبسة المتكررة واحتفظ بالأدلة الدقيقة المستخدمة في القرار.

عالج المستلِمين الجزئيين وقوائم المنع

عالج القبول الجزئي للمستلِمين وقوائم المنع

اختبر مسارات الإخفاق بأنظمة خاضعة للتحكم

اختبر بناء الرسالة وUnicode والبدائل النصية وHTML والمرفقات ورفض الترويسات وتطبيع المستلِمين والتحقق من TLS وغياب STARTTLS وبيانات الاعتماد غير الصالحة ورفض المُرسِل ورفض مستلِم واحد وكل المستلِمين ورفض DATA والمهلات قبل القبول المحتمل وبعده وانقطاع الاتصال وردود المعدّل وانتهاء إعادة المحاولة والعمال المكررين وتغيّرات المنع وتدوير الأسرار. استخدم خدمة SMTP اختبارية خاضعة للتحكم أو محاكيًا محليًا لاختبارات وحدة وتكامل حتمية؛ ولا توجّه أبدًا حركة عرضية من البيئات الدنيا إلى عناوين العملاء. وفي اختبارات الإنتاج الأولية (canaries)، استخدم مستلِمين مصرّحًا بهم وافحص الترويسات الخام لـ From الظاهر ومسار الظرف وMessage-ID وDKIM وSPF ومحاذاة DMARC وأدلة المزوّد. تأكد من أن السجلات والمقاييس لا تحتوي على تسرب لبيانات الاعتماد أو متون الرسائل. أفشل الإطلاق إذا كان العامل يستطيع تجاوز تفويض المستأجر أو خفض TLS أو إعادة المحاولة بلا حدود أو تجاهل الرفض الجزئي أو لا يستطيع إيقاف مسار الإرسال مؤقتًا.

كيف ينسجم SendHQ

SendHQ هو واجهة API للبريد الإلكتروني على مستوى مساحة العمل لاتصال المنتج المتوقع. تغطي وثائقه الإرسال والنطاقات الموثقة وأحداث التسليم وقوائم المنع. استخدم واجهة HTTP API الموثقة عند تكامل SendHQ مع Python.

الأسئلة الشائعة

هل ينبغي أن يستخدم Python الوضع SMTP_SSL أم STARTTLS؟

استخدم الوضع الذي يتطلبه عقد الإرسال الحالي لدى المزوّد. يشفّر SMTP_SSL منذ بدء الاتصال؛ أما STARTTLS فيرقّي الاتصال صراحةً ويتطلب TLS موثَّقًا مع EHLO جديد.

هل تثبت عودة send_message بشكل طبيعي أن الرسالة سُلِّمت؟

لا. إنها تعني أن مستلِمًا واحدًا على الأقل قُبل في مرحلة الإرسال عبر SMTP تلك. أما قبول الوجهة والوصول إلى صندوق الوارد والتفاعل فتحتاج إلى أدلة لاحقة محددة النطاق.

ماذا يعني القاموس الذي تعيده send_message؟

إنه يربط المستلِمين الذين رفضهم خادم SMTP بأدلة الرد. القاموس الفارغ يعني أنه لم يُرفض أحد في تلك المرحلة، لا أن كل رسالة وصلت إلى صندوق الوارد.

هل يمكن إعادة محاولة المهلة فورًا؟

ليس بأمان عندما حدثت بعد إرسال محتمل. احتفظ بالمحاولة بوصفها ملتبسة، وطابِق أدلة المزوّد أو الأحداث اللاحقة، ولا تعِد الإرسال إلا وفق سياسة محدودة لخطر التكرار.

أين ينبغي تخزين كلمة مرور SMTP؟

استخدم مرفق أسرار مُدارًا على جهة الخادم مع وصول ضيق حسب عبء العمل والبيئة، واسترجاع مدقَّق، وتدوير مختبَر، ودون كشفها للعملاء أو السجلات أو المطالبات (prompts) أو الملفات التجريبية.

هل ينبغي تعطيل التحقق من الشهادة في الإنتاج في أي وقت؟

لا. فشل الشهادة أو اسم المضيف دليل على إعداد غير آمن أو غير صحيح. أوقف المسار وشخّصه بدلًا من إضعاف التحقق من TLS بصمت.

كيف ينبغي معالجة الرفض الجزئي للمستلِمين؟

خزّن نتيجة كل مستلِم، وقدّم المجموعة المقبولة، وأعد محاولة حالات الرفض المؤقتة المؤهلة فقط. لا تعِد إرسال المستلِمين المقبولين بالفعل مع القائمة الأصلية كاملة.

هل تثبت هذه الصفحة أن SendHQ يدعم SMTP؟

لا. يغطي هذا الدليل Python SMTP عمومًا؛ استخدم وثائق SendHQ الحالية لواجهة API للبريد الإلكتروني الخاصة به.

المصادر