الأدلة التقنية

إرسال بريد خادمك عبر Amazon SES مع mailcow وPostfix وStalwart

إذا كان مزودك يحجب المنفذ 25 أو كانت رسائل سيرفرك الجديد تصل إلى Spam، فسوف نرسل البريد الصادر عبر Amazon SES ويبقى الاستقبال والصناديق على سيرفرك، مع DKIM وMAIL FROM وDMARC والارتدادات، والإعداد الدقيق لكل خادم بريد وأي تطبيق.

إرسال بريد خادمك عبر Amazon SES مع mailcow وPostfix وStalwart

في هذا الدليل سوف نترك استقبال البريد والصناديق Mailboxes على سيرفرك كما هي، ونمرر البريد الصادر فقط عبر خادم وسيط SMTP Relay (ويسمى أيضاً Smarthost) هو Amazon SES، وهذا هو الحل الذي نستخدمه نحن في خوادمنا عندما يحجب المزود المنفذ Port 25 الصادر أو يكون عنوان IP جديداً بلا تاريخ، حيث يخرج بريد أكثر من ثلاثين نطاقاً Domain من سيرفر mailcow واحد عبر SES، وبالتالي فهذا الدليل مكتوب من الأخطاء التي واجهناها فعلاً أثناء ذلك. والفكرة لا تخص mailcow وحده، فأي خادم بريد Mail Server أو تطبيق يرسل البريد يستطيع أن يسلم رسائله إلى SES عبر SMTP عادي باسم مستخدم وكلمة مرور، لذلك جمعنا في دليل واحد الجزء المشترك، أي تجهيز SES نفسه وسجلات DNS والرسائل المرتدة، ثم قسماً لكل خادم: mailcow وPostfix وStalwart وlistmonk، ثم الإعداد العام لأي تطبيق مثل Ghost وGitea وNextcloud.

أما لماذا يتحدد نجاح خادم البريد قبل أن تثبت أي برنامج، وما تجهزه من مزود وعنوان IP وسجلات DNS، فقد شرحناه في دليل استضافة البريد الإلكتروني للمؤسسات، وهنا نبدأ من سيرفر بريد يعمل ونريد أن تصل رسائله.

في هذا المقال سوف نتناول:

  • لماذا ترسل عبر خادم وسيط، وما الذي يبقى على سيرفرك، ومتى لا تحتاج إليه أصلاً.
  • تجهيز SES خطوة خطوة: المنطقة Region، والتحقق من النطاق بـ Easy DKIM، ونطاق MAIL FROM خاص بك، وسجلات SPF وDMARC، والخروج من بيئة الاختبار Sandbox، وبيانات SMTP بأقل صلاحية.
  • الرسائل المرتدة Bounces والشكاوى Complaints عبر Amazon SNS، ولماذا تحدد هذه الأرقام بقاء حسابك.
  • الإعداد الدقيق في mailcow وPostfix وStalwart وlistmonk وأي تطبيق آخر، مع مخرجات حقيقية من Postfix.
  • الاختبار، والتكلفة والحدود، وما يعنيه أن يمر بريدك عبر AWS، وأشهر الأخطاء وحلولها.

لماذا ترسل عبر خادم وسيط؟

عندما يرسل سيرفرك رسالة إلى Gmail فهو يتصل بسيرفر Gmail مباشرة على المنفذ 25، وهنا تظهر ثلاث مشكلات لا علاقة لها بجودة الإعداد، وقد شرحناها بالتفصيل في دليل البريد للمؤسسات: مزود يحجب هذا المنفذ الصادر، فمثلاً تقيد AWS المنفذ 25 على EC2 حتى تطلب رفع القيد، وغيرها يحجبه تماماً كما في دليل اختيار خادم VPS، وعنوان IP جديد ليس له سمعة Reputation فتؤخر السيرفرات الكبيرة رسائله أو تضعها في Spam أسابيع، ومتابعة قوائم الحظر Blocklists وسجل PTR وطلبات رفع الحظر وحدك.

والخادم الوسيط يحل الثلاث معاً، فسيرفرك لا يتصل بالمنفذ 25 أبداً للإرسال، وإنما يتصل بـ SES على المنفذ 587 مع STARTTLS ويسجل دخوله باسم مستخدم وكلمة مرور، ثم تخرج الرسالة من عناوين IP التابعة لـ SES والتي لها سمعة بنتها مع مزودي البريد، وتوقعها SES بمفتاح DKIM خاص بنطاقك. ويجب أن تعرف من البداية ما الذي لا يفعله SES هنا، فهو يرسل فقط، ولا يستقبل بريد نطاقك، لذلك يبقى سجل MX يشير إلى سيرفرك، ويبقى المنفذ 25 الوارد مفتوحاً على سيرفرك، وتبقى الصناديق وIMAP والبريد عبر الويب Webmail كما هي. والصورة التالية تبين المسارين:

مخطط يبين المستخدمين والتطبيقات يرسلون إلى خادم البريد على المنفذ 587، ثم يمرر الخادم البريد الصادر إلى Amazon SES على المنفذ 587 مع STARTTLS وبيانات SMTP، فتوقعه SES بـ Easy DKIM وتسلمه لسيرفر المستلم، بينما يصل البريد الوارد من سيرفر المرسل إلى خادمك مباشرة على المنفذ 25، وتعود الارتدادات والشكاوى عبر Amazon SNS إلى Webhook، مع سجلات DNS: MX وثلاثة CNAME لـ DKIM وMX وSPF لنطاق MAIL FROM وSPF للنطاق وDMARC
البريد الصادر بالبرتقالي يمر عبر SES، والوارد بالأخضر يصل إلى سيرفرك مباشرة، والبنفسجي مسار الارتدادات والشكاوى

في الصورة أعلاه لاحظ التالي:

  • المستخدمون والتطبيقات لا يعرفون شيئاً عن SES، فهم يرسلون إلى خادمك على المنفذ 587 كما كانوا يفعلون، وبالتالي تحفظ بيانات دخول SES في مكان واحد فقط هو خادم البريد.
  • سجلات DNS صارت لطرفين: سجل MX يخبر العالم أين يسلم بريدك الوارد، وثلاثة سجلات CNAME وسجلا MAIL FROM تخص SES، والسجل DMARC يربط الكل بالنطاق الظاهر في From.
  • الارتدادات والشكاوى تصل إلى SES وليس إلى سيرفرك، لذلك تحتاج إلى طريق يعيدها إليك، وهذا دور SNS كما سيأتي.

وقد يتساءل البعض: إذا كان سيرفري يرسل مباشرة ورسائله تصل، فهل أحتاج إلى SES؟ والإجابة لا، فإذا كان المنفذ 25 مفتوحاً وسجل PTR مضبوطاً والعنوان نظيفاً ورسائلك تجتاز SPF وDKIM وDMARC، فالإرسال المباشر أبسط ولا يضيف طرفاً ثالثاً يرى بريدك. وكذلك إذا كان كل ما تحتاجه إرسال رسائل آلية Transactional Emails من تطبيق واحد دون صناديق بريد، فلا تحتاج إلى خادم بريد أصلاً، وإنما تربط التطبيق بـ SES مباشرة كما في قسم التطبيقات.

ما تحتاجه قبل أن تبدأ

  • حساب AWS بصلاحية إنشاء مستخدمي IAM، والسبب أن بيانات SMTP في SES هي في الحقيقة مستخدم IAM ومفتاح وصول Access Key.
  • التحكم في DNS لنطاقك، لأنك سوف تضيف ستة سجلات على الأقل، ومعرفة أساسية بسجلات MX وSPF وDKIM وDMARC، وإذا كانت هذه المصطلحات جديدة عليك فابدأ بـ مصطلحات الاستضافة الذاتية للمبتدئين، ثم شرح DNS وسجلاته للمبتدئين وشرح SPF وDKIM وDMARC للمبتدئين.
  • خادم بريد يعمل ويستقبل مثل mailcow أو Postfix مع Dovecot أو Stalwart، أو تطبيق يرسل البريد عبر SMTP.
  • المنفذ 587 الصادر مفتوحاً من سيرفرك، وهو مفتوح عند كل المزودين تقريباً لأنه منفذ إرسال بكلمة مرور وليس منفذ تسليم بين السيرفرات، وتتأكد منه بالأمر التالي:
nc -vz -w 5 email-smtp.eu-west-1.amazonaws.com 587

ونستخدم في كل الأمثلة المنطقة eu-west-1 والنطاق example.com، فضع منطقتك ونطاقك مكانهما.

تجهيز Amazon SES خطوة خطوة

أسهل طريقة يجربها كثيرون أن ينشئوا مفتاح وصول لمستخدمهم في AWS، ثم يضعوا عنوان SES في إعداد خادم البريد ويرسلوا، فتفشل المصادقة Authentication بالخطأ 535، والسبب أن كلمة مرور SMTP ليست المفتاح السري Secret Access Key. ثم يصلحون ذلك ويتحققون من عنوان بريد واحد فقط بدلاً من النطاق، فتخرج الرسالة ولكنها تفشل في DMARC أو لا تصل إلا إلى عناوين محددة، والسبب أن الحساب ما زال في بيئة الاختبار وأن التوقيع ليس باسم نطاقك. لذلك سوف نبني الإعداد بالترتيب الصحيح: المنطقة أولاً، ثم النطاق مع DKIM، ثم MAIL FROM، ثم DNS، ثم الخروج من بيئة الاختبار، وأخيراً بيانات SMTP.

اختيار المنطقة Region

كل شيء في SES مرتبط بمنطقة واحدة: النطاقات التي تتحقق منها، وبيانات SMTP، وحالة بيئة الاختبار، وحصة الإرسال Sending Quota. فإذا تحققت من نطاقك في فرانكفورت ثم أرسلت إلى عنوان أيرلندا فسوف ترفض SES الرسالة لأن النطاق غير موثق في تلك المنطقة. واختر منطقة قريبة من سيرفرك ولها عنوان SMTP، ولاحظ أن الصفحة الرسمية تذكر أن عناوين SMTP غير متوفرة حالياً في عدة مناطق منها البحرين Middle East (Bahrain) والإمارات Middle East (UAE) وتل أبيب وكيب تاون وميلانو وزيورخ، وبالتالي فأقرب المناطق لمن في الخليج هي غالباً فرانكفورت eu-central-1 أو مومباي ap-south-1، ونحن نستخدم فرانكفورت. وعنوان SMTP لكل منطقة بالصيغة التالية:

email-smtp.<region>.amazonaws.com

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

التحقق من النطاق مع Easy DKIM

تسمي SES كل نطاق أو عنوان ترسل باسمه هوية Identity، ولا ترسل إلا من هوية موثقة. وتستطيع أن تتحقق من عنوان واحد مثل [email protected]، ولكن الصحيح أن تتحقق من النطاق كله، والسبب أن التحقق من النطاق يسمح لكل عناوينه بالإرسال، ويفعل توقيع DKIM باسم example.com وهو ما يحتاجه DMARC. والطريقة التي توصي بها AWS هي Easy DKIM، حيث تنشئ SES زوج المفاتيح Key Pair وتحتفظ بالمفتاح الخاص Private Key وتوقع كل رسالة تلقائياً، وتنشر أنت ثلاثة سجلات CNAME فقط، وطول المفتاح الافتراضي 2048 بت.

  1. من Configuration ← Identities اختر Create identity، ثم Domain، واكتب example.com.
  2. في Advanced DKIM settings اترك Easy DKIM وRSA_2048_BIT، وتأكد أن DKIM signatures مفعل.
  3. بعد الإنشاء افتح النطاق، ومن تبويب Authentication انسخ السجلات الثلاثة من Publish DNS records، أو نزلها بزر Download .csv record set.

والسجلات الثلاثة بالشكل التالي، حيث الرموز Tokens مختلفة لكل نطاق:

الاسمالنوعالقيمة
token1._domainkey.example.comCNAMEtoken1.dkim.amazonses.com
token2._domainkey.example.comCNAMEtoken2.dkim.amazonses.com
token3._domainkey.example.comCNAMEtoken3.dkim.amazonses.com

في الجدول أعلاه لاحظ التالي:

  • اكتب الاسم مرة واحدة: بعض لوحات DNS تضيف اسم النطاق تلقائياً، فإذا كتبت الاسم كاملاً صار token1._domainkey.example.com.example.com، وهذا السبب الأول الذي تذكره AWS لبقاء الحالة Pending، فاكتب token1._domainkey فقط إذا كانت لوحتك تكمل الاسم.
  • Cloudflare: اجعل السجلات الثلاثة على وضع DNS only، والسبب أن ال Proxy يخفي ال CNAME ويعيد عناوين Cloudflare بدلاً منه فلا تجد SES المفتاح، ولذلك فالسكربتات التي ننشر بها هذه السجلات عندنا ترفض أي سجل CNAME لـ DKIM يكون عليه ال Proxy.
  • التحقق يأخذ وقتاً: تقول AWS إن التغيير قد يحتاج حتى 72 ساعة حتى تراه، وغالباً يتم في دقائق، وعندها تتغير حالة النطاق إلى Verified وحالة DKIM إلى Successful.

وتتحقق من نشر السجلات من أي جهاز:

dig +short CNAME token1._domainkey.example.com
⚠️
لا تحذف هذه السجلات بعد التحقق، فـ SES تفحصها باستمرار، وإذا لم تجدها ترسل لك تنبيهاً ثم توقف توقيع DKIM وتسقط التحقق عن النطاق. وقد حدث ذلك عندنا أكثر من مرة مع نطاقات اختفت سجلات DKIM الثلاثة من مزود DNS الخاص بها، فبعد أيام بدأت رسائلها ترفض بالخطأ 554 Message rejected: Email address is not verified مع أن خادم البريد لم يتغير فيه شيء، والحل كان إعادة السجلات الثلاثة كما هي وليس تعديل إعداد الخادم الوسيط.

نطاق MAIL FROM خاص بك

عنوان المغلف MAIL FROM أو Return-Path غير عنوان From الذي يراه المستلم كما شرحنا في شرح SPF وDKIM وDMARC، وإذا لم تضبط شيئاً فإن SES تجعل MAIL FROM نطاقاً فرعياً من amazonses.com، وهذا يجتاز فحص SPF، ولكنه SPF لنطاق amazonses.com وليس لنطاقك، وبالتالي لا يتطابق Aligned مع From في DMARC، فتعتمد رسالتك في DMARC على DKIM وحده. والحل أن تضبط نطاق MAIL FROM خاصاً بك، وهو نطاق فرعي Subdomain مثل bounce.example.com، فيجتاز SPF باسم نطاقك ويصبح لرسالتك طريقان مستقلان لاجتياز DMARC بدلاً من طريق واحد.

  1. افتح النطاق في Identities، ومن قسم Custom MAIL FROM domain اختر Edit.
  2. فعل Use a custom MAIL FROM domain واكتب bounce.
  3. في Behavior on MX failure اختر Use default MAIL FROM domain، أي إذا لم تجد SES سجل MX للنطاق الفرعي عادت مؤقتاً إلى نطاقها بدلاً من رفض الرسالة.
  4. انشر السجلين اللذين تعرضهما الصفحة:
الاسمالنوعالقيمة
bounce.example.comMX10 feedback-smtp.eu-west-1.amazonses.com
bounce.example.comTXT"v=spf1 include:amazonses.com ~all"

لاحظ أن النطاق الفرعي يجب ألا تستقبل عليه بريداً وألا ترسل منه، وأن يكون له سجل MX واحد فقط، والسبب أن الإعداد يفشل إذا وجدت SES أكثر من سجل MX، ولاحظ أيضاً أن اسم المنطقة جزء من قيمة MX، فإذا انتقلت إلى منطقة أخرى فعليك تغييره.

سجلات SPF وDMARC للنطاق الرئيسي

هنا يقع أكثر الناس في سؤال: هل أضيف include:amazonses.com إلى سجل SPF للنطاق الرئيسي Root Domain؟ والإجابة أن SES لا تحتاجه، والسبب أن فحص SPF يتم على نطاق MAIL FROM وليس على النطاق الظاهر في From، فإذا ضبطت bounce.example.com فإن فحص SPF يقرأ سجل النطاق الفرعي وحده، وإذا لم تضبطه فإن الفحص يتم على نطاق amazonses.com، وفي الحالتين لا يقرأ أحد سجل example.com لرسائل SES. وقد أضفناه نحن في بعض النطاقات، وهو لا يضر، ولكنه يستهلك استعلاماً من الاستعلامات العشرة التي يسمح بها معيار SPF، لذلك اتركه فقط إذا كان عندك سبب آخر. أما سجل SPF للنطاق الرئيسي فيبقى كما هو لسيرفرك، لأن سيرفرك ما زال يستقبل ويرسل بعض الرسائل بنفسه مثل الردود الآلية والإشعارات المحلية.

والجدول التالي يجمع كل السجلات في مكان واحد بعد الإعداد:

الاسمالنوعالقيمةلمن
example.comMX10 mail.example.comالبريد الوارد إلى سيرفرك، ولا يتغير
example.comTXTv=spf1 mx -allSPF لسيرفرك، ولا يتغير
token1/2/3._domainkey.example.comCNAMEtoken.dkim.amazonses.comEasy DKIM في SES
bounce.example.comMX10 feedback-smtp.eu-west-1.amazonses.comالارتدادات إلى SES
bounce.example.comTXTv=spf1 include:amazonses.com ~allSPF لنطاق MAIL FROM
_dmarc.example.comTXTv=DMARC1; p=none; rua=mailto:[email protected]سياسة DMARC وتقاريرها
dkim._domainkey.example.comTXTv=DKIM1; k=rsa; p=…مفتاح خادمك إن كان يوقع، ويبقى كما هو

وفي سجل DMARC لاحظ أمرين، الأول أن تبدأ بالقيمة p=none وتجمع التقارير، ثم تنتقل إلى quarantine ثم reject كما توصي AWS، والثاني ألا تضع aspf=s، والسبب أن التطابق الصارم Strict Alignment يشترط أن يكون نطاق MAIL FROM هو نطاق From نفسه، وbounce.example.com نطاق فرعي، فيفشل التطابق في SPF، أما التطابق المرن Relaxed وهو الافتراضي فيقبل النطاق الفرعي.

الخروج من بيئة الاختبار Sandbox

كل حساب جديد يبدأ في بيئة الاختبار في كل منطقة على حدة، وفيها لا ترسل إلا إلى عناوين ونطاقات موثقة أو إلى عناوين المحاكي Mailbox Simulator، وبحد أقصى 200 رسالة في 24 ساعة ورسالة واحدة في الثانية. وهذا يفسر لماذا تصل رسالة الاختبار إلى بريدك الذي وثقته بينما ترفض الرسالة إلى زميلك.

ولطلب الخروج افتح Account dashboard، ثم View Get set up page، ثم Request production access. والنموذج الحالي لا يحتوي على خانة لشرح طويل كما كان سابقاً، وإنما يسألك عن نوع البريد Mail type، أي Transactional للرسائل الفردية مثل بريد الموظفين والإشعارات أو Marketing للحملات، ثم رابط موقعك، وحتى أربعة عناوين للتواصل، ولغة التواصل، ثم تقر بأنك ترسل فقط لمن طلب رسائلك وأن لديك طريقة لمعالجة الارتدادات والشكاوى. وترد AWS خلال 24 ساعة، وقد تطلب معلومات إضافية، فإذا وصلك سؤال فأجب بوضوح عن ثلاثة أمور: من أين تأتي العناوين التي ترسل إليها (موظفوك وعملاؤك المسجلون وليس قوائم مشتراة)، وكم رسالة ترسل يومياً تقريباً، وكيف تعالج الارتدادات والشكاوى وإلغاء الاشتراك، وهذا ما سوف نبنيه في قسم الارتدادات.

💡
تحقق من النطاق واضبط MAIL FROM وDMARC قبل أن تطلب الخروج من بيئة الاختبار، فـ AWS نفسها تذكر أن وجود نطاق موثق يسرع الموافقة، ورابط الموقع في الطلب يجب أن يفتح ويبين من أنت.

إنشاء بيانات SMTP بأقل صلاحية

بيانات SMTP في SES هي اسم مستخدم يشبه مفتاح الوصول وكلمة مرور مشتقة منه، وتقول صفحة بيانات SMTP أمرين يجب أن تحفظهما: كلمة مرور SMTP ليست المفتاح السري لمستخدم IAM، وهي خاصة بمنطقة واحدة، فإذا أرسلت من منطقتين احتجت إلى كلمتي مرور.

الطريقة السريعة من اللوحة: SMTP settings ثم Create SMTP credentials، فتفتح لوحة IAM وتنشئ مستخدماً تضعه في مجموعة اسمها AWSSESSendingGroupDoNotRename عليها السياسة AmazonSesSendingAccess، وهذه السياسة تسمح بالإجراء ses:SendRawEmail على كل الهويات في الحساب، ثم تعرض لك كلمة المرور مرة واحدة فقط، فاحفظها في مدير كلمات المرور قبل أن تغلق الصفحة.

وهذا يعمل، ولكن المستخدم يستطيع أن يرسل باسم أي نطاق موثق في الحساب، فإذا كان لديك عدة نطاقات أو عدة عملاء في حساب واحد ثم تسربت كلمة المرور من سيرفر واحد، فالمخترق يرسل باسمهم جميعاً. لذلك فالطريقة التي نوصي بها أن تنشئ لكل خادم مستخدماً مستقلاً بسياسة تقيد عنوان From بـ مفتاح الشرط ses:FromAddress:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "ses:SendRawEmail",
      "Resource": "*",
      "Condition": {
        "StringLike": {
          "ses:FromAddress": ["*@example.com", "*@example.org"]
        }
      }
    }
  ]
}

في الإعداد أعلاه لاحظ التالي:

  • ses:SendRawEmail هو الإجراء الوحيد الذي تحتاجه واجهة SMTP، فلا تعط المستخدم ses:* ولا صلاحية قراءة الإحصاءات أو تعديل الهويات.
  • ses:FromAddress يقيد عنوان From، فاكتب فيه نطاقات هذا الخادم فقط، وإذا أضفت نطاقاً جديداً إلى الخادم فأضفه هنا أيضاً، وإلا ترفض SES رسائله.

ثم أنشئ المستخدم في IAM دون دخول إلى اللوحة Console، وأرفق به السياسة، وأنشئ له مفتاح وصول، وحول المفتاح السري إلى كلمة مرور SMTP بالسكربت الرسمي smtp_credentials_generate.py المنشور في الصفحة نفسها، حيث تنسخه كما هو ثم تشغله بالمفتاح السري والمنطقة:

python3 smtp_credentials_generate.py 'SECRET_ACCESS_KEY' eu-west-1

والمخرج سطر واحد هو كلمة مرور SMTP، واسم المستخدم هو معرف مفتاح الوصول Access Key ID نفسه. ولاحظ أن AWS لا تقبل كلمة مرور مشتقة من بيانات مؤقتة Temporary Credentials، وأن السكربت يرفض المناطق التي ليس لها عنوان SMTP.

🛑
لا تشتق كلمة مرور SMTP من مفتاح مستخدمك الإداري أو من أي مستخدم له صلاحيات أخرى، والسبب أن من يحصل على ملف الإعداد في سيرفر البريد يحصل على اسم المستخدم وهو مفتاح الوصول نفسه، فإذا كان المستخدم يملك صلاحيات أوسع فقد سلمته حسابك. وإذا شككت في تسرب كلمة المرور فاحذف مفتاح الوصول من IAM وأنشئ غيره، فهذا يلغي كلمة مرور SMTP المشتقة منه فوراً.

عنوان الخادم والمنفذ

تشترط SES أن يكون كل اتصال مشفراً بـ TLS، وتقبل طريقتين: STARTTLS على المنافذ 25 و587 و2587، حيث يبدأ الاتصال عادياً ثم يترقى إلى TLS، وTLS المباشر TLS Wrapper على المنفذين 465 و2465. واستخدم 587 مع STARTTLS، فهو ما يدعمه mailcow وPostfix وStalwart بلا استثناء، ولا تستخدم المنفذ 25 خاصة من EC2 حيث تقيده AWS نفسها.

الإعدادالقيمة
Hostemail-smtp.eu-west-1.amazonaws.com
Port587 مع STARTTLS، أو 465 مع TLS مباشر
Usernameمعرف مفتاح الوصول، ويبدأ عادة بـ AKIA
Passwordكلمة مرور SMTP المشتقة، وليس المفتاح السري

الرسائل المرتدة والشكاوى

عندما ترسل عبر سيرفرك مباشرة فالرسائل المرتدة مشكلتك وحدك، أما مع SES فهي مشكلة حسابك كله، والسبب أن SES تراقب نسبتين وتتصرف على أساسهما كما في أسئلة التطبيق Enforcement FAQ: نسبة الارتداد الدائم Bounce Rate، والمطلوب أن تبقى تحت 2%، فإذا بلغت 5% وضعت SES حسابك تحت المراجعة، وإذا بلغت 10% فقد توقف إرسالك، ونسبة الشكاوى Complaint Rate، والمطلوب أن تبقى تحت 0.1%، فإذا بلغت 0.1% وضع حسابك تحت المراجعة، وإذا بلغت 0.5% فقد يتوقف الإرسال. وتوقف الإرسال هنا يعني أن بريد كل موظفيك يتوقف، وليس حملة واحدة فقط.

وتصلك هذه الأحداث بإحدى ثلاث طرق:

  • إعادة التوجيه بالبريد Email Feedback Forwarding: وهي مفعلة افتراضياً، حيث تعيد SES الرسالة المرتدة إلى عنوان Return-Path أو MAIL FROM الذي أرسلت به، وبالتالي يجد الموظف في صندوقه على سيرفرك رسالة الارتداد كما تعود عليها، وهذا يكفي لبريد الموظفين اليومي.
  • إشعارات Amazon SNS: ترسل SES كل ارتداد وشكوى بصيغة JSON إلى موضوع Topic في SNS، والموضوع يرسلها إلى عنوان HTTPS أو بريد أو قائمة انتظار، وهذه هي الطريقة الصحيحة لأي نظام يرسل إلى قوائم، لأن البرنامج يحتاج إلى أن يحظر العنوان تلقائياً.
  • مجموعات الإعداد Configuration Sets: تنشر أحداثاً أكثر تفصيلاً مثل التسليم والفتح، وتختارها لكل رسالة بالترويسة X-SES-CONFIGURATION-SET، ولا تحتاج إليها في البداية.

ولربط SNS، أنشئ في لوحة SNS موضوعاً من النوع Standard في المنطقة نفسها، ثم اشترك فيه بعنوان HTTPS الذي يستقبل الإشعارات، ثم افتح النطاق في SES، ومن تبويب Notifications اختر Edit في Feedback notifications وحدد الموضوع للارتداد Bounce وللشكوى Complaint، وفعل Include original email headers حتى يعرف البرنامج أي رسالة ارتدت. وهذا بالضبط ما يحتاجه listmonk، حيث يستقبل الإشعارات على المسار /webhooks/service/ses ويؤكد الاشتراك تلقائياً، ويشترط توثيقه أن تترك Enable raw message delivery غير مفعل، وقد شرحنا إعداد listmonk في دليل listmonk. وعندنا ربطنا موضوعاً واحداً لكل نطاق يرسل نشرات، ثم أرسلنا حملة تجريبية إلى عنواني المحاكي [email protected] و[email protected]، وتأكدنا أن listmonk سجل الحدثين وحظر العنوانين قبل أي حملة حقيقية.

ولاحظ أن SES تضيف العنوان الذي ارتد ارتداداً دائماً أو جاءت منه شكوى إلى قائمة الحظر على مستوى الحساب Suppression List، وهي مفعلة افتراضياً في الحسابات التي بدأت بعد 25 نوفمبر 2019، فلا ترسل إليه مرة أخرى حتى لو حاول تطبيقك، وإذا أردت لوحة تبين نسب الوصول وتوصيات لتحسينها فهناك خدمة Virtual Deliverability Manager الاختيارية.

ربط خادم البريد بـ SES

الآن صار لديك نطاق موثق وبيانات SMTP، وما بقي هو أن تخبر خادم البريد أن يسلم كل بريده الخارجي إلى SES بدلاً من الاتصال بسيرفرات المستلمين، وفيما يلي الإعداد لكل خادم.

mailcow: ناقل حسب المرسل Sender-dependent Transport

لا يضع mailcow خادماً وسيطاً واحداً لكل السيرفر، وإنما يعرف نواقل حسب المرسل Sender-dependent Transports تختار منها لكل نطاق، وهذا ما نستفيد منه عندنا، فأغلب النطاقات على ناقل SES، ونطاق واحد نقلناه إلى مزود إرسال آخر له منطقة في الرياض فصار له ناقل ثان، وكل ذلك على سيرفر واحد.

  1. افتح System ← Configuration ← Routing، وانزل إلى Add sender-dependent transport.
  2. في Host اكتب [email-smtp.eu-west-1.amazonaws.com]:587، وفي Username وPassword بيانات SMTP، ثم احفظ.
  3. اضغط Test بجوار الناقل الجديد، واكتب في "From:" address عنواناً من نطاقك، وفي "To:" address العنوان [email protected]، ثم Run test، والنتيجة الصحيحة سطر 250 في آخر المحادثة.
  4. افتح E-Mail ← Configuration ← Domains، ثم Edit للنطاق، واختر الناقل من القائمة Sender-dependent transports، ثم احفظ.

في الخطوات أعلاه لاحظ التالي:

  • لا تستخدم المنفذ 465: نص المساعدة في اللوحة نفسها يقول إن ال TLS المباشر Wrapped TLS غير مدعوم، وإن الناقل يستخدم smtp: دائماً فيطلب STARTTLS حين يعرضه الخادم، لذلك فالمنفذ الصحيح هو 587. وإذا أردت أن تفرض التشفير بدلاً من أن يكون اختيارياً فأضف الوجهة نفسها في TLS policy maps بالسياسة encrypt أو secure، مع أن SES نفسها لا تقبل تسجيل الدخول دون TLS.
  • عنوان المحاكي في الاختبار: العنوان الافتراضي الذي يرسل إليه زر Test عنوان خارجي، فإذا كان حسابك ما زال في بيئة الاختبار ترفضه SES بالخطأ 554 … Email address is not verified وتظن أن الناقل لا يعمل، لذلك اكتب عنوان المحاكي في خانة To.
  • لكل صندوق ناقله: من Mailboxes ← Edit تستطيع أن تختار ناقلاً لصندوق واحد، وهذا الاختيار يتقدم على ناقل النطاق كما يقول نص اللوحة، ويفيد حين يرسل صندوق آلي مثل noreply@ بأحجام كبيرة.
  • Transport Maps مختلفة: قسم Transport Maps في الصفحة نفسها يوجه البريد حسب المستلم وليس المرسل، ويتقدم على الناقل حسب المرسل، فلا تضع فيه SES إلا إذا كنت تعرف لماذا.
⚠️
يحفظ mailcow اسم المستخدم وكلمة المرور للناقل كنص عادي في قاعدة بياناته، فكل نسخة احتياطية من mailcow تحتوي كلمة مرور SES، وهذا سبب إضافي لتقييد المستخدم بالسياسة التي كتبناها وتشفير النسخ الاحتياطية.

ولتتأكد أن البريد يخرج عبر SES، أرسل رسالة من أي صندوق في النطاق، ثم ابحث في سجل Postfix داخل mailcow:

cd /opt/mailcow-dockerized
docker compose logs --tail=200 postfix-mailcow | grep 'relay=email-smtp'

وفي كل سطر سوف تجد relay=email-smtp.eu-west-1.amazonaws.com[…]:587 ثم status=sent (250 Ok …)، والرقم بعد 250 Ok هو معرف الرسالة MessageID في SES، وتحتاجه إذا راسلت دعم AWS عن رسالة محددة. أما التطبيقات التي ترسل عبر mailcow، فالأفضل أن تعطي كل تطبيق كلمة مرور تطبيق App Password خاصة بالإرسال فقط على المنفذ 587، فإذا تسربت من التطبيق لا تفتح صندوق البريد عبر IMAP ولا تكشف بيانات SES، وهكذا تعمل نماذج التواصل والنشرات عندنا.

Postfix: الإعداد relayhost

إذا كنت تدير Postfix بنفسك كما في دليل Postfix وDovecot، فالخادم الوسيط يضبط بالإعداد relayhost ومعه إعدادات المصادقة من جهة الكلاينت SASL Client، وهو ما يشرحه أيضاً دليل AWS لـ Postfix. ابدأ بالحزمة التي تحتوي آليات المصادقة، والسبب أن Postfix بدونها يفشل بالرسالة no mechanism available:

sudo apt install libsasl2-modules

ثم اكتب بيانات SMTP في ملف مستقل، ولاحظ أن المفتاح في أول السطر يجب أن يطابق قيمة relayhost حرفاً بحرف، بالأقواس المربعة والمنفذ:

sudo nano /etc/postfix/sasl_passwd
[email-smtp.eu-west-1.amazonaws.com]:587 SMTP_USERNAME:SMTP_PASSWORD
sudo chmod 600 /etc/postfix/sasl_passwd
sudo postmap hash:/etc/postfix/sasl_passwd

والآن نضيف الإعداد. والطريقة السهلة أن تضع relayhost وتترك مستوى TLS كما هو في Ubuntu، أي smtp_tls_security_level = may، فيعمل كل شيء، ولكن هذا المستوى يعني «شفر إن استطعت»، فإذا وجه أحدهم سيرفرك إلى خادم لا يعرض STARTTLS أو حذف عرض STARTTLS من الاتصال أثناء مروره، فسوف يرسل Postfix الرسالة دون تشفير. والمستوى encrypt يمنع ذلك لأنه يشترط TLS، ولكنه لا يتحقق من هوية الخادم، فيقبل أي شهادة Certificate. لذلك فالصحيح هو secure الذي يشترط TLS ويتحقق أن الشهادة صادرة لاسم email-smtp.eu-west-1.amazonaws.com من جهة إصدار موثوقة، وهو ما يستخدمه دليل AWS أيضاً:

sudo postconf -e \
  'relayhost = [email-smtp.eu-west-1.amazonaws.com]:587' \
  'smtp_sasl_auth_enable = yes' \
  'smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd' \
  'smtp_sasl_security_options = noanonymous' \
  'smtp_tls_security_level = secure' \
  'smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt' \
  'smtp_tls_loglevel = 1'
sudo postfix check
sudo systemctl reload postfix

في الإعداد أعلاه لاحظ التالي:

  • الأقواس المربعة في [email-smtp.eu-west-1.amazonaws.com]:587 تمنع Postfix من البحث عن سجل MX لهذا الاسم وتجعله يتصل بالعنوان مباشرة، وبدونها يبحث عن MX فلا يجده.
  • smtp_sasl_security_options = noanonymous ضروري، والسبب أن القيمة الافتراضية في Postfix تتضمن noplaintext التي ترفض آليتي PLAIN وLOGIN، وهما ما تقبله SES، أما التشفير فيضمنه مستوى TLS وليس آلية المصادقة.
  • smtp_tls_loglevel = 1 يكتب في السجل سطراً لكل اتصال TLS، وبه تعرف هل تحقق Postfix من الشهادة أم لا.
  • الإعداد relayhost يؤثر على البريد الخارجي فقط، فالرسائل إلى نطاقاتك تبقى تسلم محلياً إلى Dovecot عبر LMTP كما كانت.
  • لا تحتاج إلى تغيير الحد الافتراضي لعدد المستلمين في الرسالة، فـ Postfix يرسل حتى 50 مستلماً في كل عملية تسليم افتراضياً، وهو الحد نفسه الذي تقبله SES في الرسالة.

ولاختبار الإعداد أرسل رسالة من السيرفر إلى عنوان المحاكي، ثم اقرأ السجل:

swaks --server 127.0.0.1 --from [email protected] --to [email protected] --h-Subject "Relay test"
sudo tail -n 3 /var/log/mail.log

والمخرج سوف يكون كما يلي:

postfix/smtp[408]: Verified TLS connection established to email-smtp.eu-west-1.amazonaws.com[198.51.100.25]:587: TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256
postfix/smtp[408]: 096A37CF9: to=<[email protected]>, relay=email-smtp.eu-west-1.amazonaws.com[198.51.100.25]:587, delay=0.36, delays=0.11/0.11/0.14/0, dsn=2.0.0, status=sent (250 …)
postfix/qmgr[400]: 096A37CF9: removed

في المخرج أعلاه لاحظ كلمة Verified في السطر الأول، فهي تعني أن Postfix تحقق من الشهادة، ومع المستوى encrypt سوف تجد مكانها Untrusted لأن الشهادة لم تفحص، ثم relay= باسم SES وstatus=sent في السطر الثاني.

والآن لنكسر الإعداد عن قصد لنرى ما يحمينا منه. إذا وجهت Postfix بالمستوى encrypt إلى خادم وسيط لا يعرض STARTTLS، فسوف يرفض أن يرسل ويبقي الرسالة في الطابور:

postfix/smtp[459]: ADB7D7CF9: to=<[email protected]>, relay=plain-relay.example.net[198.51.100.30]:587, delay=0.31, delays=0.14/0.16/0/0, dsn=4.7.4, status=deferred (TLS is required, but was not offered by host plain-relay.example.net[198.51.100.30])

أما بالمستوى may الافتراضي ومع الخادم نفسه فسوف تخرج الرسالة دون أي تشفير وتنتهي بـ status=sent، وهذا بالضبط ما يحدث بصمت إذا تركت القيمة الافتراضية. وإذا وجهت المستوى secure إلى خادم يقدم شهادة صادرة لاسم آخر، فسوف يرفضه أيضاً:

postfix/smtp[433]: server certificate verification failed for relay.example.net[198.51.100.25]:587: num=62:hostname mismatch
postfix/smtp[433]: C5FAA7CE8: to=<[email protected]>, relay=relay.example.net[198.51.100.25]:587, delay=0.03, delays=0.01/0.01/0/0, dsn=4.7.5, status=deferred (Server certificate not verified)

لاحظ أن الحالة في الحالتين deferred وليس bounced، أي أن Postfix يحتفظ بالرسالة ويعيد المحاولة، فإذا أصلحت الإعداد خلال أيام فلن تضيع رسالة، وتستطيع أن تدفع الطابور فوراً بالأمر sudo postqueue -f.

توقيع DKIM الخاص بك مع SES

إذا كان OpenDKIM يوقع رسائلك كما في دليل Postfix، فسوف تحمل الرسالة بعد SES ثلاثة توقيعات: توقيعك أنت باسم example.com، وتوقيع Easy DKIM باسم example.com، وتوقيع ثالث باسم amazonses.com تقول AWS إنها تضيفه دائماً لأنها تحتاجه في حلقات الشكاوى Feedback Loops وأنك تستطيع تجاهله. والمشكلة في توقيعك أنت، فـ SES تستبدل الترويستين Date وMessage-ID بقيمها، ولذلك تقول صفحة التوقيع اليدوي لا توقع Message-ID ولا Date ولا Return-Path ولا Bounces-To. وOpenDKIM يوقع Date افتراضياً، فإذا فحصت رسالة وقعها بالإعداد الافتراضي فسوف تجد قائمة الترويسات الموقعة كما يلي:

DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=example.com; s=mail;
	t=1791156817; bh=ecGWgWCJeWxJFeM0urOVWP+KOlqqvsQYKOpYUP8nk7I=;
	h=Date:To:From:Subject;

وهذا التوقيع سوف يفشل عند المستلم بعد أن تغير SES قيمة Date، ولن يضر ذلك وصول الرسالة لأن DMARC يكفيه توقيع واحد متطابق ناجح، وهو توقيع Easy DKIM، ولكنه يملأ تقارير DMARC بنتائج fail تربكك. والحل أن تستبعد الترويستين من توقيعك بالخيار OmitHeaders، حيث تعني النجمة القائمة الافتراضية وعلامة الجمع إضافة إليها، وأضف السطر التالي إلى /etc/opendkim.conf:

OmitHeaders *,+Date,+Message-ID
sudo systemctl restart opendkim

وبعد إعادة التشغيل سوف تصبح الترويسات الموقعة كما يلي، فلا يبقى في التوقيع شيء تغيره SES:

DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=example.com; s=mail;
	t=1791156894; bh=ecGWgWCJeWxJFeM0urOVWP+KOlqqvsQYKOpYUP8nk7I=;
	h=To:From:Subject;

والأمر نفسه ينطبق على mailcow وStalwart، فكلاهما يوقع بمفتاحه الخاص قبل أن تصل الرسالة إلى SES، وقد تجد نتيجة fail لهذا التوقيع في التقارير، وهذا مقبول ما دام توقيع Easy DKIM ناجحاً ومتطابقاً، ولا تحذف مفتاح خادمك من DNS، لأنك تحتاجه إذا عدت يوماً إلى الإرسال المباشر.

Stalwart 0.16: مسار من النوع Relay

منذ الإصدار 0.16 صار إعداد Stalwart كائنات Objects في قاعدة البيانات تديرها من الواجهة WebUI بدلاً من ملف نصي، والتوجيه فيه على مرحلتين: تعرف مساراً Route من النوع Relay، ثم تخبر استراتيجية الإرسال MtaOutboundStrategy متى تستخدمه.

  1. من Settings › MTA › Outbound › Routes أنشئ مساراً من النوع Relay باسم ses، واكتب في address القيمة email-smtp.eu-west-1.amazonaws.com، وفي port القيمة 587، واترك protocol على smtp وimplicitTls وallowInvalidCerts معطلين، ثم اكتب اسم مستخدم SMTP في authUsername، واختر لـ authSecret النوع Value وضع كلمة المرور، أو النوع File أو EnvironmentVariable إذا أردت ألا تحفظ في قاعدة البيانات.
  2. من Settings › MTA › Outbound › TLS Strategies أنشئ استراتيجية باسم ses-tls وضع startTls على require، والسبب أن القيمة الافتراضية optional، ومثال الإعداد في التوثيق يخفف TLS تدريجياً بعد أخطاء TLS حتى يعطله، وهذا مقبول مع سيرفرات المستلمين القديمة وغير مقبول مع اتصال يحمل كلمة مرور.
  3. من Settings › MTA › Outbound › Strategy عدل التعبيرين route وtls حتى يذهب كل ما ليس لنطاقاتك إلى SES.

والقيمتان بصيغة الكائنات كما يكتبها التوثيق تكونان كما يلي:

{
  "route": {
    "match": {
      "0": {"if": "is_local_domain(rcpt_domain)", "then": "'local'"}
    },
    "else": "'ses'"
  },
  "tls": {
    "else": "'ses-tls'"
  }
}

في الإعداد أعلاه لاحظ التالي:

  • الأسماء local وses وses-tls يجب أن تطابق أسماء كائنات موجودة، فإذا أخطأت في اسم لا يفشل الإرسال، وإنما يكتب Stalwart تحذيراً smtp.id-not-found ويعود بصمت إلى الإعداد المدمج، أي التسليم المباشر عبر MX مع TLS اختياري، لذلك ابحث عن هذا التحذير في السجل بعد كل تعديل.
  • التعبير is_local_domain(rcpt_domain) في route يبقي بريد نطاقاتك داخل الخادم، فلا تخرج رسالة من زميل إلى زميل عبر SES ثم تعود.
  • أما tls فيكفي فيه ses-tls لكل الرسائل، والسبب أن البريد المحلي لا يفتح اتصالاً خارجياً أصلاً، وكل اتصال خارجي يذهب إلى SES فقط.
  • بقية التعبيرات في الاستراتيجية مثل الجدولة Schedule والاتصال Connection تبقى كما هي.

وبعد الحفظ أرسل رسالة إلى عنوان المحاكي [email protected]، وراجع في سجل التسليم أن الرسالة خرجت عبر المسار ses قبل أن تعتمد على الإعداد.

listmonk: الإرسال المباشر أو عبر خادمك

لديك خياران مع listmonk. الأول أن يرسل إلى SES مباشرة، فتضيف من Settings ← SMTP خادماً بالمضيف email-smtp.eu-west-1.amazonaws.com والمنفذ 587 وTLS بقيمة STARTTLS وAuth protocol بقيمة LOGIN وبيانات SMTP، والأفضل هنا مستخدم SMTP مستقل لا يرسل إلا من عنوان النشرة. والثاني أن يرسل إلى خادم بريدك على المنفذ 587 بكلمة مرور تطبيق، فيمرر الخادم الرسائل إلى SES كما يفعل مع بقية البريد، وهذا ما نفعله نحن، فتبقى بيانات SES في مكان واحد.

وفي الحالتين اربط الارتدادات بـ SNS كما شرحنا في قسم الارتدادات، وانتبه إلى سرعة الإرسال، فحصة SES مشتركة بين كل ما يرسل من الحساب في المنطقة نفسها، فإذا أطلقت حملة بأقصى سرعة فقد تستهلك المعدل في الثانية وتتأخر رسائل الموظفين وكلمات المرور، لذلك حددنا سرعة النشرات عندنا برسالة واحدة في الثانية مع أن حصة الحساب أكبر بكثير، فالنشرة تستطيع أن تنتظر وإشعار تغيير كلمة المرور لا يستطيع.

أي تطبيق آخر: Ghost وGitea وNextcloud

كل تطبيق يرسل البريد عبر SMTP يحتاج إلى القيم نفسها التي في جدول عنوان الخادم والمنفذ: المضيف والمنفذ 587 وSTARTTLS واسم المستخدم وكلمة المرور وعنوان From من نطاق موثق، والفرق فقط في أسماء الحقول:

التطبيقأين تضبط البريدملاحظة
Ghostقسم mail في ملف الإعداد بالنقل SMTP كما في توثيق الإعداديرسل عبر SMTP رسائل الدخول والإشعارات فقط، أما النشرات البريدية المدمجة فتشترط Mailgun في النسخة المستضافة ذاتياً، ولذلك نرسل نشراتنا من listmonk
Giteaقسم [mailer] في app.ini كما في توثيق البريدمع المنفذ 587 اكتب PROTOCOL = smtp+starttls
NextcloudAdministration settings ← Basic settings ← Email server، أو قيم mail_smtp* في config.php كما في توثيق البريداختر SMTP واكتب المضيف والمنفذ وفعل المصادقة

وقد يتساءل البعض: أيهما أفضل، أن أربط كل تطبيق بـ SES مباشرة أم عبر خادم البريد؟ والإجابة أن الربط عبر خادم البريد يجعل بيانات SES في مكان واحد، ويجعل كل رسائل التطبيقات في سجل واحد، ويسمح لك بتغيير المزود يوماً ما دون أن تلمس أي تطبيق، أما الربط المباشر فيناسب التطبيق الذي يعمل بعيداً عن خادم البريد أو الذي ليس لديك خادم بريد أصلاً، وعندها أنشئ لكل تطبيق مستخدم SMTP مستقلاً مقيداً بعنوان From الخاص به، حتى إذا تسربت كلمة مرور تطبيق واحد لا تضطر إلى تغييرها في كل التطبيقات.

التحقق من النجاح

أول ما تستخدمه هو محاكي صناديق البريد Mailbox Simulator، وهو عناوين وهمية ترد عليك كما ترد السيرفرات الحقيقية، ويعمل حتى في بيئة الاختبار، ولا تحسب رسائله في حصتك اليومية ولا في نسب الارتداد والشكاوى، ولكنها تحسب في الفاتورة كأي رسالة:

العنوانما يحدث
[email protected]يقبل الرسالة
[email protected]يرفضها بالرد 550 5.1.1 فتصلك رسالة ارتداد أو إشعار SNS
[email protected]يقبلها ثم يرسل شكوى كأن المستلم صنفها Spam
[email protected]يرد برد آلي Out of Office إلى عنوان MAIL FROM

وتستطيع أن تختبر SES مباشرة من سيرفرك قبل أن تلمس خادم البريد، أي أن تتحقق من المنفذ وبيانات SMTP وحدها، بالأداة swaks:

swaks --server email-smtp.eu-west-1.amazonaws.com --port 587 --tls \
  --auth LOGIN --auth-user 'SMTP_USERNAME' --auth-password 'SMTP_PASSWORD' \
  --from [email protected] --to [email protected] \
  --h-Subject "SES test"

فإذا نجح هذا الأمر وفشل خادم البريد، فالمشكلة في إعداد الخادم وليست في SES. وبعد ذلك أرسل رسالة حقيقية من صندوقك إلى حساب في Gmail، وافتحها واختر Show original، ثم ابحث في الترويسة Authentication-Results عن التالي:

  • dkim=pass مع [email protected]، وهو توقيع Easy DKIM، وبجواره dkim=pass مع amazonses.com.
  • spf=pass مع smtp.mailfrom= عنوان من bounce.example.com، فإذا وجدت فيه amazonses.com فمعنى ذلك أن MAIL FROM الخاص بك لم يعمل بعد وأن SES عادت إلى نطاقها.
  • dmarc=pass مع header.from=example.com.

وفي آخر رسالة اختبرناها من أحد نطاقاتنا بهذه الطريقة وصلت إلى Gmail في ثانية واحدة، والنتائج الثلاث pass.

التكلفة والحدود

تغيرت طريقة التسعير في SES هذا العام، فبحسب صفحة الأسعار صارت هناك خطط Plans، وكل حساب جديد، أو منطقة لم يكن فيها استخدام محسوب منذ 1 يونيو 2025، يبدأ منذ 21 يوليو 2026 على خطة Essentials بسعر 0.16 دولار لكل 1000 رسالة في أول 10 ملايين شهرياً، وتشمل الخطة Virtual Deliverability Manager. وتستطيع في أي وقت أن تنتقل إلى التسعير بالقطعة À la carte، وفيه 0.10 دولار لكل 1000 رسالة، و0.12 دولار لكل غيغابايت من المرفقات، ويحسب VDM فيه منفصلاً. فمثلاً فريق يرسل 20 ألف رسالة في الشهر يدفع دولارين بالتسعير بالقطعة، أو 3.20 دولار بخطة Essentials، ولاحظ أن رسائل المحاكي تحسب بالسعر نفسه، وأن عملاء AWS الجدد يحصلون على رصيد مجاني حتى 200 دولار يمكن استخدامه في SES.

أما الحدود فأهمها:

  • بيئة الاختبار: 200 رسالة في 24 ساعة ورسالة في الثانية، وإلى عناوين موثقة فقط.
  • بعد الخروج منها: تحدد AWS لحسابك حصة يومية ومعدلاً في الثانية، وتراهما في Account dashboard، والحصة اليومية محسوبة على آخر 24 ساعة متحركة وليست يوماً تقويمياً، وتطلب زيادتهما عند الحاجة. وهما لكل منطقة في الحساب، وبالتالي مشتركان بين خادم البريد والنشرات وكل التطبيقات التي ترسل من المنطقة نفسها.
  • حجم الرسالة: حتى 40 ميغابايت عبر SMTP بعد الترميز Base64، أي أن المرفق الذي حجمه 5 ميغابايت يصبح قرابة 6.85 ميغابايت في الرسالة.
  • المستلمون: 50 مستلماً في الرسالة الواحدة بين To وCC وBCC.

ماذا يعني أن يمر بريدك عبر AWS؟

يجب أن تكون صريحاً مع نفسك ومع إدارتك في هذه النقطة، فعندما تضع SES خادماً وسيطاً فإن كل رسالة يرسلها موظفوك تمر بمحتواها ومرفقاتها عبر سيرفرات AWS في المنطقة التي اخترتها، وتسجل SES بيانات كل رسالة مثل المرسل والمستلم ونتيجة التسليم. أما البريد الوارد والصناديق والأرشيف فتبقى على سيرفرك، وهذا ما يجعل هذا الحل وسطاً بين الاستضافة الكاملة وبين نقل البريد كله إلى خدمة سحابية. وإذا كانت جهتك ملزمة بأن تبقى البيانات داخل بلد معين، فتذكر أن SES ليس لها عنوان SMTP في مناطق الخليج حالياً كما ذكرنا، وأن الإعداد نفسه يعمل مع أي مزود إرسال آخر له منطقة داخل بلدك، حيث تغير في الناقل المضيف وبيانات الدخول فقط، وهذا ما فعلناه مع نطاق واحد بقي على سيرفر mailcow نفسه بناقل مختلف. وقد ناقشنا كيف تقيم الاعتماد على مزود خارجي في مقال الاستضافة الذاتية كخيار استراتيجي، ونجمع خيارات البريد كلها للمؤسسات في دليل استضافة البريد الإلكتروني للمؤسسات.

مشكلات شائعة وحلولها

أغلب الأخطاء هنا تصلك كرد SMTP من SES يظهر في سجل خادمك، وتجد معناها في جدول ردود SMTP، وفيما يلي أكثرها شيوعاً.

554 Message rejected: Email address is not verified

هذا الرد يعني أن أحد العناوين في الرسالة ليس هوية موثقة في هذه المنطقة، ويذكر الرد نفسه أسماء الهويات التي فشلت. وله ثلاثة أسباب: أن حسابك ما زال في بيئة الاختبار والمستلم غير موثق، أو أن عنوان From أو MAIL FROM من نطاق لم تتحقق منه أو تحققت منه في منطقة أخرى، أو أن النطاق فقد التحقق بعد أن اختفت سجلات DKIM كما حدث معنا. وفي الحالة الأخيرة لا تقم بتعديل الخادم الوسيط، وإنما افتح النطاق في Identities وراجع حالته، ثم أعد السجلات الثلاثة وانتظر حتى تعود الحالة إلى Verified، ثم ادفع الطابور.

535 Authentication Credentials Invalid

بيانات SMTP خاطئة، وأشهر الأسباب أن تضع المفتاح السري لمستخدم IAM بدلاً من كلمة مرور SMTP المشتقة منه، أو أن تستخدم كلمة مرور أنشأتها لمنطقة مع عنوان منطقة أخرى، أو أن يكون المستخدم قد حذف أو عطل مفتاحه. وفي Postfix تأكد أن المفتاح في sasl_passwd يطابق relayhost تماماً، وأنك شغلت postmap بعد آخر تعديل، فإذا لم يجد Postfix سطراً مطابقاً فلن يسجل الدخول أصلاً، وسوف ترى بدلاً من ذلك الرد 530 Authentication required.

cannot authenticate to server: no mechanism available

هذا خطأ من Postfix نفسه وليس من SES، ويعني أنه لم يجد آلية مصادقة يقبلها الطرفان، والسبب إما أن الحزمة libsasl2-modules غير مثبتة، أو أن smtp_sasl_security_options ما زال على القيمة الافتراضية التي تمنع PLAIN وLOGIN، فاضبطه على noanonymous.

mail for … loops back to myself

هذا يعني أن Postfix وجد أن الخادم الوسيط هو السيرفر نفسه، فرفض أن يسلم الرسالة لنفسه في حلقة لا تنتهي، وأبقاها مؤجلة. ويحدث عندما يكتب أحدهم في relayhost اسم خادم البريد نفسه أو 127.0.0.1 بدلاً من عنوان SES، أو عندما يكون في Transport Maps في mailcow قاعدة توجه نطاقاً إلى السيرفر نفسه، فراجع القيمة وأعد تحميل Postfix.

DMARC fail مع أن DKIM ناجح

افتح Show original وانظر إلى النطاق في dkim=pass، فإذا كان amazonses.com فقط دون نطاقك فإن Easy DKIM غير مفعل لهذا النطاق في هذه المنطقة، أو أنك ترسل من عنوان موثق كهوية مستقلة داخل نطاق موثق، وفي هذه الحالة تستخدم SES إعدادات العنوان وليس النطاق، والحل حذف هوية العنوان المنفردة. وإذا كان SPF هو المقصود فراجع أن smtp.mailfrom من bounce.example.com وأن سجل DMARC لا يحتوي على aspf=s، وتذكر أن حالة MAIL FROM إذا فشل سجل MX تعود إلى نطاق amazonses.com بصمت.

454 Throttling failure

الرد 454 Throttling failure: Maximum sending rate exceeded يعني أنك تجاوزت المعدل في الثانية، وDaily message quota exceeded يعني أنك استهلكت حصة آخر 24 ساعة. والردود التي تبدأ بالرقم 4 مؤقتة، فخادم البريد يعيد المحاولة تلقائياً ولا تضيع رسالة، ولكن الحل الدائم أن تحدد سرعة النشرات والحملات، وأن تطلب زيادة الحصة قبل أي إرسال كبير وليس أثناءه.

حالة DKIM تبقى Pending

نفذ dig على أحد الأسماء الثلاثة، فإذا لم يعد شيئاً فالسجل لم ينشر أو كتب باسم مكرر مثل …example.com.example.com، وإذا عاد بعنوان IP بدلاً من اسم ينتهي بـ dkim.amazonses.com فال Proxy في Cloudflare مفعل على السجل. أصلح السبب وانتظر، فـ SES تعيد الفحص تلقائياً.

الخلاصة

وصلنا لنهاية الموضوع، وأهم ما فيه:

  • SES يرسل فقط، فيبقى سجل MX والمنفذ 25 الوارد والصناديق على سيرفرك، ويخرج البريد الصادر على المنفذ 587 مع STARTTLS ببيانات SMTP.
  • تحقق من النطاق كله بـ Easy DKIM، واضبط MAIL FROM على نطاق فرعي مثل bounce.example.com، فيجتاز بريدك DMARC بطريقين، ولا تحتاج إلى include:amazonses.com في سجل SPF للنطاق الرئيسي.
  • كل شيء في SES لمنطقة واحدة: الهويات وبيانات SMTP وبيئة الاختبار والحصة، ولا توجد عناوين SMTP حالياً في البحرين والإمارات.
  • أنشئ لكل خادم مستخدم SMTP لا يملك إلا ses:SendRawEmail مقيداً بعنوان From، وكلمة مرور SMTP ليست المفتاح السري.
  • اربط الارتدادات والشكاوى بـ SNS لأي نظام يرسل إلى قوائم، فنسبة ارتداد 5% أو شكاوى 0.1% تضع حسابك كله تحت المراجعة.
  • في Postfix استخدم smtp_tls_security_level = secure مع smtp_sasl_security_options = noanonymous، وفي mailcow ناقلاً حسب المرسل على المنفذ 587، وفي Stalwart مساراً من النوع Relay مع startTls بقيمة require.
  • لا تحذف سجلات DKIM بعد التحقق، فاختفاؤها يسقط التحقق ويظهر بالخطأ 554 … not verified بعد أيام.

وإذا كنت ما زلت تختار خادم البريد نفسه فاقرأ مقارنة mailcow وStalwart وPostfix، وإذا كنت تنقل البريد بين سيرفرين فراجع دليل ترحيل البريد بين خادمي mailcow وتذكر أن تنقل إعداد الناقل وسجلات DNS معه.

تدريب عملي

  • أرسل من خادمك رسالة إلى [email protected]، ثم تتبع أين وصلت رسالة الارتداد: هل وصلت إلى صندوق المرسل عبر Email Feedback Forwarding، أم إلى SNS، أم إلى الاثنين؟
  • غير في Postfix المستوى إلى encrypt وأرسل رسالة، ثم قارن سطر TLS في السجل مع المستوى secure، وابحث عن الفرق بين Verified وUntrusted.

سجل التحديثات

  • أكتوبر 2026: كتابة الدليل واختبار إعداد Postfix 3.8.6 على Ubuntu 24.04 مع خادم وسيط محلي بالمصادقة وSTARTTLS، ومراجعة خطوات SES وmailcow وStalwart 0.16 مع التوثيق الرسمي.
نشرة عرب رووت | ArabRoot

معرفة تستحق مكاناً في بريدك.

مقالات مختارة وأدوات مفيدة وأفكار لمشروعك القادم، في رسالة واحدة كل أسبوع.

يمكنك إلغاء الاشتراك متى شئت. الخصوصية

تم استلام طلبك. افتح بريدك واضغط رابط التأكيد لإتمام الاشتراك.