كيف ترسل البريد من Cloudflare Workers
لا يستطيع Worker تشغيل خادم بريد، لكنه يستطيع التحدث إلى خادم بريد. إليك ما ينجح وما يفشل ولماذا، من تجربة بناء MakiSend، وهو API بريد يعمل بالكامل على Workers.
آخر تحديث · نسخة Markdown (بالإنجليزية)
ثلاث طرق للإرسال
أمام Worker ثلاثة منافذ للخروج. اختر بحسب الجهة التي تريد الاعتماد عليها، لا بحسب الشيفرة: فالشيفرة قصيرة في كل الحالات.
| الطريقة | كيف يرسل Worker | ما تحتاج إليه | انتبه إلى |
|---|---|---|---|
| API بريد عبر HTTP | fetch() إلى API المزوّد | حساب ومفتاح API لدى ذلك المزوّد | صيغة طلبات مزوّد واحد، وسعره لكل رسالة |
| SMTP عبر TCP | nodemailer (مع nodejs_compat) على مقابس TCP من Cloudflare | بيانات اعتماد SMTP من أي مزوّد أو صندوق بريد | المنافذ المسموح بها، ووضع TLS، ورحلة ذهاب وإياب لكل أمر SMTP |
| Cloudflare Email Service | ربط send_email | نطاق مرسِل مُضاف إلى Email Sending | الإرسال إلى أي مستلم يتطلب Workers Paid |
SMTP هو الخيار الذي يُبقيك حرًّا في التنقل: الشيفرة نفسها ترسل عبر Google Workspace أو Zoho أو Microsoft 365 أو Amazon SES أو SendGrid أو Mailgun أو Postmark أو Brevo أو SMTP الخاص بـ Resend. وهو أيضًا الخيار الذي فيه فخاخ.
منافذ SMTP التي يستطيع Worker استخدامها
تحظر Cloudflare الاتصالات الصادرة على المنفذ 25، لذا لا يستطيع Worker التسليم مباشرة إلى خادم MX لدى المستلم. عليه أن يسلّم الرسالة إلى خادم إرسال، على أحد هذه المنافذ:
| المنفذ | الأمان | المعنى |
|---|---|---|
| 465 | TLS ضمني (tls) | TLS من أول بايت |
| 587 | STARTTLS (starttls) | يبدأ بنص واضح ثم يرتقي إلى TLS قبل المصادقة |
| 2465 | TLS ضمني (tls) | بديل للمنفذ 465 يقدمه بعض المزوّدين |
| 2525, 2587 | STARTTLS (starttls) | بدائل للمنفذ 587 يقدمها بعض المزوّدين |
| 25 | لا شيء | محظور على Workers |
اقرن المنفذ بالوضع الصحيح. المنفذ 465 مع STARTTLS، أو 587 مع TLS ضمني، يفشل أثناء مصافحة TLS (wrong version number)، قبل إرسال أي بيانات اعتماد. يرفض MakiSend المنفذ 25 عند حفظ الإعداد ويستنتج الوضع من المنفذ.
تشغيل nodemailer على Workers
يعمل nodemailer على Workers بمجرد تفعيل علم التوافق nodejs_compat: إذ يُربط node:net وnode:tls بمقابس TCP من Cloudflare. ومع ذلك أوقعتنا ثلاثة أمور.
- يحلّ nodemailer اسم المضيف ثم يتصل بعنوان IP. ويرفض workerd الاتصال بعنوان IP مع TLS ضمني على المنفذ 465 (
proxy request failed, cannot connect to the specified address)، بينما يُفتح الخادم نفسه باسمه دون مشكلة. ولا تقول رسالة الخطأ شيئًا عن السبب الحقيقي. - الدالتان
dns.resolve4وdns.resolve6غير مطبّقتين في التطوير المحلي، لذا قد يتوقف النقل الافتراضي تحتwrangler dev. - من دون
family: 4يسجّل workerd تحذيرات شبكة عند كل إرسال.
حل المشكلتين الأوليين هو خيار getSocket في nodemailer: افتح المقبس بنفسك، باسم المضيف، ثم سلّمه إليه. يظل nodemailer يشغّل STARTTLS عند الحاجة ويتحقق من الشهادة مقابل اسم المضيف.
تضيف نسخة MakiSend مهلة زمنية، ويستخدمها كلٌّ من فحص الاتصال والإرسال التجريبي والإرسال الفعلي: smtp-connection.ts.
تتحدث Cloudflare Email Service بروتوكول SMTP أيضًا على smtp.mx.cloudflare.net، لكن Worker لا يستطيع فتح مقبس إلى ذلك المضيف. من داخل Worker، أرسل عبر ربط send_email بدلًا من ذلك.
لا ترسل داخل الطلب
ينتظر SMTP ردًّا على كل أمر: TCP، TLS، EHLO، AUTH، MAIL FROM، RCPT TO، DATA، QUIT. على Workers يستغرق الإرسال من 300 إلى 400 ms في أفضل الحالات ونحو ثانيتين في أسوئها، ويفتح Worker اتصالًا جديدًا لكل رسالة. لا ينبغي أن ينتظر المستخدم ذلك، ولا ينبغي أن يضيع إرسال فاشل.
- أجب بـ
202 Acceptedفور حفظ الرسالة، ثم ضع معرّفها في Cloudflare Queue. - أرسل من Cloudflare Workflow: كل خطوة دائمة، فتستأنف إعادة المحاولة من حيث توقف التشغيل.
- لا تُعِد إلا ما يمكن أن ينجح لاحقًا. يقوم MakiSend بمحاولة واحدة وثلاث إعادات بفاصل 30 ثانية؛ وتتوقف أخطاء المصادقة وTLS وDNS والإعداد و5xx فورًا، وتذهب الرسالة التي استنفدت محاولاتها إلى طابور الرسائل الميتة.
- اقبل ترويسة
Idempotency-Keyحتى لا يرسل العميل الذي يعيد طلبه الرسالة مرتين.
انتظار الشبكة لا يُحتسب ضمن حد المعالج (10 ms لكل استدعاء على Workers Free)، لذا يتسع الإرسال نفسه للخطة المجانية. تتبع صفحة البنية رسالة واحدة عبر هذه الخطوات.
عناوين IP الثابتة وصندوق الوارد
- تتصل Workers من عناوين Cloudflare مشتركة ومتغيرة. المزوّد الذي لا يقبل إلا عناوين IP من قائمة سماح سيرفض الاتصال: أوقف قائمة السماح واعتمد على بيانات اعتماد SMTP، أو أرسل من خادم بعنوان IP ثابت.
- وصول البريد إلى صندوق الوارد يعتمد على نطاق المرسِل (SPF وDKIM وDMARC) وسمعة المزوّد، لا على Worker. في اختباراتنا، تصل رسائل MakiSend إلى صندوق الوارد بعد ضبط هذه السجلات الثلاثة.
- تضع Gmail وGoogle Workspace حدًّا لما يرسله صندوق بريد واحد يوميًا. للأحجام الكبيرة، استخدم مزوّدًا للبريد المعاملاتي.
أو دع MakiSend يتولى الأمر
MakiSend هو كل ما في هذه الصفحة، جاهزًا: POST /send-email موثّق، وطابور، وWorkflow دائم مع إعادة المحاولة، وnodemailer على مقابس تُفتح باسم المضيف، وربط Cloudflare Email Service، ولوحة تحكم فيها السجلات. وهو مفتوح المصدر ويُنشر على حساب Cloudflare الخاص بك، حتى لو كان حساب Workers Free.
- مع وكيل برمجة: انسخ موجّه التثبيت والصقه في Claude Code أو Codex أو Cursor أو أي وكيل آخر.
- من دون وكيل: Deploy to Cloudflare، بعد توليد السرّين اللذين يطلبهما.
- اقرأ الشيفرة أولًا: github.com/lixalistudio-oss/makisend.
أسئلة
هل يستطيع Cloudflare Worker إرسال البريد عبر SMTP؟
نعم. مع علم nodejs_compat يعمل nodemailer على مقابس TCP من Cloudflare ويتحدث إلى أي مزوّد SMTP على المنافذ 465 أو 587 أو 2465 أو 2525 أو 2587. المنفذ 25 محظور.
لماذا لا يعمل المنفذ 25 من Worker؟
تحظر Cloudflare الاتصالات الصادرة على المنفذ 25. استخدم منفذ الإرسال لدى مزوّدك بدلًا منه: 465 مع TLS ضمني أو 587 مع STARTTLS.
لماذا يفشل nodemailer برسالة "proxy request failed" على المنفذ 465؟
يتصل nodemailer بعنوان IP الذي حلّه، ويرفض workerd استخدام TLS ضمني مع عنوان IP مجرد. افتح المقبس باسم المضيف عبر خيار getSocket في nodemailer.
هل أستطيع استخدام Cloudflare Email Service على الخطة المجانية؟
ليس للإرسال إلى أي مستلم: فذلك يتطلب Workers Paid ($5 شهريًا). على Workers Free، أرسل عبر مزوّد SMTP آخر.