البريد الوارد · 22 سبتمبر 2026

كيفية استقبال البريد الإلكتروني باستخدام Amazon SES: ‏S3 وLambda

ابنِ مسار بريد وارد جاهزًا للإنتاج باستخدام Amazon SES وS3 وLambda، يشمل أمان MIME وتوجيه المستأجرين وعدم التكرار وإعادة المحاولات وتسلسل الرسائل.

أقصر مسار وارد موثوق في Amazon SES هو: وثّق نطاقًا، ووجّه سجل MX إلى نقطة استقبال SES، واحفظ كل رسالة مقبولة في S3، ثم استدعِ Lambda بشكل غير متزامن لتحليلها وحفظها. ضع إجراء S3 قبل إجراء Lambda. تعامل مع معرّف رسالة SES بوصفه مفتاح عدم تكرار، واستخدم مستلِم ظرف SMTP للتوجيه، وضع المحتوى غير الآمن في الحجر بدلًا من الوثوق بالترويسات أو المرفقات.

البنية التي ينبغي بناؤها

استخدم نطاقًا فرعيًا مخصصًا مثل inbound.example.com ما لم يكن ينبغي أن تستقبل SES كل البريد الخاص بنطاقك الجذري. فهذا يفصل بريد التطبيق عن صناديق بريد الموظفين ويجعل التراجع تغييرًا في DNS بدلًا من ترحيل بريد.

مسار الإنتاج هو:

sender -> SES inbound SMTP endpoint -> active SES receipt rule -> S3 raw-message object -> asynchronous Lambda action -> MIME parser and policy checks -> application database and private attachment storage

تنفّذ قواعد الاستقبال في Amazon SES إجراءاتها بالترتيب. وتوثّق AWS صراحةً نمط S3 أولًا ثم Lambda ثانيًا عندما تحتاج الشيفرة إلى جسم الرسالة. أما إجراء Lambda المباشر فيتلقى البيانات الوصفية وترويسات مختارة، لا الجسم الكامل. ويبقى الجسم كائن MIME الخام في S3 (مفاهيم الاستقبال في AWS SES).

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

1. اختر منطقة مدعومة ووثّق النطاق

استقبال البريد في SES متاح في مناطق AWS محددة فقط. اختر منطقة من قائمة نقاط استقبال SES الحالية، ثم أبقِ موارد SES وLambda وSNS وKMS في تلك المنطقة ما لم تسمح وثائق AWS ذات الصلة بخلاف ذلك صراحةً.

أنشئ هوية نطاق في SES للنطاق الجذري أو الفرعي الذي سيستقبل البريد تحديدًا. ويتطلب توثيق النطاق نشر سجلات DNS التي توفرها SES. والتوثيق لأغراض الاستقبال يثبت التحكم في النطاق؛ وهو منفصل عن ضبط مسار MX الذي يوجّه الحركة الواردة إلى SES (دليل توثيق النطاق في AWS).

بالنسبة إلى نطاق فرعي مخصص، تبدو سجلات DNS من الناحية المفاهيمية هكذا:

inbound.example.com. MX 10 inbound-smtp.us-east-1.amazonaws.com.

استبدل us-east-1 بالمنطقة التي اخترتها. وتوثّق AWS قيمة MX على أنها 10 inbound-smtp.<region>.amazonaws.com (دليل سجل MX في AWS). لا توجّه نطاقك الجذري إلى SES إذا كان الأشخاص ما زالوا يستقبلون البريد عليه عبر Google Workspace أو Microsoft 365 أو مزوّد صندوق بريد آخر.

تحقق من السجل المنشور عبر أكثر من محلّل DNS قبل الاختبار:

dig MX inbound.example.com +short

ظهور DNS يثبت فقط أن المسار منشور. أرسل رسالة اختبار مضبوطة إلى عنوان تجريبي وتأكد من أن SES خزّنتها قبل أن تعدّ الإعداد مكتملًا.

2. احفظ الرسالة الخام قبل معالجتها

أنشئ حاوية S3 خاصة مع حظر الوصول العام وسياسة دورة حياة وأضيق أذونات IAM عمليًا. ثم أنشئ قاعدة استقبال في SES يطابق شرط المستلِم فيها نطاقك الوارد أو عناوين محددة.

ينبغي أن يسلّم الإجراء الأول الرسالة الخام إلى S3. وتسهّل بادئة كائن مثل inbound/ تحديد قواعد الاحتفاظ وسياسات الوصول. وتخزّن SES محتوى MIME الخام دون تعديل. وتوثّق AWS حاليًا حدًا أقصى افتراضيًا قدره 40 MB عند حفظ الرسائل في S3، بينما يبلغ الحد الأقصى لإجراء SNS الذي يتضمن الرسالة الكاملة 150 KB فقط (إجراء الاستقبال S3 في AWS). وهذا الفارق في الحجم هو سبب كون S3 الخيار الافتراضي الأكثر أمانًا للردود والمرفقات في الواقع العملي.

إذا فعّلت إعداد SES KMS الاختياري على قاعدة الاستقبال، فاقرأ تفاصيل التشفير بعناية. فتستخدم SES تشفيرًا من جهة العميل لهذه الميزة، لا تشفير S3 العادي من جهة الخادم، لذا يجب أن يفكّ قارئك تشفير الكائن باستخدام عميل متوافق. لا تفعّلها باستخفاف ثم تكتشف أثناء حادث أن محلّل Node لديك لا يستطيع قراءة البايتات المخزّنة.

امنح SES إذن الكتابة إلى الحاوية والبادئة المقصودتين فقط. وامنح Lambda الإذن s3:GetObject على الموقع نفسه فقط. لا تحتاج الدالة إلى أذونات إدارة الحاوية.

3. أضف إجراء Lambda غير متزامن

ضع إجراء Lambda بعد إجراء S3 في قاعدة الاستقبال واستخدم الاستدعاء غير المتزامن ما لم يكن على الدالة أن تقرر هل ينبغي أن تواصل SES تقييم القاعدة. وتوصي AWS بالتنفيذ غير المتزامن للمعالجة العادية وتخصّص التنفيذ المتزامن لقرارات تدفق البريد (إجراء الاستقبال Lambda في AWS).

ويكون mail.messageId الذي تعيّنه SES هو أيضًا مفتاح كائن S3 عند عدم ضبط بادئة. وعند وجود بادئة، ألحِقها في البداية. يجلب هيكل Node.js التالي الرسالة الخام ويحلّلها. ضمّن الحزمة @aws-sdk/client-s3 ومحلّل MIME مُصانًا مثل mailparser في حزمة النشر، وثبّت إصداراتهما.

import { GetObjectCommand, S3Client } from "@aws-sdk/client-s3"; import { simpleParser } from "mailparser"; const s3 = new S3Client({}); const bucket = process.env.INBOUND_BUCKET; const prefix = process.env.INBOUND_PREFIX || "inbound/"; export async function handler(event) { for (const record of event.Records || []) { const ses = record.ses; const messageId = ses?.mail?.messageId; const recipients = ses?.receipt?.recipients || []; if (!messageId || !/^[A-Za-z0-9._-]+$/.test(messageId)) { throw new Error("Missing or invalid SES message ID"); } // claimOnce must be an atomic insert with a unique constraint. if (!(await claimOnce(messageId))) continue; try { const object = await s3.send(new GetObjectCommand({ Bucket: bucket, Key: `${prefix}${messageId}`, })); const raw = Buffer.from(await object.Body.transformToByteArray()); const parsed = await simpleParser(raw, { skipHtmlToText: true, skipTextToHtml: true, }); await saveInboundMessage({ providerMessageId: messageId, envelopeRecipients: recipients, envelopeFrom: ses.mail.source, headerMessageId: parsed.messageId || null, inReplyTo: parsed.inReplyTo || null, references: parsed.references || [], subject: parsed.subject || "", text: parsed.text || "", html: parsed.html || null, attachments: parsed.attachments, receivedAt: ses.mail.timestamp, }); await markComplete(messageId); } catch (error) { await releaseOrMarkFailed(messageId, String(error)); throw error; } } }

تمثّل الدوال النائبة تخزينًا خاصًا بالتطبيق، لكن عقدها مهم. يجب أن تستخدم claimOnce قيد تفرّد في قاعدة البيانات أو كتابة مشروطة على معرّف رسالة المزوّد. فالقراءة متبوعة بإدراج عُرضة لحالات التسابق. خزّن حالة المعالجة ليتمكن المشغّل من التمييز بين processing وcomplete وquarantined وfailed.

وجّه باستخدام مستلِم الظرف، لا ترويسة To

الحقلان To وCc المرئيان جزء من محتوى الرسالة يقدّمه المُرسِل. وقد يغفلان الوجهة الفعلية بسبب BCC أو إعادة التوجيه أو التلاعب المتعمد. وتستخدم شروط الاستقبال في SES مستلِمي ظرف SMTP، وتطلب AWS من المعالجات اللاحقة استخدام المستلِمين الواردين في إشعار SES عند تحديد الجهة التي سُلِّمت إليها الرسالة (مفاهيم الاستقبال في AWS).

هذا التمييز يمنع خللًا عابرًا للمستأجرين. فإذا استقبل reply+tenant-a@inbound.example.com رسالة تقول ترويسة To المرئية فيها tenant-b@example.com، فوجّهها باستخدام ربط التطبيق الموثَّق لعنوان الظرف، وليس بترويسة العرض أبدًا.

استخدم رمز رد عشوائيًا يصعب تخمينه عندما يحدد العنوان عميلًا أو محادثة. وخزّن تجزئة الرمز عند التخزين، واجعله ينتهي عند الاقتضاء، وارفض العناوين التي لا ترتبط بمساحة عمل نشطة. فالجزء المحلي المتوقع مثل ticket-42 دعوة لحقن رسائل في سلسلة مستخدم آخر.

حلّل MIME بوصفه مُدخلًا عدائيًا

البريد الإلكتروني صيغة إدخال متداخلة عمرها عقود. يحدد RFC 5322 ترويسات الرسائل وأجسامها، بينما يضيف MIME المحتوى متعدد الأجزاء وترميزات النقل (RFC 5322، RFC 2045). استخدم محلّلًا مُصانًا بدلًا من التقسيم عند الأسطر الفارغة أو الحدود بنفسك.

طبّق الحدود قبل إتاحة المحتوى للمنتج:

  • ضع سقفًا لإجمالي البايتات بعد فك الترميز، وعدد المرفقات، وحجم كل مرفق، وعمق تداخل MIME، وزمن التحليل.
  • خزّن المرفقات بشكل خاص بأسماء كائنات مولّدة. لا تستخدم اسم ملف المُرسِل مسارًا أبدًا.
  • تعامل مع نوع المحتوى المعلَن واسم الملف بوصفهما تلميحات. واكتشف النوع من المحتوى حيثما أمكن.
  • لا تنفّذ محتوى المرفقات أبدًا. افحص المرفقات أو ضعها في الحجر قبل تنزيلها.
  • نقِّ HTML بقائمة سماح صارمة، واحظر الصور البعيدة افتراضيًا، واعرضه في سياق معزول. وفضّل النص العادي للتحليل الآلي.
  • لا تضع الأجسام الخام أو العناوين أو الرموز أو محتوى المرفقات في سجلات التطبيق العادية.

يمكن لـ SES الإبلاغ عن أحكام SPF وDKIM وDMARC والبريد المزعج والفيروسات، لكن AWS تشير إلى أن SES تكشف هذه النتائج ولا تطبّق سياسة عملك تلقائيًا. قرر هل ينبغي رفض الإخفاقات أو وضعها في الحجر أو عرضها مع تحذير. فاجتياز المصادقة يحدد نطاقًا بموجب آلية معينة؛ ولا يجعل المحتوى آمنًا ولا يثبت أن إنسانًا كتبه.

اجعل إعادة المحاولات مملة

يمكن للاستدعاء غير المتزامن لـ Lambda إعادة محاولة الدوال الفاشلة، وتحذّر AWS من أن التسليم المكرر ممكن حتى عندما لا تعيد الدالة خطأ. اضبط وجهة عند الفشل أو طابور رسائل ميتة (dead-letter queue) وأنشئ تنبيهًا لإخفاقات المعالجة (سلوك إعادة المحاولة في AWS Lambda).

ينبغي أن يغطي عدم التكرار كل أثر جانبي لاحق:

  1. أدرج معرّف رسالة SES تحت قيد تفرّد.
  2. احفظ المحتوى المحلَّل وروابط السلسلة في معاملة واحدة حيثما أمكن.
  3. ضع الإشعارات أو إنشاء التذاكر أو عمل الوكلاء في صندوق صادر (outbox) مفتاحه معرّف الرسالة مضافًا إليه نوع الإجراء.
  4. علِّم السجل مكتملًا فقط بعد نجاح عمليات الكتابة الدائمة.
  5. أعد المعالجة من كائن S3 الأصلي، لا من مدخل سجل مفقود التفاصيل.

وإذا كنت تُطلق المعالجة من إشعارات S3 بدلًا من إجراء Lambda في SES، فتنطبق القاعدة نفسها. فإشعارات Amazon S3 مصمَّمة للتسليم مرة واحدة على الأقل ولا يُضمَن وصولها بالترتيب (إشعارات أحداث S3 في AWS).

اربط الرسائل في سلسلة دون الوثوق بالموضوع

استخدم الحقول المحلَّلة Message-ID وIn-Reply-To وReferences لاقتراح مطابقة السلسلة. لا تربط في سلسلة بالاعتماد على موضوع يبدأ بـ Re: وحده. وتأكد أيضًا من أن عنوان الظرف أو رمز الرد ينتمي إلى مساحة العمل والمحادثة نفسيهما قبل ربط أي شيء.

تحتاج الردود التلقائية إلى سياسة منفصلة. اكتشف إشارات مثل Auto-Submitted وتجنب توليد حلقات ردود. ويوصي RFC 3834 بالتعريف الواضح والسلوك المحافظ للاستجابات التلقائية (RFC 3834). وإذا صاغ وكيل ذكاء اصطناعي ردًا، فأبقِ الإرسال أثرًا جانبيًا صريحًا وغير مكرَّر. واشترط موافقة المستخدم عند وجود مستلِمين غير متوقعين أو محتوى حساس أو إجراءات خارج سير عمل الدعم أو المنتج الأصلي. واستقبال رسالة ليس موافقة شاملة على تسويق غير ذي صلة.

قائمة التحقق للإنتاج

  • منطقة الاستقبال تدعم البريد الوارد في SES.
  • هوية النطاق موثَّقة وسجل MX يُحلّ بشكل صحيح.
  • تتضمن قاعدة الاستلام شرطًا ضيقًا للمستلِم ومجموعة القواعد المقصودة نشطة.
  • يُنفَّذ إجراء S3 قبل معالجة Lambda غير المتزامنة.
  • الحاوية خاصة، والوصول وفق أقل الصلاحيات، والاحتفاظ موثَّق.
  • يتضمن معرّف رسالة SES قيدًا فريدًا في قاعدة البيانات.
  • يستخدم التوجيه مستلِمي الظرف (envelope)، وليس ترويستي To أو Cc الظاهرتين.
  • تُعامل MIME وHTML والروابط والمرفقات كمدخلات غير موثوقة.
  • تصل الأحداث الفاشلة إلى وجهة خاضعة للمراقبة ويمكن إعادة تشغيلها.
  • تفرض مطابقة سلسلة الرسائل ملكية مساحة العمل.
  • تحتوي الردود التلقائية على منع للحلقات وضوابط للموافقة وعدم تكرار للإرسال.
  • يغطي اختبار مضبوط النص العادي وHTML وBCC والتسليم المكرر والمرفقات الكبيرة وMIME المشوّه وفشل المحلل.

SES المباشر خيار مناسب عندما يريد فريقك تحكمًا أصليًا في AWS ومستعد لتولّي DNS وIAM وتحليل MIME وعزل المستأجرين والاحتفاظ ومعالجة إعادة المحاولة وتنبيهات التشغيل. وإذا أردت هذه العناصر الأساسية للتطبيق خلف واجهة API للبريد أضيق نطاقًا، فإن SendHQ توفّر عناوين واردة ورسائل محتفَظًا بها وسلاسل ووصولًا على مستوى مساحة العمل إلى جانب البريد المعاملاتي الصادر. وفي الحالتين، أبقِ الرسالة الخام قابلة للاسترداد واجعل كل إجراء لاحق آمنًا عند إعادة التشغيل.