> ## Content Index
> Fetch the complete content index at: https://arabroot.io/llms.txt
> Use this file to discover other available public pages before exploring further.

# كيف يعمل البريد الإلكتروني؟ SMTP وIMAP للمبتدئين
- URL: https://arabroot.io/articles/كيف-يعمل-البريد-الالكتروني-smtp-و-imap/
- Published: 2026-10-05T17:45:00.000Z
- Updated: 2026-10-12T11:35:14.000Z
- Description: ماذا يحدث بين ضغطك على «إرسال» ووصول الرسالة، ولماذا ترتد بعض الرسائل، وأي منفذ تفتح لكل غرض.
- Author: فريق عرب رووت
- Tags: الأدلة التقنية, الاستضافة الذاتية والتطبيقات, البريد الإلكتروني, الشبكات والوصول, الاستضافة الذاتية

تكتب رسالة في برنامج البريد وتضغط «إرسال»، فتصل إلى صاحبها في Gmail خلال ثوان، وفي يوم آخر تعود إليك بعد ساعات برسالة إنجليزية طويلة فيها أرقام مثل `550 5.1.1`، أو تبقى «معلقة» دون أن تعرف أين هي. ثم تقرأ دليل تثبيت خادم بريد فيطلب منك أن تفتح المنافذ 25 و587 و993، وأن تتأكد من أن مزود السيرفر لا يحجب المنفذ 25، وأن تضبط سجل MX، وكل ذلك دون أن يشرح لماذا يحتاج البريد كل هذه الأبواب. وهذا المقال هو الأساس الذي تبنى عليه بقية مقالات البريد على الموقع: كيف تنتقل الرسالة فعلاً من جهاز إلى جهاز، وما الذي يقوله كل طرف للآخر، وأي منفذ لأي غرض، ثم نرى ذلك كله بأعيننا في مختبر صغير على جهازك لا تخرج منه أي رسالة إلى الإنترنت. وإذا كنت تبني بريد مؤسستك فالصورة الكاملة والقرار في دليل [كيف تستضيف بريد مؤسستك بنفسك](https://arabroot.io/articles/%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D8%B3%D8%AA%D8%B6%D8%A7%D9%81%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%8A%D8%AF-%D8%A7%D9%84%D8%A5%D9%84%D9%83%D8%AA%D8%B1%D9%88%D9%86%D9%8A-%D9%84%D9%84%D9%85%D8%A4%D8%B3%D8%B3%D8%A7%D8%AA/).

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

- الطريق الذي تقطعه رسالة واحدة من المرسل إلى المستلم، والبرامج التي تمر بها وأسماؤها: MUA وMSA وMTA وMDA، ودور سجل MX.
- بروتوكول SMTP كمحادثة نصية: الأوامر `EHLO` و`MAIL FROM` و`RCPT TO` و`DATA`، وأرقام الردود، ولماذا يعني الرد 4xx «حاول لاحقاً» والرد 5xx «لا تحاول أبداً».
- الطابور وإعادة المحاولة Queue and Retry، والرسائل المرتدة Bounces، والفرق بين عنوان الظرف Envelope وعنوان الرسالة Header.
- المنافذ 25 و587 و465 و993 و995 و143 و110، والفرق بين STARTTLS والتشفير المباشر Implicit TLS، ولماذا يحجب مزودو السيرفرات المنفذ 25.
- قراءة البريد عبر IMAP وPOP3 وJMAP، والفرق بينها في الواقع اليومي.
- إعادة استخدام اتصال SMTP لإرسال رسائل كثيرة، في كود تطبيقك وفي Postfix نفسه، وحدود السيرفرات المستقبلة التي تجعل الاتصالات الكثيرة مشكلة.
- مختبر حقيقي بـ Postfix وDovecot وMailpit، ثم أدوات الفحص، والأخطاء الشائعة، وقائمة تحقق.

## ماذا يحدث بعد أن تضغط «إرسال»؟

البريد الإلكتروني يشبه البريد العادي أكثر مما تتوقع، فأنت لا تسلم الرسالة لصاحبها يداً بيد، وإنما تضعها في مكتب البريد القريب منك، وهذا المكتب يعرف من الدليل أين مكتب البريد في مدينة المستلم فيرسلها إليه، ثم يضعها ذلك المكتب في صندوق المستلم، وصاحب الصندوق يفتحه متى شاء. وكل خطوة من هذه الخطوات يقوم بها برنامج مختلف له اسم في المعيار [RFC 5598](https://www.rfc-editor.org/rfc/rfc5598.html?ref=arabroot.io) الذي يصف بنية البريد على الإنترنت، والصورة التالية تبين الطريق الذي تقطعه رسالة من Alice في النطاق `example.org` إلى Bob في النطاق `example.net`:

![مخطط من اليمين إلى اليسار: 1 جهاز Alice يرسل عبر المنفذ 587 مع كلمة المرور وSTARTTLS إلى سيرفر mx.example.org، 2 السيرفر يسأل DNS عن سجل MX للنطاق example.net فيعرف أنه mx.example.net، 3 يتصل به على المنفذ 25 دون كلمة مرور، 4 سيرفر المستلم يسلم الرسالة عبر LMTP إلى صندوق Bob في Dovecot، 5 هاتف Bob يقرأ الصندوق عبر IMAP على المنفذ 993، وتحتها بطاقات الأدوار MUA وMSA وMTA وMDA وبروتوكولات القراءة](https://arabroot.io/content/images/2026/10/how-email-works-01-message-path.webp)

خمس خطوات وخمسة أدوار، وفي المؤسسة الصغيرة يقوم برنامج واحد بأكثر من دور

وفيما يلي الأدوار بالترتيب كما في الصورة:

- **برنامج البريد Message User Agent، واختصاراً MUA:** البرنامج الذي يكتب فيه الإنسان رسالته ويقرأ بريده، مثل Thunderbird وOutlook وتطبيق البريد في الهاتف والبريد عبر الويب Webmail. ولاحظ أن تطبيقك الذي يرسل رسالة «تأكيد الطلب» يقوم بنفس الدور تماماً.
- **وكيل الاستلام من المستخدمين Mail Submission Agent، واختصاراً MSA:** البوابة التي يسلم إليها برنامج البريد رسالته، ويعرفها المعيار [RFC 6409](https://www.rfc-editor.org/rfc/rfc6409.html?ref=arabroot.io) على المنفذ 587، وأهم ما يميزها أنها تطلب تسجيل الدخول Authentication قبل أن تقبل أي رسالة، والسبب أنها تقبل رسائل إلى أي مكان في العالم، فلو قبلت من أي شخص لأصبح سيرفرك مرحلاً مفتوحاً Open Relay يرسل منه كل مرسلي الرسائل المزعجة Spam.
- **وكيل نقل البريد Mail Transfer Agent، واختصاراً MTA:** البرنامج الذي ينقل الرسالة من سيرفر إلى سيرفر عبر بروتوكول نقل البريد البسيط Simple Mail Transfer Protocol، واختصاراً SMTP، على المنفذ 25، مثل Postfix وExim. وفي أغلب الخوادم يكون ال MSA وال MTA برنامجاً واحداً يستمع على عدة منافذ، كما في المختبر الذي سوف نبنيه.
- **وكيل التسليم Mail Delivery Agent، واختصاراً MDA:** البرنامج الذي يكتب الرسالة في صندوق المستخدم على القرص، وفي المختبر هو Dovecot الذي يستلم الرسالة من Postfix عبر بروتوكول LMTP، وهو نسخة من SMTP مخصصة للتسليم المحلي.
- **بروتوكولات القراءة IMAP وPOP3 وJMAP:** الطريقة التي يقرأ بها برنامج البريد عند Bob صندوقه من السيرفر، وسوف نخصص لها [قسماً كاملاً](#reading).

### كيف يعرف السيرفر أين يرسل؟ سجل MX

في الخطوة 2 يحتاج سيرفر Alice أن يعرف أي سيرفر يستقبل بريد `example.net`، فيسأل نظام DNS عن سجل MX لهذا النطاق، وقد شرحنا هذا السجل وطريقة نشره في [مقال شرح DNS وسجلاته](https://arabroot.io/articles/%D8%B4%D8%B1%D8%AD-dns-%D9%88%D8%B3%D8%AC%D9%84%D8%A7%D8%AA%D9%87-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/#mx). والمثال التالي يبين سجلات MX للنطاق `gmail.com` كما يراها أي سيرفر يرسل إلى Gmail:

```bash
dig +short MX gmail.com
```

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

```text
5 gmail-smtp-in.l.google.com.
40 alt4.gmail-smtp-in.l.google.com.
10 alt1.gmail-smtp-in.l.google.com.
20 alt2.gmail-smtp-in.l.google.com.
30 alt3.gmail-smtp-in.l.google.com.
```

في المخرج أعلاه لاحظ التالي:

- الرقم قبل كل اسم هو الأولوية Preference، والسيرفر المرسل يبدأ بالرقم الأصغر، أي `gmail-smtp-in.l.google.com`، فإذا لم يرد ينتقل إلى الذي بعده، وبهذا الشكل يكون للنطاق سيرفرات احتياطية دون أي إعداد في الطرف المرسل.
- الترتيب الذي يطبعه `dig` ليس مهماً، فالمهم هو الرقم.
- إذا لم يكن للنطاق سجل MX أصلاً، فإن المعيار [RFC 5321](https://www.rfc-editor.org/rfc/rfc5321.html?ref=arabroot.io) يجعل السيرفر المرسل يعامل سجل A أو AAAA للنطاق نفسه كأنه سجل MX ضمني Implicit MX، لذلك فالنطاق الذي لا يستقبل بريداً أبداً ينشر ما يسمى [Null MX](https://www.rfc-editor.org/rfc/rfc7505.html?ref=arabroot.io)، وهو سجل MX بأولوية 0 واسمه نقطة فقط `.`، فيعرف كل مرسل أنه لا يوجد سيرفر بريد لهذا النطاق ولا يحاول.

## نبني نسخة صغيرة من هذا الطريق على جهازك

الشرح النظري للبريد سهل النسيان، والأفضل أن ترى كل سطر بعينك، لذلك سوف نبني مختبراً فيه الأطراف الأربعة من الصورة السابقة، كل طرف في Container على شبكة Docker خاصة، ولا يوجد أي منفذ مفتوح خارج جهازك سوى واجهة Mailpit على `127.0.0.1`، والعناوين كلها في النطاقات المحجوزة للأمثلة مثل `example.org`، وسيرفر Postfix في المختبر يرفض أي مستلم خارج النطاقين كما سيأتي، وبالتالي لا تخرج رسالة واحدة إلى الإنترنت:

- **`lab-mail-mta`:** سيرفر Postfix للنطاق `example.org`، يستقبل من السيرفرات على المنفذ 25، ومن المستخدمين على 587 و465.
- **`lab-mail-dovecot`:** سيرفر Dovecot يحفظ صناديق `example.org`، ويستلم من Postfix عبر LMTP، ونقرأ منه عبر IMAP وPOP3.
- **`lab-mail-pit`:** برنامج [Mailpit](https://mailpit.axllent.org/?ref=arabroot.io)، وهو سيرفر SMTP للاختبار يستقبل كل رسالة ويعرضها في واجهة ويب دون أن يرسلها لأحد، ويقوم هنا بدور «السيرفر الآخر على الإنترنت» للنطاق `example.net`، وفيه ميزة [Chaos](https://mailpit.axllent.org/docs/integration/chaos/?ref=arabroot.io) التي تجعله يرد بأخطاء نختارها، وهذا ما نحتاجه لنرى الطابور والرسائل المرتدة.
- **`lab-mail-client`:** جهازك أو تطبيقك، وفيه أدوات الفحص `swaks` و`openssl` و`dig` و`nc` وPython.

أنشئ مجلداً للمختبر وشهادة ذاتية التوقيع Self-signed Certificate للسيرفر الذي يمثله Mailpit:

```bash
mkdir -p mail-lab/{postfix,client,scripts,certs} && cd mail-lab
openssl req -x509 -newkey rsa:2048 -nodes -days 30 -subj /CN=mx.example.net \
  -keyout certs/key.pem -out certs/cert.pem
```

ثم الملف `compose.yaml`:

```yaml
name: lab-mail

services:
  mailpit:                         # stands in for "the other server on the internet"
    image: axllent/mailpit:v1.31.4
    container_name: lab-mail-pit
    hostname: mx.example.net
    command:
      - --smtp-tls-cert=/certs/cert.pem
      - --smtp-tls-key=/certs/key.pem
      - --smtp-auth-accept-any
      - --smtp-allowed-recipients=^[a-z0-9]+@example\.net$$
      - --enable-chaos
      - --smtp-disable-rdns
    volumes:
      - ./certs:/certs:ro
    ports:
      - "127.0.0.1:18680:8025"     # web UI and API
    networks:
      lab:
        aliases: [mx.example.net]

  dovecot:                         # mailboxes of example.org: LMTP in, IMAP and POP3 out
    image: dovecot/dovecot:2.4.5-dev
    container_name: lab-mail-dovecot
    hostname: imap.example.org
    environment:
      USER_PASSWORD: labpass       # lab only: any user, this password
    volumes:
      - ./dovecot-lab.conf:/etc/dovecot/conf.d/lab.conf:ro
    networks:
      lab:
        aliases: [imap.example.org]

  postfix:                         # the MTA of example.org: port 25, 587 and 465
    build: ./postfix
    container_name: lab-mail-mta
    hostname: mx.example.org
    depends_on: [dovecot, mailpit]
    networks:
      lab:
        aliases: [mx.example.org]

  client:                          # your laptop or your application
    build: ./client
    container_name: lab-mail-client
    hostname: laptop.example.org
    command: sleep infinity
    volumes:
      - ./scripts:/lab:ro
    networks:
      - lab

networks:
  lab:
    name: lab-mail-net
```

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

- كل Container له اسم مستعار Alias على الشبكة باسم سيرفر حقيقي الشكل، مثل `mx.example.net`، فيتصل Postfix به بالاسم كما يتصل بأي سيرفر على الإنترنت، والفرق الوحيد أننا نوجهه إليه مباشرة بدل البحث عن سجل MX كما سيأتي.
- الخيار `--smtp-allowed-recipients` يجعل Mailpit يرفض أي مستلم لا يطابق النمط، فالعنوان `ops@example.net` مقبول والعنوان `no.such.user@example.net` مرفوض لأن فيه نقطة، وهكذا نحصل على رفض دائم حقيقي عندما نحتاجه. والعلامة `$$` لأن Compose يعامل `$` كبداية متغير.
- كلمة المرور `labpass` في Dovecot تقبل أي اسم مستخدم، وهذا إعداد اختبار فقط تقدمه [وثائق Docker Image الرسمية لـ Dovecot](https://doc.dovecot.org/latest/installation/docker.html?ref=arabroot.io)، ولا يصلح لأي سيرفر حقيقي.

ال Docker Image الرسمية لـ Dovecot 2.4 تعمل دون صلاحيات root وتستمع على منافذ غير معتادة مثل 31143 لـ IMAP و31993 لـ IMAPS، ولا تفعل POP3 افتراضياً، ونضيف لها الملف `dovecot-lab.conf`:

```text
# Plain LMTP for Postfix inside the lab network (the image only offers LMTP over TLS on 31024)
service lmtp {
  inet_listener lmtp {
    port = 24
  }
}
# Postfix asks Dovecot to check passwords on 587 and 465 (SASL)
service auth {
  inet_listener sasl {
    port = 12345
  }
}
# POP3 is not enabled by default in the image
protocols {
  pop3 = yes
}
```

أما Postfix فنبنيه من حزمة Debian 13، والملف `postfix/Dockerfile` كما يلي:

```dockerfile
FROM debian:13
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
      postfix ssl-cert ca-certificates && rm -rf /var/lib/apt/lists/*
COPY start.sh /start.sh
CMD ["sh", "/start.sh"]
```

والإعداد كله في الملف `postfix/start.sh` الذي يعمل عند تشغيل ال Container:

```bash
#!/bin/sh
set -e
make-ssl-cert generate-default-snakeoil --force-overwrite   # self-signed certificate for mx.example.org
postconf -e \
  'myhostname = mx.example.org' 'mydomain = example.org' 'myorigin = example.org' \
  'mydestination = localhost' 'mynetworks_style = host' \
  'smtpd_relay_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination' \
  'virtual_mailbox_domains = example.org' \
  'virtual_transport = lmtp:inet:imap.example.org:24' \
  'transport_maps = inline:{ example.net=smtp:[mx.example.net]:1025 }' \
  'default_transport = error:5.7.1 lab: mail never leaves this machine' \
  'smtpd_sasl_type = dovecot' 'smtpd_sasl_path = inet:imap.example.org:12345' \
  'smtp_tls_security_level = may' 'smtp_tls_loglevel = 1' \
  'maillog_file = /dev/stdout' 'smtp_host_lookup = native' 'lmtp_host_lookup = native'
# 587: STARTTLS required before AUTH, then relay only for logged-in users
postconf -M submission/inet='submission inet n - n - - smtpd'
postconf -P 'submission/inet/syslog_name=postfix/submission' \
  'submission/inet/smtpd_tls_security_level=encrypt' 'submission/inet/smtpd_sasl_auth_enable=yes' \
  'submission/inet/smtpd_relay_restrictions=permit_sasl_authenticated,reject'
# 465: the same, but TLS starts with the connection (implicit TLS)
postconf -M submissions/inet='submissions inet n - n - - smtpd'
postconf -P 'submissions/inet/syslog_name=postfix/submissions' \
  'submissions/inet/smtpd_tls_wrappermode=yes' 'submissions/inet/smtpd_sasl_auth_enable=yes' \
  'submissions/inet/smtpd_relay_restrictions=permit_sasl_authenticated,reject'
# tlsproxy is needed for TLS connection reuse (smtp_tls_connection_reuse), Debian does not list it
postconf -M tlsproxy/unix='tlsproxy unix - - n - 0 tlsproxy'
postconf -F '*/*/chroot = n'
exec postfix start-fg
```

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

- `virtual_mailbox_domains` و`virtual_transport`: بريد `example.org` يسلم إلى Dovecot عبر LMTP، فهذا السيرفر هو ال MTA الذي يستقبل بريد النطاق.
- `transport_maps`: بريد `example.net` يذهب إلى Mailpit مباشرة، والأقواس المربعة حول الاسم تعني «لا تبحث عن سجل MX لهذا الاسم»، وهذا السطر هو الشيء الوحيد الذي يختلف عن سيرفر حقيقي يبحث عن MX في الخطوة 2.
- `smtp_tls_security_level = may`: عندما يرسل Postfix إلى سيرفر آخر يستخدم STARTTLS إذا عرضه السيرفر الآخر، ويرسل دون تشفير إذا لم يعرضه، وهذا ما يسمى التشفير الانتهازي Opportunistic TLS، وسوف نعود إليه في [قسم المنافذ](#ports).
- المنفذان 587 و465 يقبلان الإرسال إلى الخارج للمستخدم الذي سجل دخوله فقط، وكلمات المرور يتحقق منها Dovecot لصالح Postfix، وهو نفس التصميم الذي شرحناه في [دليل خادم Postfix وDovecot يدوياً](https://arabroot.io/articles/%D8%AE%D8%A7%D8%AF%D9%85-%D8%A8%D8%B1%D9%8A%D8%AF-postfix-%D9%88-dovecot-%D9%8A%D8%AF%D9%88%D9%8A%D8%A7/)، والفرق أن الاتصال بينهما هنا عبر الشبكة وليس عبر ملف Socket.
- `default_transport`: أي نطاق غير `example.org` و`example.net` يذهب إلى ناقل الخطأ `error`، فلو كتبت في المختبر عنواناً حقيقياً بالخطأ يرفضه Postfix فوراً ولا يحاول أن يسلمه، حتى للمستخدم الذي سجل دخوله على 587، والرد يكون كما يلي: `550 5.7.1 <someone@gmail.com>: Recipient address rejected: lab: mail never leaves this machine`.
- هذا الإعداد للمختبر فقط، فلا توجد فيه سجلات DNS ولا DKIM ولا حماية من الرسائل المزعجة، وإذا كنت تريد خادماً حقيقياً فابدأ من الدليل السابق.

وأخيراً الملف `client/Dockerfile`:

```dockerfile
FROM ubuntu:24.04
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
      swaks libnet-ssleay-perl libio-socket-ssl-perl libauthen-sasl-perl \
      openssl netcat-openbsd bind9-dnsutils curl python3 ca-certificates && rm -rf /var/lib/apt/lists/*
```

ولاحظ الحزم الثلاث التي تبدأ بـ `lib`، فبدونها يعمل swaks ولكنه يرفض STARTTLS بالرسالة `TLS not available: requires Net::SSLeay`، ولا يستطيع تسجيل الدخول. الآن نشغل المختبر:

```bash
docker compose up -d --build
docker compose ps --format 'table {{.Name}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}'
```

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

```text
NAME               IMAGE                       STATUS                    PORTS
lab-mail-client    lab-mail-client             Up 20 minutes
lab-mail-dovecot   dovecot/dovecot:2.4.5-dev   Up 20 minutes             8080/tcp, 9090/tcp, 31024/tcp, 31110/tcp, 31143/tcp, 31587/tcp, 31993/tcp, 31995/tcp, 34190/tcp
lab-mail-mta       lab-mail-postfix            Up 20 minutes
lab-mail-pit       axllent/mailpit:v1.31.4     Up 20 minutes (healthy)   127.0.0.1:18680->8025/tcp
```

لاحظ أن منافذ Dovecot مكتوبة دون عنوان، أي أنها معروضة داخل شبكة Docker فقط ولم تنشر على جهازك، وأن Mailpit وحده منشور على `127.0.0.1:18680`، فتستطيع أن تفتح `http://127.0.0.1:18680` في المتصفح وترى الرسائل التي تصل إليه. وكل الأوامر التالية ننفذها داخل ال Container الذي يمثل جهازك، فادخل إليه بالأمر `docker exec -it lab-mail-client bash`.

## SMTP: محادثة نصية بأوامر قصيرة وردود بأرقام

بروتوكول SMTP الذي يعرفه المعيار [RFC 5321](https://www.rfc-editor.org/rfc/rfc5321.html?ref=arabroot.io) هو محادثة نصية بين برنامجين، يرسل فيها المرسل أمراً قصيراً في سطر، ويرد السيرفر برقم من ثلاث خانات وجملة قصيرة، وهي نفس فكرة HTTP الذي شرحنا فيه أن [الطلب والرد رسالتان نصيتان](https://arabroot.io/articles/http-%D9%88-https-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/#messages)، والفرق أن SMTP محادثة طويلة بعدة أسطر ذهاباً وإياباً وليست طلباً واحداً ورداً واحداً. والصورة التالية تبين المحادثة كاملة كما سوف نراها بعد قليل:

![محادثة بين سيرفرين: السيرفر يرحب بالرقم 220، ثم يرسل الطرف الآخر EHLO فيرد 250 مع قائمة الإمكانيات STARTTLS وDSN وCHUNKING، ثم MAIL FROM فيرد 250، ثم RCPT TO لعنوان مقبول فيرد 250، ثم RCPT TO لعنوان في gmail.com فيرد بالأحمر 554 Relay access denied، ثم DATA فيرد 354، ثم الرؤوس والنص وسطر فيه نقطة فيرد 250 queued، ثم QUIT فيرد 221، مع قوس يجمع MAIL FROM وRCPT TO باسم الظرف envelope وقوس على المحتوى content، وتحتها مفتاح الألوان 2xx و3xx و4xx و5xx](https://arabroot.io/content/images/2026/10/how-email-works-02-smtp-conversation.webp)

أوامر المرسل على اليمين وردود السيرفر على اليسار، والظرف يرسل قبل المحتوى وبأوامر منفصلة

والجدول التالي يجمع الأوامر التي تراها في كل محادثة تقريباً:

| الأمر     | ماذا يعني                                                                                                                                      |
| --------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| EHLO      | المرسل يعرف بنفسه باسم سيرفره، والسيرفر يرد بقائمة الإمكانيات التي يدعمها، مثل STARTTLS وAUTH وSIZE. والأمر الأقدم HELO يعرف بالنفس دون قائمة. |
| STARTTLS  | طلب تحويل الاتصال نفسه إلى اتصال مشفر قبل إكمال المحادثة، كما في [RFC 3207](https://www.rfc-editor.org/rfc/rfc3207.html?ref=arabroot.io).      |
| AUTH      | تسجيل الدخول باسم مستخدم وكلمة مرور، ويستخدم على منافذ الإرسال 587 و465 وليس بين السيرفرات.                                                    |
| MAIL FROM | عنوان المرسل على الظرف، وإليه تعود رسائل الفشل.                                                                                                |
| RCPT TO   | عنوان مستلم على الظرف، ويتكرر لكل مستلم، ولكل واحد رده الخاص.                                                                                  |
| DATA      | بداية محتوى الرسالة: الرؤوس Headers ثم سطر فارغ ثم النص، وينتهي المحتوى بسطر فيه نقطة واحدة فقط.                                               |
| RSET      | إلغاء الرسالة الحالية والبدء من جديد على نفس الاتصال.                                                                                          |
| QUIT      | إنهاء المحادثة وإغلاق الاتصال.                                                                                                                 |

الآن نرى ذلك على المختبر، فنرسل رسالة إلى `alice@example.org` كأننا سيرفر بريد آخر اسمه `mx.example.net`، والأداة [swaks](https://github.com/jetmore/swaks?ref=arabroot.io) تكتب كل سطر يذهب وكل سطر يعود:

```bash
swaks --server mx.example.org --port 25 --helo mx.example.net \
  --from finance@example.net --to alice@example.org \
  --h-From "Finance <finance@example.net>" --h-Subject "Invoice 1042" \
  --body "Hello Alice, the invoice is attached."
```

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

```text
=== Trying mx.example.org:25...
=== Connected to mx.example.org.
<-  220 mx.example.org ESMTP Postfix (Debian)
 -> EHLO mx.example.net
<-  250-mx.example.org
<-  250-PIPELINING
<-  250-SIZE 10240000
<-  250-VRFY
<-  250-ETRN
<-  250-STARTTLS
<-  250-ENHANCEDSTATUSCODES
<-  250-8BITMIME
<-  250-DSN
<-  250-SMTPUTF8
<-  250 CHUNKING
 -> MAIL FROM:<finance@example.net>
<-  250 2.1.0 Ok
 -> RCPT TO:<alice@example.org>
<-  250 2.1.5 Ok
 -> DATA
<-  354 End data with <CR><LF>.<CR><LF>
 -> Date: Tue, 06 Oct 2026 04:59:46 +0000
 -> To: alice@example.org
 -> From: Finance <finance@example.net>
 -> Subject: Invoice 1042
 -> Message-Id: <20261006045946.000023@laptop.example.org>
 -> X-Mailer: swaks v20240103.0 jetmore.org/john/code/swaks/
 ->
 -> Hello Alice, the invoice is attached.
 ->
 ->
 -> .
<-  250 2.0.0 Ok: queued as AFA1DB069F
 -> QUIT
<-  221 2.0.0 Bye
=== Connection closed with remote host.
```

في المخرج أعلاه لاحظ التالي:

- الأسطر التي تبدأ بـ `->` أرسلها swaks، والتي تبدأ بـ `<-` ردود Postfix. والسيرفر هو الذي يبدأ الكلام بالرقم 220 قبل أن يرسل المرسل أي شيء، وإذا اتصلت بسيرفر ولم تر هذا السطر فالمشكلة في الشبكة وليست في البريد.
- رد `EHLO` عدة أسطر، وكل سطر غير الأخير فيه شرطة بعد الرقم `250-`، والسطر الأخير فيه مسافة `250 CHUNKING`، وهكذا يعرف المرسل أن الرد انتهى. ولاحظ أن `STARTTLS` في القائمة، أي أن السيرفر مستعد للتشفير، وأن `AUTH` ليس فيها لأن المنفذ 25 لا يقبل تسجيل الدخول في إعدادنا.
- الرد `354` ليس نجاحاً نهائياً، وإنما «أكمل»، ثم يرسل swaks الرؤوس وسطراً فارغاً والنص، وينتهي المحتوى بسطر فيه نقطة وحدها، فيرد السيرفر `250 2.0.0 Ok: queued as AFA1DB069F`. وهذه النقطة البسيطة لها تاريخ أمني، فاختلاف السيرفرات في فهم نهاية المحتوى هو ما استغله هجوم تهريب SMTP الذي شرحناه في [دليل Postfix وDovecot](https://arabroot.io/articles/%D8%AE%D8%A7%D8%AF%D9%85-%D8%A8%D8%B1%D9%8A%D8%AF-postfix-%D9%88-dovecot-%D9%8A%D8%AF%D9%88%D9%8A%D8%A7/#smuggling).
- الكلمة `queued` مهمة، فالسيرفر لم يسلم الرسالة بعد، وإنما قبل مسؤوليتها ووضعها في طابوره برقم `AFA1DB069F`، وبهذا الرقم تجدها في سجلاته.

وفي سجل Postfix نرى ما حدث بعد ذلك:

```bash
docker logs lab-mail-mta 2>&1 | grep AFA1DB069F
```

```text
Oct 06 04:59:46 mx postfix/smtpd[191]: AFA1DB069F: client=lab-mail-client.lab-mail-net[192.168.80.3]
Oct 06 04:59:46 mx postfix/cleanup[196]: AFA1DB069F: message-id=<20261006045946.000023@laptop.example.org>
Oct 06 04:59:46 mx postfix/qmgr[189]: AFA1DB069F: from=<finance@example.net>, size=478, nrcpt=1 (queue active)
Oct 06 04:59:46 mx postfix/lmtp[197]: AFA1DB069F: to=<alice@example.org>, relay=imap.example.org[192.168.80.2]:24, delay=0.06, delays=0.01/0.01/0.02/0.02, dsn=2.0.0, status=sent (250 2.0.0 <alice@example.org> XxzyLEKAxGoQAAAA68ePFA Saved)
Oct 06 04:59:46 mx postfix/qmgr[189]: AFA1DB069F: removed
```

وهذه هي الخطوة 4 من الصورة الأولى: مدير الطابور `qmgr` أخذ الرسالة، وسلمها البرنامج `lmtp` إلى Dovecot الذي رد بنفس لغة الأرقام `250 2.0.0 ... Saved`، ثم حذفت من الطابور. وإذا أردت أن تكتب المحادثة بيدك حرفاً حرفاً بدل swaks، فالأمر `nc -C mx.example.org 25` يفتح الاتصال، والخيار `-C` يرسل نهاية السطر بالشكل `CRLF` الذي يطلبه المعيار، ثم تكتب الأوامر نفسها سطراً سطراً.

### ماذا تعني أرقام الردود؟

الخانة الأولى من الرد هي أهم ما فيه، فالمرسل يقرر ما يفعله بناء عليها وحدها تقريباً، والمعيار RFC 5321 يقسمها إلى أربعة أنواع:

- **2xx نجاح Positive Completion:** الأمر نفذ، مثل `250` و`221`.
- **3xx أكمل Positive Intermediate:** السيرفر ينتظر بقية البيانات، والمثال المشهور `354` بعد `DATA`.
- **4xx فشل مؤقت Transient Negative:** «ليس الآن، حاول لاحقاً»، فالمرسل يحتفظ بالرسالة ويعيد المحاولة، مثل `421` عندما يكون السيرفر مشغولاً و`451` عند خطأ مؤقت.
- **5xx فشل دائم Permanent Negative:** «لا تحاول مرة أخرى بنفس الشكل»، فالمرسل يتوقف ويخبر صاحب الرسالة، مثل `550` عندما لا يوجد صندوق بهذا الاسم و`554` عند رفض لأسباب السياسة.

وبعد الرقم ترى غالباً رقماً ثانياً بنقطتين مثل `5.7.1`، وهو رمز الحالة المفصل Enhanced Status Code من [RFC 3463](https://www.rfc-editor.org/rfc/rfc3463.html?ref=arabroot.io)، وقد أعلن عنه السيرفر في السطر `ENHANCEDSTATUSCODES`. وشكله «النوع.الموضوع.التفصيل»، فالخانة الأولى تكرر النوع نفسه، والثانية موضوع الخطأ: 1 للعنوان Addressing، و2 للصندوق Mailbox، و4 للشبكة والتوجيه Routing، و7 للأمان والسياسة Security or Policy. لذلك عندما ترى `5.1.1` فابحث في العنوان، وعندما ترى `5.7.x` فابحث في الصلاحيات أو في سجلات المصادقة مثل SPF وDMARC التي شرحناها في [مقال شرح SPF وDKIM وDMARC](https://arabroot.io/articles/%D8%B4%D8%B1%D8%AD-spf-%D9%88-dkim-%D9%88-dmarc-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/).

الآن نكسر شيئاً عن قصد، فنطلب من سيرفر `example.org`، ونحن غير مسجلين، أن يمرر رسالة إلى عنوان في `gmail.com`، أي أن يكون مرحلاً لنا:

```bash
swaks --server mx.example.org --port 25 --helo mx.example.net \
  --from finance@example.net --to someone@gmail.com --quit-after RCPT
```

```text
 -> MAIL FROM:<finance@example.net>
<-  250 2.1.0 Ok
 -> RCPT TO:<someone@gmail.com>
<** 554 5.7.1 <someone@gmail.com>: Relay access denied
 -> QUIT
<-  221 2.0.0 Bye
```

اختصرنا أسطر `EHLO` لأنها نفسها، والمهم أن السيرفر رفض المستلم برفض دائم `554 5.7.1`، وهذا هو السلوك الصحيح للمنفذ 25، فهو يقبل البريد لنطاقاته فقط. وقد يتساءل البعض: لماذا وضعنا في الإعداد السطر `smtpd_relay_restrictions` ما دام Postfix يرفض أصلاً؟ والإجابة أننا عندما شغلنا المختبر أول مرة دون هذا السطر كان الرد نفسه مؤقتاً:

```text
454 4.7.1 <someone@gmail.com>: Relay access denied
```

والسبب أن القيمة الافتراضية لهذا الإعداد في [وثائق Postfix](https://www.postfix.org/postconf.5.html?ref=arabroot.io#smtpd%5Frelay%5Frestrictions) تنتهي بـ `defer_unauth_destination`، وهي ترفض نفس الطلبات التي يرفضها `reject_unauth_destination` ولكن برمز مؤقت، وهذا الرمز المؤقت مفيد وأنت تجهز سيرفراً جديداً، فإذا أخطأت في الإعداد ورفض السيرفر بريداً كان يجب أن يقبله، فالمرسلون يعيدون المحاولة ولا تضيع رسائل، ولكنه على سيرفر يعمل فعلاً تجعل كل من يحاول استغلالك كمرحل يعيد المحاولة أياماً، لذلك بعد أن تتأكد من إعدادك اجعلها رفضاً دائماً كما في [دليل Postfix وDovecot](https://arabroot.io/articles/%D8%AE%D8%A7%D8%AF%D9%85-%D8%A8%D8%B1%D9%8A%D8%AF-postfix-%D9%88-dovecot-%D9%8A%D8%AF%D9%88%D9%8A%D8%A7/#main-cf).

### الطابور وإعادة المحاولة Queue and Retry

هنا الفرق الكبير بين البريد وبين صفحة الويب، فإذا لم يرد سيرفر الويب يظهر لك خطأ وينتهي الأمر، أما البريد فقد صمم ليصل حتى لو كان السيرفر المستقبل متوقفاً ساعات، والسبب أن كل MTA يحتفظ بطابور Queue على القرص، وعندما يتلقى رداً مؤقتاً 4xx أو لا يستطيع الاتصال أصلاً، يبقي الرسالة في الطابور ويعيد المحاولة لاحقاً. ويقول المعيار [RFC 5321](https://www.rfc-editor.org/rfc/rfc5321.html?ref=arabroot.io) في القسم 4.5.4.1 إن الفترة بين المحاولات ينبغي ألا تقل عن 30 دقيقة في العادة، وإن مدة الاستسلام تحتاج غالباً أن تكون 4 إلى 5 أيام على الأقل. والصورة التالية تبين الطريقين، المؤقت والدائم:

![صفان: في الأعلى سيرفر mx.example.org يرسل RCPT TO إلى mx.example.net فيرد 451، فتذهب الرسالة إلى الطابور deferred، ثم يعيد المحاولة بين 300 و4000 ثانية ويستسلم بعد 5 أيام، ثم يرد السيرفر 250 فتصل الرسالة دون أن تضيع، وفي الأسفل يرد السيرفر 550 لعدم وجود الصندوق، فينشئ السيرفر المرسل رسالة مرتدة DSN بعنوان MAIL FROM فارغ ويرسلها إلى Return-Path فتصل إلى صندوق Alice بعنوان Undelivered Mail Returned to Sender مع Status 5.1.0 وAction failed](https://arabroot.io/content/images/2026/10/how-email-works-03-4xx-5xx.webp)

الرد المؤقت يبقي الرسالة في الطابور، والرد الدائم ينشئ رسالة مرتدة إلى صاحبها

ولنرى الطابور بأعيننا نطلب من Mailpit أن يرد على كل مستلم بالرمز المؤقت 451 عبر واجهته البرمجية API:

```bash
curl -s -X PUT -H 'Content-Type: application/json' \
  -d '{"Recipient":{"ErrorCode":451,"Probability":100}}' http://mx.example.net:8025/api/v1/chaos
```

```text
{"Sender":{"ErrorCode":451,"Probability":0},"Recipient":{"ErrorCode":451,"Probability":100},"Authentication":{"ErrorCode":535,"Probability":0}}
```

ثم نرسل 50 رسالة من «التطبيق» إلى عناوين في `example.net` عبر منفذ الإرسال 587 بالسكربت `send.py` الذي سوف نشرحه في [قسم إعادة استخدام الاتصال](#connection-reuse)، ونعرض الطابور من داخل Postfix بالأمر `postqueue -p`، وهو نفس الأمر القديم `mailq`:

```bash
python3 /lab/send.py mx.example.org 587 reuse 50
docker exec lab-mail-mta sh -c 'postqueue -p | head -4; postqueue -p | tail -1'
```

```text
reuse 50 messages in 0.52 s (10.4 ms per message)
-Queue ID-  --Size-- ----Arrival Time---- -Sender/Recipient-------
28795B0985      403 Tue Oct  6 05:00:55  alice@example.org
(host mx.example.net[192.168.80.4] said: 451 Chaos recipient error (in reply to RCPT TO command))
                                         user0@example.net
-- 19 Kbytes in 50 Requests.
```

الأمر `docker exec` ننفذه من جهازك وليس من داخل `lab-mail-client`، لأنه يدخل إلى Container آخر. وفي المخرج لاحظ أن التطبيق انتهى في نصف ثانية وكأن كل شيء نجح، فهو سلم الرسائل لسيرفر `example.org` وأخذ الرد 250، أما الرسائل نفسها فما زالت كلها في الطابور، وبجانب كل واحدة سبب التأجيل كما قاله السيرفر الآخر بالحرف. وفي السجل تجد السطر نفسه بالحالة `status=deferred`:

```text
Oct 06 05:00:55 mx postfix/smtp[209]: A0EE3B19B3: to=<user49@example.net>, relay=mx.example.net[192.168.80.4]:1025, delay=0.06, delays=0.01/0/0.05/0.01, dsn=4.0.0, status=deferred (host mx.example.net[192.168.80.4] said: 451 Chaos recipient error (in reply to RCPT TO command))
```

وفي Postfix تبدأ الفترة بين المحاولات من [minimal\_backoff\_time](https://www.postfix.org/postconf.5.html?ref=arabroot.io#minimal%5Fbackoff%5Ftime) وقيمتها الافتراضية 300 ثانية، وتكبر حتى `maximal_backoff_time` وقيمتها 4000 ثانية، أي حوالي 67 دقيقة، والرسالة التي تبقى مؤجلة أكثر من [maximal\_queue\_lifetime](https://www.postfix.org/postconf.5.html?ref=arabroot.io#maximal%5Fqueue%5Flifetime) وقيمتها 5 أيام تعتبر غير قابلة للتسليم وترتد إلى صاحبها. ولكي لا ننتظر خمس دقائق نلغي الخطأ ونطلب من Postfix أن يحاول الآن بالأمر `postqueue -f`:

```bash
curl -s -X PUT -H 'Content-Type: application/json' \
  -d '{"Recipient":{"ErrorCode":451,"Probability":0}}' http://mx.example.net:8025/api/v1/chaos
docker exec lab-mail-mta postqueue -f
sleep 5; docker exec lab-mail-mta postqueue -p
```

```text
Mail queue is empty
```

وصلت الرسائل الخمسون كلها دون أن يعيد التطبيق إرسال أي شيء، وهذه هي الفائدة الحقيقية من وجود MTA بين تطبيقك والعالم. ويجدر الإشارة هنا إلى أن بعض السيرفرات ترد بالرمز المؤقت عن قصد على كل مرسل لا تعرفه، وهي تقنية التأجيل الرمادي Greylisting التي يصفها [RFC 6647](https://www.rfc-editor.org/rfc/rfc6647.html?ref=arabroot.io)، والفكرة أن السيرفر الحقيقي سوف يعيد المحاولة كما يطلب المعيار، بينما كثير من برامج الرسائل المزعجة لا تعيد، لذلك إذا كان تطبيقك يرسل مباشرة إلى سيرفرات المستلمين دون طابور، فكل رد 4xx يعني رسالة ضائعة.

### الرسائل المرتدة Bounces وتقارير DSN

الآن الحالة الثانية في الصورة: نرسل من حساب Alice إلى عنوان غير موجود عند Mailpit:

```bash
swaks --server mx.example.org --port 587 --tls --auth PLAIN \
  --auth-user alice@example.org --auth-password labpass --helo laptop.example.org \
  --from alice@example.org --to no.such.user@example.net \
  --h-Subject "Meeting tomorrow" --body "See you at 10."
```

سوف يرد Postfix على swaks بالرد `250 2.0.0 Ok: queued as B647CB1997`، أي أن الإرسال «نجح» من وجهة نظر Alice، ثم في السجل نرى ما حدث بعد ذلك:

```text
Oct 06 05:02:12 mx postfix/smtp[291]: B647CB1997: to=<no.such.user@example.net>, relay=mx.example.net[192.168.80.4]:1025, delay=0.07, delays=0.01/0/0.05/0.01, dsn=5.1.0, status=bounced (host mx.example.net[192.168.80.4] said: 550 5.1.0 Requested action not taken: mailbox unavailable (in reply to RCPT TO command))
Oct 06 05:02:12 mx postfix/cleanup[280]: C74FDB199C: message-id=<20261006050212.C74FDB199C@mx.example.org>
Oct 06 05:02:12 mx postfix/bounce[317]: B647CB1997: sender non-delivery notification: C74FDB199C
Oct 06 05:02:12 mx postfix/qmgr[273]: C74FDB199C: from=<>, size=2504, nrcpt=1 (queue active)
Oct 06 05:02:12 mx postfix/qmgr[273]: B647CB1997: removed
Oct 06 05:02:12 mx postfix/lmtp[318]: C74FDB199C: to=<alice@example.org>, relay=imap.example.org[192.168.80.2]:24, delay=0.05, delays=0.01/0.01/0.02/0.02, dsn=2.0.0, status=sent (250 2.0.0 <alice@example.org> UEhaMtSAxGoTAAAA68ePFA Saved)
```

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

- الرد `550` دائم، فلم يبق Postfix الرسالة في الطابور لإعادة المحاولة، وإنما أنشأ مباشرة رسالة جديدة برقم `C74FDB199C` تسمى إشعار عدم التسليم Non-Delivery Notification، أو الرسالة المرتدة Bounce.
- المرسل في الرسالة المرتدة فارغ `from=<>`، وهذا ما يسمى المرسل الفارغ Null Reverse-Path، ويذكر RFC 5321 أن المعايير تطلب إرسال إشعارات الفشل وتقارير DSN به، والسبب أن الرسالة المرتدة إذا ارتدت هي الأخرى فلا يوجد عنوان تعود إليه، وبالتالي لا تدخل السيرفرات في حلقة من الرسائل المرتدة بلا نهاية.
- الرسالة المرتدة ذهبت إلى عنوان الظرف `alice@example.org` وسلمت إلى صندوقها، وسوف نقرؤها عبر IMAP في [قسم القراءة](#reading).

والرسالة المرتدة ليست نصاً حراً، وإنما لها شكل قياسي يسمى إشعار حالة التسليم Delivery Status Notification، واختصاراً DSN، يعرفه [RFC 3464](https://www.rfc-editor.org/rfc/rfc3464.html?ref=arabroot.io)، حتى تستطيع البرامج قراءتها وليس الإنسان فقط. وهذه أهم أسطرها كما وصلت إلى صندوق Alice:

```bash
docker exec lab-mail-dovecot doveadm fetch -u alice@example.org text mailbox INBOX HEADER Subject "Undelivered" \
  | grep -E "^(Return-Path|From|Auto-Submitted|Content-Type|Reporting-MTA|Final-Recipient|Action|Status|Remote-MTA|Diagnostic-Code):"
```

```text
Return-Path: <>
From: Mail Delivery System <MAILER-DAEMON@example.org>
Auto-Submitted: auto-replied
Content-Type: multipart/report; report-type=delivery-status;
Content-Type: text/plain; charset=utf-8
Content-Type: message/delivery-status
Reporting-MTA: dns; mx.example.org
Final-Recipient: rfc822; no.such.user@example.net
Action: failed
Status: 5.1.0
Remote-MTA: dns; mx.example.net
Diagnostic-Code: smtp; 550 5.1.0 Requested action not taken: mailbox
Content-Type: message/rfc822
Return-Path: <alice@example.org>
From: alice@example.org
```

الرسالة من ثلاثة أجزاء: نص يقرؤه الإنسان، ثم جزء `message/delivery-status` بالحقول `Action` و`Status` و`Diagnostic-Code` التي تقرؤها البرامج، ثم الرسالة الأصلية أو رؤوسها في الجزء `message/rfc822`. وهذه الحقول هي ما تقرؤه منصات الإرسال لتوقف الإرسال إلى العناوين الميتة، كما شرحنا في [دليل Amazon SES](https://arabroot.io/articles/%D8%A7%D8%B1%D8%B3%D8%A7%D9%84-%D8%A8%D8%B1%D9%8A%D8%AF%D9%83-%D8%B9%D8%A8%D8%B1-amazon-ses/#bounces).

⚠️

ارفض الرسالة أثناء محادثة SMTP بدلاً من قبولها ثم إرجاعها، والسبب أن الرسالة المرتدة تذهب إلى عنوان الظرف، وهذا العنوان يكتبه المرسل بنفسه، فإذا قبل سيرفرك رسالة مزعجة بعنوان مزور ثم أرجعها، فأنت ترسل رسالة مرتدة لشخص بريء لم يرسل شيئاً، وهذا ما يسمى [Backscatter](https://www.postfix.org/BACKSCATTER%5FREADME.html?ref=arabroot.io)، وقد يضع سيرفرك في قوائم الحظر. لذلك يتحقق السيرفر الجيد من وجود الصندوق عند `RCPT TO` ويرد بـ 550 مباشرة كما فعل Mailpit هنا.

## الظرف والرؤوس: عنوانان للمرسل وعنوانان للمستلم

لاحظت في المحادثة أن العناوين تظهر مرتين: مرة في الأوامر `MAIL FROM` و`RCPT TO`، ومرة في الرؤوس `From:` و`To:` بعد `DATA`، وهذا ليس تكراراً، فالأولى هي الظرف Envelope الذي يعرفه RFC 5321 وتقرؤه السيرفرات لتعرف أين تسلم الرسالة وأين تعيدها إذا فشلت، والثانية هي رؤوس الرسالة التي يعرفها [RFC 5322](https://www.rfc-editor.org/rfc/rfc5322.html?ref=arabroot.io) ويعرضها برنامج البريد للإنسان. والأهم أن البروتوكول لا يطلب أن يتطابقا، والصورة التالية تبين ذلك بقيم حقيقية من المختبر:

![ظرف كبير عليه عنوان الظرف حسب RFC 5321: MAIL FROM bounces@example.org وRCPT TO ops@example.net، ويرسل كأوامر SMTP ولا يراه القارئ، وفي داخله ورقة الرسالة برؤوس RFC 5322: From Alice alice@example.org وTo Team team@example.net وSubject Envelope vs headers ثم النص، وسهم من الظرف إلى السيرفرات التي تسلم إلى RCPT TO وترجع إلى MAIL FROM، وسهم من الورقة إلى القارئ الذي يرى From وTo](https://arabroot.io/content/images/2026/10/how-email-works-05-envelope.webp)

السيرفرات تسلم حسب الظرف، والقارئ يرى الرؤوس، والاثنان مستقلان تماماً

والمثال التالي يرسل رسالة ظرفها إلى `ops@example.net`، بينما السطر `To:` فيها يقول `team@example.net`، وعنوان المرسل على الظرف يختلف عن السطر `From:`، كما يلي:

```bash
swaks --server mx.example.net --port 1025 --helo laptop.example.org \
  --from bounces@example.org --to ops@example.net \
  --h-From "Alice <alice@example.org>" --h-To "Team <team@example.net>" \
  --h-Subject "Envelope vs headers" --body "Who is this really for?"
curl -s http://mx.example.net:8025/api/v1/message/latest/raw | grep -E "^(Return-Path|From|To|Subject):"
curl -s http://mx.example.net:8025/api/v1/message/latest | python3 -c "import sys,json;m=json.load(sys.stdin);print('ReturnPath:',m['ReturnPath']);print('From:',m['From']);print('To:',m['To']);print('Bcc:',m['Bcc'])"
```

```text
Return-Path: <bounces@example.org>
To: Team <team@example.net>
From: Alice <alice@example.org>
Subject: Envelope vs headers
ReturnPath: bounces@example.org
From: {'Name': 'Alice', 'Address': 'alice@example.org'}
To: [{'Name': 'Team', 'Address': 'team@example.net'}]
Bcc: [{'Name': '', 'Address': 'ops@example.net'}]
```

في المخرج أعلاه لاحظ التالي:

- الرسالة وصلت إلى `ops` لأنه في الظرف، مع أن اسمه لا يظهر في أي رأس، لذلك اعتبره Mailpit نسخة مخفية `Bcc`، وهذه بالضبط طريقة عمل النسخة المخفية Blind Carbon Copy في كل برامج البريد: العنوان في `RCPT TO` فقط، ولا يوجد في الرؤوس، كما يصف RFC 5322.
- السيرفر الأخير حفظ عنوان الظرف في الرأس `Return-Path` عند التسليم النهائي كما يطلب RFC 5321، فإذا أردت أن تعرف أين تعود رسائل الفشل لرسالة وصلتك، فانظر إلى هذا الرأس وليس إلى `From:`.
- هذا الاستقلال مفيد، فمنصات الإرسال تضع في الظرف عنواناً خاصاً بها لتستقبل الرسائل المرتدة وتعالجها، ولكنه أيضاً ما يجعل انتحال الاسم الظاهر ممكناً، ولهذا جاء DMARC ليربط النطاق في `From:` بنتائج الفحص، كما شرحنا في [مقال SPF وDKIM وDMARC](https://arabroot.io/articles/%D8%B4%D8%B1%D8%AD-spf-%D9%88-dkim-%D9%88-dmarc-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/#the-problem) مع مثال انتحال كامل.

وهناك رأس ثالث يضيفه كل سيرفر تمر به الرسالة، وهو `Received:`، فالمعيار يطلب من كل سيرفر أن يضيف سطراً في أعلى الرسالة فيه اسم من سلمها إليه وعنوانه والوقت. وهذه رؤوس رسالة أرسلتها Alice من 587 إلى `ops@example.net` كما وصلت إلى Mailpit:

```text
Return-Path: <alice@example.org>
Received: from mx.example.org (unknown [192.168.80.5])
        by mx.example.net (Mailpit) with SMTP
        for <ops@example.net>; Tue, 6 Oct 2026 05:00:07 +0000 (UTC)
Received: from laptop.example.org (lab-mail-client.lab-mail-net [192.168.80.3])
	by mx.example.org (Postfix) with ESMTPSA id 1A4FEB095A
	for <ops@example.net>; Tue, 06 Oct 2026 05:00:07 +0000 (UTC)
```

اقرأ الأسطر `Received:` من الأسفل إلى الأعلى، فالأسفل هو أول خطوة: من جهاز `laptop.example.org` إلى `mx.example.org`، ثم الأعلى منه من `mx.example.org` إلى `mx.example.net`. والكلمة `ESMTPSA` من [RFC 3848](https://www.rfc-editor.org/rfc/rfc3848.html?ref=arabroot.io) تعني أن الخطوة الأولى كانت مشفرة S ومسجلة الدخول A، وهذه الأسطر هي أول ما تقرؤه عندما تتأخر رسالة، لأن الوقت في كل سطر يبين أين انتظرت.

## المنافذ والتشفير: أي باب لأي غرض؟

الآن نعود إلى السؤال الذي بدأنا به: لماذا يحتاج البريد كل هذه المنافذ Ports؟ والإجابة أن كل منفذ باب لنوع مختلف من الزوار، فالسيرفرات الأخرى تدخل من باب، ومستخدموك الذين يرسلون من باب، والذين يقرؤون من باب ثالث، ولكل باب قواعده في التشفير وتسجيل الدخول، وإذا كان مصطلح المنفذ جديداً عليك فقد شرحناه في [مقال مصطلحات الاستضافة الذاتية](https://arabroot.io/articles/%D9%85%D8%B5%D8%B7%D9%84%D8%AD%D8%A7%D8%AA-%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D8%B6%D8%A7%D9%81%D8%A9-%D8%A7%D9%84%D8%B0%D8%A7%D8%AA%D9%8A%D8%A9-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/#network). والصورة التالية تبين المنافذ ونوع التشفير على كل منها:

![مخطط في وسطه سيرفر mx.example.org، على يساره سحابة سيرفرات البريد الأخرى على المنفذ 25 مع قفل أصفر يعني STARTTLS إذا عرضه الطرفان، وملاحظة أن MTA-STS وDANE تجعله إلزامياً، وبطاقة حمراء أن كثيراً من مزودي السيرفرات يحجبون المنفذ 25 الصادر، وعلى يمينه منافذ المستخدمين: 465 للإرسال بتشفير مباشر توصي به RFC 8314، و587 للإرسال مع STARTTLS قبل تسجيل الدخول، و993 IMAPS، و143 IMAP مع STARTTLS، و995 POP3S، و443 JMAP، وفي الأسفل مقارنة بين STARTTLS الذي يبدأ بتحية مكشوفة ثم يتحول إلى TLS وبين التشفير المباشر من أول بايت](https://arabroot.io/content/images/2026/10/how-email-works-04-ports.webp)

منفذ واحد للسيرفرات، ومنافذ للإرسال والقراءة لمستخدميك، والفرق في متى يبدأ التشفير

| المنفذ | الاسم       | من يستخدمه                       | التشفير                        | تسجيل الدخول |
| ------ | ----------- | -------------------------------- | ------------------------------ | ------------ |
| 25     | smtp        | السيرفرات فيما بينها             | STARTTLS إذا عرضه الطرفان      | لا يوجد      |
| 587    | submission  | برامج البريد والتطبيقات للإرسال  | STARTTLS، وسيرفرك يجب أن يطلبه | إلزامي       |
| 465    | submissions | برامج البريد والتطبيقات للإرسال  | تشفير مباشر Implicit TLS       | إلزامي       |
| 993    | imaps       | القراءة عبر IMAP                 | تشفير مباشر                    | إلزامي       |
| 143    | imap        | القراءة عبر IMAP للبرامج القديمة | STARTTLS                       | إلزامي       |
| 995    | pop3s       | التنزيل عبر POP3                 | تشفير مباشر                    | إلزامي       |
| 110    | pop3        | التنزيل عبر POP3 للبرامج القديمة | STARTTLS                       | إلزامي       |
| 443    | https       | JMAP والبريد عبر الويب           | HTTPS                          | إلزامي       |

الأسماء في العمود الثاني هي أسماء الخدمات المسجلة في [سجل IANA للمنافذ](https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?ref=arabroot.io)، ومنها `submission` و`submissions` اللذان كتبناهما لـ Postfix في `start.sh`.

### STARTTLS أم التشفير المباشر Implicit TLS؟

هناك طريقتان لتشفير اتصال البريد. في الطريقة الأولى STARTTLS يبدأ الاتصال مكشوفاً، ويرسل الطرفان التحية و`EHLO` نصاً واضحاً، ثم يطلب المرسل `STARTTLS` فيتحول الاتصال نفسه إلى اتصال مشفر، وفي الطريقة الثانية يبدأ التشفير مع أول بايت على منفذ مخصص لذلك، تماماً كما يحدث في HTTPS الذي شرحناه في [مقال HTTP وHTTPS](https://arabroot.io/articles/http-%D9%88-https-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/#https). والمثال التالي يبين STARTTLS على المنفذ 587، فنحاول أولاً أن نرسل دون تشفير:

```bash
swaks --server mx.example.org --port 587 --helo laptop.example.org \
  --from alice@example.org --to ops@example.net --quit-after MAIL
```

```text
 -> MAIL FROM:<alice@example.org>
<** 530 5.7.0 Must issue a STARTTLS command first
```

اختصرنا أسطر `EHLO` مرة أخرى، والمهم الرد: رفض دائم، وهذا ما نريده تماماً من منفذ الإرسال، لأن كلمة المرور سوف تمر عليه. والآن مع `--tls` وتسجيل الدخول:

```bash
swaks --server mx.example.org --port 587 --tls --auth PLAIN \
  --auth-user alice@example.org --auth-password labpass --helo laptop.example.org \
  --from alice@example.org --to ops@example.net \
  --h-From "Alice <alice@example.org>" --h-Subject "Weekly report" --body "The weekly report is ready."
```

والمخرج سوف يكون كما يلي، واختصرنا منه سطري الاتصال الأولين وأسطر المحتوى بعد `DATA`:

```text
<-  220 mx.example.org ESMTP Postfix (Debian)
 -> EHLO laptop.example.org
<-  250-mx.example.org
<-  250-PIPELINING
<-  250-SIZE 10240000
<-  250-VRFY
<-  250-ETRN
<-  250-STARTTLS
<-  250-ENHANCEDSTATUSCODES
<-  250-8BITMIME
<-  250-DSN
<-  250-SMTPUTF8
<-  250 CHUNKING
 -> STARTTLS
<-  220 2.0.0 Ready to start TLS
=== TLS started with cipher TLSv1.3:TLS_AES_256_GCM_SHA384:256
=== TLS client certificate not requested and not sent
=== TLS no client certificate set
=== TLS peer[0]   subject=[/CN=mx.example.org]
===               commonName=[mx.example.org], subjectAltName=[DNS:mx.example.org] notAfter=[2036-10-03T04:59:13Z]
=== TLS peer certificate failed CA verification (self-signed certificate), passed host verification (using host mx.example.org to verify)
 ~> EHLO laptop.example.org
<~  250-mx.example.org
<~  250-PIPELINING
<~  250-SIZE 10240000
<~  250-VRFY
<~  250-ETRN
<~  250-AUTH PLAIN
<~  250-ENHANCEDSTATUSCODES
<~  250-8BITMIME
<~  250-DSN
<~  250-SMTPUTF8
<~  250 CHUNKING
 ~> AUTH PLAIN AGFsaWNlQGV4YW1wbGUub3JnAGxhYnBhc3M=
<~  235 2.7.0 Authentication successful
 ~> MAIL FROM:<alice@example.org>
<~  250 2.1.0 Ok
 ~> RCPT TO:<ops@example.net>
<~  250 2.1.5 Ok
 ~> DATA
<~  354 End data with <CR><LF>.<CR><LF>
<~  250 2.0.0 Ok: queued as 1A4FEB095A
 ~> QUIT
<~  221 2.0.0 Bye
```

في المخرج أعلاه لاحظ التالي:

- بعد `STARTTLS` تتغير الأسهم من `->` إلى `~>`، أي أن ما بعدها مشفر، ويرسل swaks الأمر `EHLO` مرة ثانية لأن المعيار يلغي كل ما عرفه الطرفان قبل التشفير.
- `AUTH PLAIN` لم يظهر في القائمة قبل التشفير، وظهر بعده، فسيرفر الإرسال الصحيح لا يعرض تسجيل الدخول على اتصال مكشوف أصلاً. والنص بعد `AUTH PLAIN` ليس تشفيراً وإنما ترميز Base64 لاسم المستخدم وكلمة المرور، ويستطيع أي شخص أن يفكه، ولهذا بالضبط يجب أن يكون داخل TLS.
- swaks فشل في التحقق من الشهادة لأنها ذاتية التوقيع في المختبر، وأكمل لأنه أداة فحص، أما برنامج البريد الحقيقي فيجب أن يرفض، والشهادة الحقيقية تصدرها من Let's Encrypt كما في أدلة الخوادم.

أما التشفير المباشر على المنفذ 465 فيظهر بوضوح مع `openssl s_client`، فالتحية `220` نفسها لا تصل إلا بعد اكتمال TLS:

```bash
openssl s_client -connect mx.example.org:465 -brief -crlf
```

```text
depth=0 CN = mx.example.org
verify error:num=18:self-signed certificate
CONNECTION ESTABLISHED
Protocol version: TLSv1.3
Ciphersuite: TLS_AES_256_GCM_SHA384
Peer certificate: CN = mx.example.org
Hash used: SHA256
Signature type: RSA-PSS
Verification error: self-signed certificate
Server Temp Key: X25519, 253 bits
220 mx.example.org ESMTP Postfix (Debian)
250-mx.example.org
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-AUTH PLAIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250-SMTPUTF8
250 CHUNKING
```

كتبنا `EHLO laptop.example.org` بعد أن ظهر سطر `220`، ولاحظ أن `STARTTLS` غير موجود في القائمة، فالاتصال مشفر من البداية ولا حاجة له. وللمنفذ 587 تستخدم الأمر نفسه مع `-starttls smtp`، فيقوم openssl بالخطوات المكشوفة بنفسه ثم يعرض لك الشهادة.

وقد يتساءل البعض: ما دامت الطريقتان تنتهيان باتصال مشفر، فما الفرق؟ والإجابة أن الخطوات المكشوفة في STARTTLS هي نقطة ضعفه، فمن يقف في منتصف الطريق يستطيع أن يحذف السطر `250-STARTTLS` من القائمة فيظن البرنامج أن السيرفر لا يدعم التشفير، كما يذكر [RFC 3207](https://www.rfc-editor.org/rfc/rfc3207.html?ref=arabroot.io) نفسه في قسم الأمان، والبرنامج الذي يكمل دون تشفير يرسل كلمة المرور نصاً واضحاً. لذلك جاء [RFC 8314](https://www.rfc-editor.org/rfc/rfc8314.html?ref=arabroot.io) في يناير 2018 ليوصي بالتشفير المباشر Implicit TLS لكل البروتوكولات بين برنامج البريد ومزود الخدمة: 465 للإرسال، و993 لـ IMAP، و995 لـ POP3، مع إبقاء 587 بـ STARTTLS للبرامج التي تحتاجه.

📌

في مارس 2011 نشر Wietse Venema، مطور Postfix، [ثغرة CVE-2011-0411](https://www.postfix.org/CVE-2011-0411.html?ref=arabroot.io): كثير من تطبيقات STARTTLS، ومنها Postfix نفسه، كانت تقرأ الأوامر التي يرسلها المهاجم في نفس حزمة الأمر `STARTTLS` ثم تنفذها بعد بدء التشفير وكأنها جاءت مشفرة. وبعد عشر سنوات نشر باحثون من جامعة Münster للعلوم التطبيقية في مؤتمر USENIX Security 2021 دراسة [NO STARTTLS](https://nostarttls.secvuln.info/?ref=arabroot.io)، وجدوا فيها أكثر من 40 ثغرة في تطبيقات STARTTLS في برامج وخوادم البريد، ووجدوا أن ثغرة 2011 نفسها ما زالت في 15 تطبيقاً وفي حوالي 2% من خوادم البريد التي فحصوها، وكانت توصيتهم تجنب STARTTLS حيث أمكن. والدرس: لمستخدميك فضل 465 و993 و995، وأبق 587 و143 للبرامج التي لا تعرف غيرها.

### التشفير بين السيرفرات على المنفذ 25

المنفذ 25 مختلف، فلا يوجد عليه تسجيل دخول لأن أي سيرفر في العالم يحق له أن يسلمك بريداً لنطاقك، والتشفير عليه بـ STARTTLS انتهازي Opportunistic، أي أن المرسل يشفر إذا عرض المستقبل التشفير، ويرسل نصاً واضحاً إذا لم يعرضه، ولا يتحقق عادة من الشهادة، والسبب أن رفض التسليم لسيرفر بلا شهادة صحيحة كان سيوقف جزءاً كبيراً من البريد في العالم. وهذا ما فعله Postfix في المختبر عندما أرسل إلى Mailpit، وتراه في السجل:

```text
Oct 06 05:00:07 mx postfix/smtp[199]: Untrusted TLS connection established to mx.example.net[192.168.80.4]:1025: TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange x25519 server-signature RSA-PSS (2048 bits) server-digest SHA256
Oct 06 05:00:07 mx postfix/smtp[199]: 1A4FEB095A: to=<ops@example.net>, relay=mx.example.net[192.168.80.4]:1025, delay=0.09, delays=0.01/0.03/0.05/0, dsn=2.0.0, status=sent (250 2.0.0 Ok: queued as 1EXgYuKrMHjhn7STTBMCLs)
```

الكلمة `Untrusted` تعني أن الاتصال مشفر ولكن الشهادة لم يتحقق منها، وأكمل Postfix التسليم لأن المستوى `may` لا يطلب أكثر من ذلك. ولكي يطلب النطاق المستقبل تشفيراً بشهادة صحيحة يوجد معياران: [MTA-STS](https://www.rfc-editor.org/rfc/rfc8461.html?ref=arabroot.io) الذي ينشر سياسة عبر HTTPS وDNS، وقد شرحناه في [مقال SPF وDKIM وDMARC](https://arabroot.io/articles/%D8%B4%D8%B1%D8%AD-spf-%D9%88-dkim-%D9%88-dmarc-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/#mta-sts)، و[DANE لـ SMTP في RFC 7672](https://www.rfc-editor.org/rfc/rfc7672.html?ref=arabroot.io) الذي ينشر بصمة الشهادة في سجل TLSA ويحتاج DNSSEC على النطاق، وهذا هو سبب التحذير الذي يظهر في سجلات Stalwart كما في [دليل Stalwart](https://arabroot.io/articles/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D8%AE%D8%A7%D8%AF%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%8A%D8%AF-stalwart/#dane-warning).

### لماذا يحجب مزود السيرفر المنفذ 25؟

لأن المنفذ 25 لا يحتاج تسجيل دخول، فأي برنامج خبيث على أي سيرفر مخترق يستطيع أن يتصل مباشرة بسيرفرات Gmail وOutlook ويرسل منها آلاف الرسائل المزعجة، وعنوان IP الذي يرسل منها يدخل قوائم الحظر، ثم يؤجره المزود لعميل جديد فيجد بريده مرفوضاً من أول يوم. لذلك يحجب كثير من المزودين الاتصال الصادر على المنفذ 25 افتراضياً، مثل [Hetzner](https://docs.hetzner.com/cloud/servers/faq/?ref=arabroot.io) و[DigitalOcean](https://docs.digitalocean.com/support/why-is-smtp-blocked/?ref=arabroot.io) و[AWS](https://repost.aws/knowledge-center/ec2-port-25-throttle?ref=arabroot.io)، ويفتحه بعضهم بطلب، ولاحظ أن الحجب على الاتصال الصادر فقط، فسيرفرك يستقبل على 25 عادة ولكنه لا يستطيع أن يسلم. وقد شرحنا كيف تتأكد من ذلك قبل الشراء في [دليل Postfix وDovecot](https://arabroot.io/articles/%D8%AE%D8%A7%D8%AF%D9%85-%D8%A8%D8%B1%D9%8A%D8%AF-postfix-%D9%88-dovecot-%D9%8A%D8%AF%D9%88%D9%8A%D8%A7/#server)، وإذا كان المنفذ محجوباً فالحل أن ترسل عبر خادم وسيط SMTP Relay على المنفذ 587 أو 465 كما في [دليل الإرسال عبر Amazon SES](https://arabroot.io/articles/%D8%A7%D8%B1%D8%B3%D8%A7%D9%84-%D8%A8%D8%B1%D9%8A%D8%AF%D9%83-%D8%B9%D8%A8%D8%B1-amazon-ses/#why-relay)، وهذا ممكن لأن منافذ الإرسال لا يحجبها أغلب المزودين. وقد جمعنا سياسات المزودين بتواريخ صفحاتهم الرسمية، ومنهم من يحجب 465 و587 أيضاً، مع أشكال الترحيل Relay كلها في مقال [الفرق بين SMTP والترحيل Relay](https://arabroot.io/articles/%D8%A7%D9%84%D9%81%D8%B1%D9%82-%D8%A8%D9%8A%D9%86-smtp-%D9%88%D8%A7%D9%84%D8%AA%D8%B1%D8%AD%D9%8A%D9%84-relay/).

## قراءة البريد: IMAP وPOP3 وJMAP

وصلت الرسالة إلى صندوق Bob على السيرفر، والآن يحتاج برنامج البريد أن يقرأها، وهنا ثلاثة بروتوكولات تختلف في سؤال واحد بسيط: أين يعيش البريد، على السيرفر أم على الجهاز؟ والصورة التالية تبين الفرق:

![ثلاثة أعمدة: POP3 على المنفذ 995 ينزل صندوق INBOX فقط إلى جهاز واحد بالأمرين RETR وDELE فيجد الهاتف الصندوق فارغاً، ولا توجد مجلدات ولا حالة قراءة مشتركة، وIMAP على المنفذ 993 يبقي الصندوق على السيرفر بمجلداته INBOX وSent وDrafts وTrash وJunk وعلامة Seen، والجهاز والهاتف يتزامنان فما يقرأ في أحدهما يظهر مقروءاً في الآخر، وJMAP على المنفذ 443 يعمل بنفس نموذج IMAP عبر JSON وHTTPS مع الدفع الفوري ويدعمه Stalwart](https://arabroot.io/content/images/2026/10/how-email-works-06-imap-pop3.webp)

POP3 ينقل البريد إلى جهاز واحد، وIMAP وJMAP يبقيانه على السيرفر لكل الأجهزة

- **POP3:** البروتوكول الأقدم في [RFC 1939](https://www.rfc-editor.org/rfc/rfc1939.html?ref=arabroot.io)، صمم لزمن كان فيه الاتصال بالإنترنت مؤقتاً، فيتصل البرنامج وينزل الرسائل من الصندوق الرئيسي ثم يحذفها من السيرفر عادة، ولا يعرف شيئاً عن المجلدات ولا عن حالة القراءة. وهو مناسب لحالة واحدة اليوم: جهاز واحد يريد نسخة محلية من البريد ولا يهمه أن يراه في مكان آخر.
- **IMAP:** البروتوكول الذي يستخدمه أغلب الناس دون أن يعرفوا، وإصداره الحالي IMAP4rev2 في [RFC 9051](https://www.rfc-editor.org/rfc/rfc9051.html?ref=arabroot.io) منذ أغسطس 2021\. البريد يبقى على السيرفر بمجلداته، وكل رسالة لها علامات Flags مثل `\Seen` للمقروءة و`\Flagged` للمهمة، فإذا قرأت رسالة في الحاسوب ظهرت مقروءة في الهاتف، والبحث يتم على السيرفر، والأمر `IDLE` يجعل السيرفر يخبر البرنامج بالرسالة الجديدة فوراً.
- **JMAP:** البروتوكول الأحدث، وهو JSON عبر HTTPS في [RFC 8620](https://www.rfc-editor.org/rfc/rfc8620.html?ref=arabroot.io) للأساس و[RFC 8621](https://www.rfc-editor.org/rfc/rfc8621.html?ref=arabroot.io) للبريد، بنفس نموذج IMAP من صناديق وعلامات، ولكنه يجمع تغييرات كثيرة في طلب HTTP واحد ويدعم الدفع Push دون اتصال دائم، كما في [موقع JMAP](https://jmap.io/?ref=arabroot.io). ويدعمه [Stalwart](https://stalw.art/?ref=arabroot.io) بجانب IMAP وPOP3، ولكن تأكد أن برنامج البريد عند مستخدميك يدعمه قبل أن تعتمد عليه.

والآن نقرأ صندوق Alice في المختبر عبر IMAP بالكتابة اليدوية، فنفتح اتصالاً مشفراً مباشراً بالمنفذ 31993، وهو المقابل لـ 993 في ال Docker Image الرسمية:

```bash
openssl s_client -connect imap.example.org:31993 -crlf -quiet 2>/dev/null
```

ثم نكتب الأوامر التالية سطراً سطراً، وكل أمر في IMAP يبدأ بوسم Tag نختاره، مثل `a1`، يعيده السيرفر في نهاية الرد لنعرف أي رد لأي أمر:

```text
a1 LOGIN alice@example.org labpass
a2 LIST "" "*"
a3 SELECT INBOX
a4 FETCH 1:* (FLAGS RFC822.SIZE BODY.PEEK[HEADER.FIELDS (FROM SUBJECT)])
a5 STORE 1 +FLAGS (\Seen)
a6 LOGOUT
```

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

```text
* OK [CAPABILITY IMAP4rev1 IMAP4rev2 LOGIN-REFERRALS ID ENABLE IDLE SASL-IR LITERAL+ AUTH=PLAIN] Dovecot ready.
a1 OK [CAPABILITY IMAP4rev1 IMAP4rev2 SASL-IR LOGIN-REFERRALS ID ENABLE IDLE SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS THREAD=ORDEREDSUBJECT MULTIAPPEND URL-PARTIAL CATENATE UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS BINARY MOVE REPLACE SNIPPET=FUZZY PREVIEW=FUZZY PREVIEW SPECIAL-USE STATUS=SIZE SAVEDATE COMPRESS=DEFLATE INPROGRESS NOTIFY LITERAL+ UTF8=ACCEPT FILTER=SIEVE] Logged in
* LIST (\HasNoChildren \Drafts) "/" Drafts
* LIST (\HasNoChildren \Junk) "/" Junk
* LIST (\HasNoChildren \Sent) "/" Sent
* LIST (\HasNoChildren \Trash) "/" Trash
* LIST (\HasNoChildren) "/" INBOX
a2 OK List completed (0.001 + 0.000 secs).
* FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
* OK [PERMANENTFLAGS (\Answered \Flagged \Deleted \Seen \Draft \*)] Flags permitted.
* 2 EXISTS
* 2 RECENT
* OK [UNSEEN 1] First unseen.
* OK [UIDVALIDITY 1791262786] UIDs valid
* OK [UIDNEXT 3] Predicted next UID
a3 OK [READ-WRITE] Select completed (0.001 + 0.000 secs).
* 1 FETCH (FLAGS (\Recent) RFC822.SIZE 754 BODY[HEADER.FIELDS (FROM SUBJECT)] {62}
From: Finance <finance@example.net>
Subject: Invoice 1042

)
* 2 FETCH (FLAGS (\Recent) RFC822.SIZE 2742 BODY[HEADER.FIELDS (FROM SUBJECT)] {104}
From: Mail Delivery System <MAILER-DAEMON@example.org>
Subject: Undelivered Mail Returned to Sender

)
a4 OK Fetch completed (0.001 + 0.000 secs).
* 1 FETCH (FLAGS (\Seen \Recent))
a5 OK Store completed (0.002 + 0.000 + 0.001 secs).
* BYE Logging out
a6 OK Logout completed (0.001 + 0.000 secs).
```

في المخرج أعلاه لاحظ التالي:

- في الصندوق رسالتان: الفاتورة التي أرسلناها على المنفذ 25، والرسالة المرتدة من [قسم الرسائل المرتدة](#bounces)، وكلاهما وصل عبر LMTP من Postfix.
- الأمر `FETCH` طلب رأسين فقط وحجم كل رسالة، ولم ينزل الرسالة كاملة، وهذا ما يجعل IMAP سريعاً مع صندوق فيه آلاف الرسائل، فالبرنامج يعرض القائمة أولاً وينزل الرسالة عندما تفتحها. والكلمة `PEEK` تعني «اقرأ دون أن تجعلها مقروءة».
- الأمر `STORE` وضع العلامة `\Seen` على الرسالة الأولى على السيرفر نفسه، فأي برنامج آخر يفتح هذا الصندوق الآن سوف يراها مقروءة، وهذا هو الفرق الجوهري عن POP3.
- المجلدات `Sent` و`Drafts` و`Junk` و`Trash` لها علامات استخدام خاصة Special-Use مثل `\Sent`، وبها يعرف برنامج البريد أين يحفظ الرسائل المرسلة مهما كانت لغة اسم المجلد.

وللمقارنة، نفس الصندوق عبر POP3 على المنفذ 31995، وهو المقابل لـ 995، بالأمر `openssl s_client -connect imap.example.org:31995 -crlf -quiet 2>/dev/null` ثم الأوامر `USER alice@example.org` و`PASS labpass` و`STAT` و`LIST` و`TOP 1 0` و`QUIT`:

```text
+OK Dovecot ready.
+OK
+OK Logged in.
+OK 2 3496
+OK 2 messages:
1 754
2 2742
.
+OK
Return-Path: <finance@example.net>
Delivered-To: alice@example.org
Received: from mx.example.org ([192.168.80.5])
	by imap.example.org with LMTP
	id XxzyLEKAxGoQAAAA68ePFA
	(envelope-from <finance@example.net>)
	for <alice@example.org>; Tue, 06 Oct 2026 04:59:46 +0000
Received: from mx.example.net (lab-mail-client.lab-mail-net [192.168.80.3])
	by mx.example.org (Postfix) with ESMTP id AFA1DB069F
	for <alice@example.org>; Tue, 06 Oct 2026 04:59:46 +0000 (UTC)
Date: Tue, 06 Oct 2026 04:59:46 +0000
To: alice@example.org
From: Finance <finance@example.net>
Subject: Invoice 1042
Message-Id: <20261006045946.000023@laptop.example.org>
X-Mailer: swaks v20240103.0 jetmore.org/john/code/swaks/

.
+OK Logging out.
```

لاحظ أن POP3 لا يعرف إلا صندوقاً واحداً برسائل مرقمة وأحجام، فلا توجد مجلدات ولا علامات، والردود ليست أرقاماً بل `+OK` و`-ERR` فقط. ولاحظ أيضاً في رؤوس الرسالة أن Dovecot أضاف سطر `Received:` جديداً بالكلمة `with LMTP`، وأضاف `Return-Path` و`Delivered-To` عند التسليم النهائي، فهذه الرسالة تحمل الآن الطريق الذي قطعته كاملاً. والقاعدة العملية لمستخدميك: IMAP على 993 لكل الأجهزة، وPOP3 فقط لمن يطلبه بسبب واضح، وJMAP عندما يكون الخادم والبرامج تدعمه.

## إعادة استخدام اتصال SMTP: رسائل كثيرة على اتصال واحد

نعود الآن إلى الطرف المرسل، فقد رأيت في محادثة المنفذ 587 أن الرسالة الواحدة تحتاج قبل أن يبدأ إرسالها: اتصال TCP، ثم انتظار التحية، ثم `EHLO`، ثم `STARTTLS` ومصافحة TLS، ثم `EHLO` مرة ثانية، ثم `AUTH`، وكل خطوة تنتظر رداً من السيرفر قبل الخطوة التالية. فإذا كان تطبيقك يرسل 50 رسالة «تأكيد طلب» ويفتح اتصالاً جديداً لكل رسالة، فهو يدفع هذا الثمن خمسين مرة، والحل أن تبقي الاتصال مفتوحاً وترسل عليه رسالة بعد رسالة، فالمعيار يسمح بعدة رسائل في جلسة واحدة، وكل `MAIL FROM` جديد يبدأ رسالة جديدة. وهذه هي نفس فكرة تجميع الاتصالات Connection Pooling التي شرحناها بالتفصيل لقواعد البيانات في [مقال تجميع الاتصالات](https://arabroot.io/articles/%D8%AA%D8%AC%D9%85%D9%8A%D8%B9-%D8%A7%D9%84%D8%A7%D8%AA%D8%B5%D8%A7%D9%84%D8%A7%D8%AA-connection-pooling-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/#other-pools)، والصورة التالية تبينها في SMTP:

![صفان: في الأعلى اتصال لكل رسالة، فكل رسالة تمر بالخطوات TCP وEHLO وSTARTTLS وTLS وEHLO وAUTH ثم الرسالة ثم QUIT، وتتكرر 50 مرة، ونتيجة Python smtplib في المختبر 2.5 إلى 2.7 ثانية لخمسين رسالة، وPostfix فتح 50 اتصال TLS، وفي الأسفل اتصال واحد يدفع الخطوات مرة واحدة ثم يرسل الرسائل 1 و2 و3 حتى 50 ثم QUIT، والنتيجة 0.7 إلى 1.2 ثانية، وPostfix استخدم 14 اتصال TLS، وفي الأسفل تنبيه أن تبقي الاتصالات المتوازية قليلة لأن السيرفرات المستقبلة تعدها، وأن Postfix رد في المختبر 421 4.7.0 too many connections](https://arabroot.io/content/images/2026/10/how-email-works-07-smtp-pooling.webp)

الخطوات قبل الرسالة تدفع مرة واحدة بدل خمسين مرة، والأرقام من المختبر على جهاز واحد

### في كود تطبيقك

السكربت التالي `scripts/send.py` يرسل عدداً من الرسائل بطريقتين: اتصال جديد لكل رسالة، أو اتصال واحد لكل الرسائل، ويستخدم المكتبة [smtplib](https://docs.python.org/3/library/smtplib.html?ref=arabroot.io) المدمجة في Python:

```python
import smtplib, ssl, sys, time
from email.message import EmailMessage

HOST, PORT = sys.argv[1], int(sys.argv[2])
MODE, COUNT = sys.argv[3], int(sys.argv[4])   # MODE: "new" = one connection per message, "reuse" = one connection for all
USER, PASSWORD = "alice@example.org", "labpass"
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE                # lab only: self-signed certificate

def message(i):
    m = EmailMessage()
    m["From"], m["To"], m["Subject"] = USER, f"user{i}@example.net", f"Order #{i} confirmed"
    m.set_content(f"Your order #{i} is confirmed.")
    return m

def connect():
    s = smtplib.SMTP(HOST, PORT, local_hostname="app.example.org")
    s.starttls(context=ctx)
    s.login(USER, PASSWORD)
    return s

start = time.perf_counter()
if MODE == "new":
    for i in range(COUNT):
        with connect() as s:                   # TCP + EHLO + STARTTLS + EHLO + AUTH for every message
            s.send_message(message(i))
else:
    with connect() as s:                       # paid once
        for i in range(COUNT):
            s.send_message(message(i))         # MAIL FROM, RCPT TO, DATA on the same session
elapsed = time.perf_counter() - start
print(f"{MODE:5} {COUNT} messages in {elapsed:.2f} s ({elapsed / COUNT * 1000:.1f} ms per message)")
```

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

- الدالة `connect` تقوم بكل الخطوات المكلفة، والفرق بين الطريقتين هو فقط مكان `with`: داخل الحلقة أو خارجها. والكلاس `SMTP` يرسل `QUIT` تلقائياً عند الخروج من `with` كما تذكر الوثائق.
- السطران اللذان يلغيان التحقق من الشهادة للمختبر فقط بسبب الشهادة الذاتية، فلا تنسخهما إلى تطبيق حقيقي، والسبب أنك بدونهما تعطي كلمة مرور SMTP لأي شخص يقف في منتصف الطريق.

نشغله ثلاث مرات بكل طريقة على Mailpit مباشرة، أي على المنفذ 1025 مع STARTTLS وتسجيل الدخول:

```bash
for r in 1 2 3; do
  python3 /lab/send.py mx.example.net 1025 new 50
  python3 /lab/send.py mx.example.net 1025 reuse 50
done
```

```text
new   50 messages in 2.66 s (53.2 ms per message)
reuse 50 messages in 1.16 s (23.2 ms per message)
new   50 messages in 2.54 s (50.9 ms per message)
reuse 50 messages in 0.71 s (14.3 ms per message)
new   50 messages in 2.54 s (50.8 ms per message)
reuse 50 messages in 0.69 s (13.9 ms per message)
```

هذه الأرقام للتوضيح فقط، فهي على جهاز واحد والشبكة بين ال Containers شبه فورية، وتختلف من تشغيل لآخر، فقد رأينا في تشغيلات أخرى أن إعادة الاستخدام أخذت بين 0.2 و1.2 ثانية والاتصال الجديد بين 2.5 و4.2 ثانية، ولكن النتيجة ثابتة: الاتصال الواحد أسرع عدة مرات. وعلى الإنترنت يكبر الفرق، لأن كل خطوة من الخطوات المكررة تنتظر رداً من سيرفر قد يكون في قارة أخرى.

وفي Node.js تقوم المكتبة Nodemailer بذلك بالخيار `pool: true`، وتقول [وثائقها](https://nodemailer.com/smtp/pooled?ref=arabroot.io) إنها تبقي حتى `maxConnections` من الاتصالات مفتوحة، وقيمته الافتراضية 5، وترسل حتى `maxMessages` رسالة على الاتصال الواحد، وقيمته الافتراضية 100، ثم تفتح اتصالاً جديداً:

```javascript
import nodemailer from 'nodemailer';

// Create ONE transporter when the app starts and reuse it for every message.
export const mailer = nodemailer.createTransport({
  host: 'smtp.example.org',
  port: 465,
  secure: true,          // implicit TLS
  auth: { user: process.env.SMTP_USER, pass: process.env.SMTP_PASS },
  pool: true,
  maxConnections: 5,     // default 5: parallel connections to this server
  maxMessages: 100,      // default 100: messages per connection before reconnecting
  rateDelta: 1000,       // optional: at most rateLimit messages per rateDelta ms
  rateLimit: 10,
});
```

والقاعدة نفسها في كل لغة: أنشئ كائن الإرسال مرة واحدة عند تشغيل التطبيق ولا تنشئه داخل دالة الطلب، فتقول الوثائق صراحة إن إنشاء Transporter جديد لكل رسالة يلغي فائدة التجميع. أما متى ترسل عبر SMTP ومتى عبر HTTP API، وأين ترسل البريد التفاعلي من تطبيقك، فقد شرحناه في [دليل البريد التفاعلي](https://arabroot.io/articles/%D8%A7%D9%84%D8%A8%D8%B1%D9%8A%D8%AF-%D8%A7%D9%84%D8%AA%D9%81%D8%A7%D8%B9%D9%84%D9%8A-transactional-email/#smtp-vs-api).

### في Postfix نفسه

وماذا عن السيرفر عندما يسلم الرسائل من طابوره إلى سيرفر آخر؟ يقوم Postfix بنفس الشيء عبر ذاكرة الاتصالات Connection Cache، وتشرح [وثيقتها الرسمية](https://www.postfix.org/CONNECTION%5FCACHE%5FREADME.html?ref=arabroot.io) أن الإعداد `smtp_connection_cache_on_demand` مفعل افتراضياً، فيحفظ Postfix الاتصال ليعيد استخدامه عندما يكون لوجهة واحدة عدد كبير من الرسائل في الطابور النشط، ويمكنك أن تفرضه دائماً لوجهات معينة بالإعداد `smtp_connection_cache_destinations`، مثل الخادم الوسيط `relayhost`. ولكن هناك تفصيل لا تجده إلا إذا قرأت الوثائق كاملة: هذا يعمل على الاتصالات المكشوفة، أما الاتصالات المشفرة بـ TLS فتحتاج الإعداد [smtp\_tls\_connection\_reuse](https://www.postfix.org/postconf.5.html?ref=arabroot.io#smtp%5Ftls%5Fconnection%5Freuse)، وقيمته الافتراضية `no`، وهو متاح منذ Postfix 3.4، ويعمل عبر الخدمة `tlsproxy` التي أضفناها في `start.sh`.

ولكي نرى ذلك نعيد تجربة [الطابور](#queue-retry) مرتين: 50 رسالة مؤجلة إلى `example.net` ثم `postqueue -f`، ونعد في السجل الرسائل التي وصلت، والرسائل التي أرسلت على اتصال مستخدم من قبل، ويكتب Postfix لهذه الأخيرة `conn_use=` برقم الاستخدام، فالرسالة التي لا يوجد في سطرها `conn_use` فتحت اتصالاً جديداً. في المرة الأولى بالإعداد الافتراضي `smtp_tls_connection_reuse=no`:

```bash
docker logs --since 10s lab-mail-mta 2>&1 | grep -c "status=sent"
docker logs --since 10s lab-mail-mta 2>&1 | grep "status=sent" | grep -c "conn_use="
```

```text
50
0
```

خمسون رسالة ولا توجد أي رسالة على اتصال مستخدم، أي 50 اتصال TCP وTLS كاملاً. ثم نفعل إعادة استخدام اتصالات TLS ونكرر نفس التجربة:

```bash
docker exec lab-mail-mta postconf -e smtp_tls_connection_reuse=yes
docker exec lab-mail-mta postfix reload
# ... the same 50 deferred messages, then postqueue -f ...
docker logs --since 10s lab-mail-mta 2>&1 | grep -c "status=sent"
docker logs --since 10s lab-mail-mta 2>&1 | grep "status=sent" | grep -c "conn_use="
docker logs --since 10s lab-mail-mta 2>&1 | grep "status=sent" | grep -o "conn_use=[0-9]*" | sort -t= -k2 -n | uniq -c
```

```text
50
36
      8 conn_use=2
      8 conn_use=3
      6 conn_use=4
      5 conn_use=5
      4 conn_use=6
      3 conn_use=7
      1 conn_use=8
      1 conn_use=9
```

36 رسالة من 50 ذهبت على اتصال مفتوح من قبل، أي أن Postfix فتح 14 اتصالاً فقط بدل 50، واستخدم أطولها لتسع رسائل، وفي تشغيل آخر كانت النتيجة 15 اتصالاً. ويظهر الفرق في سطر التسليم نفسه، فهذا سطر رسالة فتحت اتصالاً جديداً ثم سطر رسالة على اتصال مستخدم:

```text
Oct 06 05:28:16 mx postfix/smtp[481]: 28C6EB2405: to=<user1@example.net>, relay=mx.example.net[192.168.80.4]:1025, delay=10, delays=10/0/0.05/0, dsn=2.0.0, status=sent (250 2.0.0 Ok: queued as 6nV0jRISuLifZ2WtWnHEl5)
Oct 06 05:28:16 mx postfix/smtp[472]: 3D312B240E: to=<user10@example.net>, relay=mx.example.net[192.168.80.4]:1025, conn_use=2, delay=10, delays=10/0.15/0/0, dsn=2.0.0, status=sent (250 2.0.0 Ok: queued as 4QOBU4yxRBMnB0aeihxR88)
```

والحقل `delays` فيه أربعة أزمنة كما تشرح [وثائق Postfix](https://www.postfix.org/postconf.5.html?ref=arabroot.io#delay%5Flogging%5Fresolution%5Flimit): من وصول الرسالة حتى دخولها الطابور النشط، ثم حتى بداية الاتصال، ثم إعداد الاتصال، وهو مع الاتصال الجديد يشمل DNS وTCP و`EHLO` و`STARTTLS`، ثم نقل الرسالة. ولاحظ أن الزمن الثالث `0.05` في السطر الأول و`0` في الثاني لأن الاتصال كان جاهزاً، فالعشر ثوان في أول الحقل هي فقط وقت انتظار الرسالة في الطابور أثناء التجربة. وتذكر الوثيقة أن الفائدة الحقيقية تظهر في حالتين: الوجهة التي لها عدة سيرفرات بعضها لا يرد، والسيرفرات التي تحدد عدد الاتصالات الجديدة، وهذه الحالة الثانية هي موضوع القسم التالي.

### لماذا لا تفتح اتصالات كثيرة بالتوازي؟

قد تفكر أن الحل الأسرع ليس إعادة الاستخدام، وإنما أن تفتح 50 اتصالاً معاً وترسل الرسائل كلها في نفس اللحظة، وعلى جهازك سوف ينجح هذا وقد يكون أسرع. ولكن السيرفر المستقبل لا يرى «تطبيقاً سريعاً»، وإنما يرى عنوان IP واحداً فتح فجأة عشرات الاتصالات، وهذا بالضبط شكل البرامج المزعجة، لذلك تضع السيرفرات حدوداً على عدد الاتصالات المتزامنة وعلى معدلها. وفي Postfix مثلاً يحدد [smtpd\_client\_connection\_count\_limit](https://www.postfix.org/postconf.5.html?ref=arabroot.io#smtpd%5Fclient%5Fconnection%5Fcount%5Flimit) عدد الاتصالات المتزامنة من كلاينت واحد، وقيمته الافتراضية 50، ولنرى الرد عندما تتجاوزه جعلناه 3 في المختبر وفتحنا خمسة اتصالات:

```bash
docker exec lab-mail-mta sh -c 'postconf -e smtpd_client_connection_count_limit=3 && postfix reload'
python3 -c "
import smtplib
conns = []
for i in range(1, 6):
    try:
        s = smtplib.SMTP('mx.example.org', 25, local_hostname='mx.example.net')
        code, msg = s.ehlo()
        print(i, code, msg.split(b'\n')[0].decode())
        conns.append(s)
    except Exception as e:
        print(i, type(e).__name__, e)
"
```

```text
1 250 mx.example.org
2 250 mx.example.org
3 250 mx.example.org
4 SMTPConnectError (421, b'4.7.0 mx.example.org Error: too many connections from 192.168.80.3')
5 SMTPConnectError (421, b'4.7.0 mx.example.org Error: too many connections from 192.168.80.3')
```

وفي سجل Postfix:

```text
Oct 06 05:15:50 mx postfix/smtpd[348]: warning: Connection concurrency limit exceeded: 4 from lab-mail-client.lab-mail-net[192.168.80.3] for service smtp
```

الرد `421` مؤقت، فالسيرفر المرسل الجيد يعيد المحاولة لاحقاً، ولكن التطبيق الذي يرسل مباشرة دون طابور يفقد الرسالة، والسيرفرات الكبيرة أشد من ذلك، فقائمة [أخطاء SMTP في Gmail](https://support.google.com/a/answer/3726730?ref=arabroot.io) فيها الرد `421 4.7.28` الذي يقول إن Gmail لاحظ معدلاً غير معتاد من البريد من عنوانك أو نطاقك فحد منه مؤقتاً، والرد `450 4.2.1` عندما يستقبل المستلم بريداً بمعدل أكبر مما يسمح به. وبالتالي فالمعدل والتوازي يؤثران في سمعة عنوانك وفي وصول بريدك، وليس في السرعة فقط. لذلك القواعد العملية:

- أعد استخدام الاتصال بدل أن تفتح اتصالاً لكل رسالة، فهذا أسرع لك وأخف على السيرفر الآخر.
- أبق الاتصالات المتوازية قليلة، فالقيمة الافتراضية 5 في Nodemailer معقولة، واستخدم `rateLimit` إذا كانت خدمة الإرسال تحدد معدلاً.
- لا ترسل من التطبيق مباشرة إلى سيرفرات المستلمين، وإنما إلى MTA أو خدمة إرسال لها طابور تعيد المحاولة عند 4xx، فهذا ما رأيته في [قسم الطابور](#queue-retry).

أعد القيمة إلى 50 بالأمر `postconf -e smtpd_client_connection_count_limit=50` ثم `postfix reload`، وعندما تنتهي من المختبر احذفه كاملاً من مجلد `mail-lab`:

```bash
docker compose down --rmi local
```

الخيار `--rmi local` يحذف ال Images التي بناها Compose لـ Postfix والكلاينت فقط، ويترك Images Mailpit وDovecot التي نزلها من Docker Hub.

## أدوات الفحص التي تحتاجها

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

- **swaks:** [سكين الجيش السويسري لـ SMTP](https://github.com/jetmore/swaks?ref=arabroot.io)، يرسل رسالة اختبار ويكتب المحادثة كاملة، ويدعم STARTTLS والتشفير المباشر بالخيار `--tlsc` وتسجيل الدخول والرؤوس المخصصة، وهو أول ما تجربه بعد أي تغيير في إعداد الإرسال. ولا تنس الحزم التي تضيف له TLS وتسجيل الدخول.
- **openssl s\_client:** يفتح اتصالاً مشفراً ويعرض الشهادة والإصدار، بالخيار `-starttls smtp` أو `-starttls imap` للمنافذ التي تبدأ مكشوفة، ودونه للمنافذ 465 و993 و995، وهو الطريقة الأسرع لترى هل الشهادة منتهية أو لاسم آخر.
- **nc:** لكتابة المحادثة بيدك على المنافذ المكشوفة 25 و587 قبل STARTTLS، مع الخيار `-C` لنهاية السطر الصحيحة، وأبسط استخدام له أن ترى هل يصل سطر التحية `220` أصلاً، فإذا لم يصل فالمشكلة في جدار الحماية أو في حجب المنفذ وليست في إعداد البريد.
- **dig:** لسجلات MX وA وPTR، وقد جمعنا أوامره لكل سجل بريد في [مقال SPF وDKIM وDMARC](https://arabroot.io/articles/%D8%B4%D8%B1%D8%AD-spf-%D9%88-dkim-%D9%88-dmarc-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/#dig-commands).
- **Mailpit:** سيرفر SMTP للاختبار يمسك كل رسالة يرسلها تطبيقك أثناء التطوير ويعرضها في المتصفح، فلا تصل رسالة تجريبية إلى عميل حقيقي، وتستطيع أن تختبر به رد تطبيقك على أخطاء 4xx و5xx بميزة Chaos كما فعلنا.
- **سجل الخادم والطابور:** في Postfix الأمر `postqueue -p` للطابور و`postqueue -f` لإعادة المحاولة الآن، والسجل بالبحث عن رقم الرسالة، وأهم ما فيه الحقلان `status=` و`dsn=` والرد الذي قاله السيرفر الآخر بين قوسين.
- **الفحص من الخارج:** خدمات مثل [mail-tester.com](https://www.mail-tester.com/?ref=arabroot.io) و[internet.nl](https://internet.nl/test-mail/?ref=arabroot.io) ترسل لها رسالة حقيقية أو تفحص نطاقك، فتخبرك عن سجلات المصادقة وعن STARTTLS وغيرها، وقد شرحنا ما تفحصه كل خدمة في [قسم الاختبار في مقال SPF وDKIM وDMARC](https://arabroot.io/articles/%D8%B4%D8%B1%D8%AD-spf-%D9%88-dkim-%D9%88-dmarc-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/#testing).

## أخطاء شائعة

- **إعداد برنامج البريد أو التطبيق على المنفذ 25:** المنفذ 25 للسيرفرات، وأغلب الخوادم لا تقبل عليه تسجيل الدخول، وكثير من المزودين يحجبونه صادراً، فتبدو المشكلة وكأنها «السيرفر لا يرد». استخدم 465 أو 587.
- **اعتبار `250 queued` وصولاً:** هذا الرد يعني أن سيرفرك قبل الرسالة فقط، وقد تبقى في طابوره أياماً أو ترتد، لذلك عندما يقول المستخدم «أرسلت ولم تصل» ابدأ بسجل سيرفرك والطابور قبل أي شيء آخر.
- **إعادة المحاولة عند 5xx أو تجاهل 4xx:** التطبيق الذي يعيد إرسال رسالة رفضت بـ 550 يضر سمعة عنوانه، والذي يتجاهل 421 أو 451 يفقد رسائل كان يمكن أن تصل، والحل أن ترسل إلى MTA أو خدمة لها طابور.
- **قبول الرسالة ثم إرجاعها:** يرسل رسائل مرتدة إلى عناوين مزورة لأشخاص أبرياء، فتحقق من المستلم عند `RCPT TO`.
- **الخلط بين الظرف والرؤوس:** البحث عن سبب الرسالة المرتدة في `From:` بدل `Return-Path`، أو الظن أن `To:` هو من استلم الرسالة فعلاً.
- **إطفاء التحقق من الشهادة في كود الإرسال:** سطرا المختبر في `send.py` يجعلان كلمة مرور SMTP تذهب لأي سيرفر يدعي أنه سيرفرك، فلا تنقلهما إلى تطبيق حقيقي.
- **اتصال جديد لكل رسالة، أو عشرات الاتصالات المتوازية:** الأول بطيء ويرهق سيرفر الإرسال بتسجيل الدخول، والثاني يجلب ردود 421 وحدود المعدل، والصحيح اتصالات قليلة يعاد استخدامها.
- **POP3 لمستخدمين لديهم أكثر من جهاز:** ينزل البريد إلى أول جهاز يتصل ويحذفه من السيرفر عادة، فيجد الهاتف صندوقاً فارغاً، وتضيع الرسائل إذا تعطل ذلك الجهاز.

## قائمة تحقق

1. هل تعرف أي برنامج في منظومتك يقوم بكل دور: من يستقبل من المستخدمين، ومن ينقل بين السيرفرات، ومن يكتب في الصناديق، ومن يخدم القراءة؟
2. هل سجل MX لنطاقك يشير إلى اسم سيرفر له سجل A، وهل تعرف ماذا يرى `dig +short MX` لنطاقك؟
3. هل المنفذ 25 مفتوح للاستقبال، وهل الاتصال الصادر على 25 مسموح من مزودك، أو لديك خادم وسيط؟
4. هل منفذ الإرسال 465 أو 587 يطلب TLS قبل تسجيل الدخول، ويرفض الإرسال إلى الخارج دون تسجيل دخول؟
5. هل المنفذ 25 يرفض التمرير إلى نطاقات غيرك برفض دائم بعد أن تأكدت من إعدادك؟
6. هل مستخدموك على 993 و465، ومنافذ STARTTLS وهي 587 و143 و110 فقط لمن يحتاجها؟
7. هل تتحقق من المستلم أثناء المحادثة بدل قبول الرسالة ثم إرجاعها؟
8. هل تطبيقك يرسل إلى MTA أو خدمة لها طابور، ويعيد استخدام الاتصال، ويبقي الاتصالات المتوازية قليلة؟
9. هل تعرف أين تجد الطابور والسجل على سيرفرك، وكيف تتبع رسالة برقمها؟

## الخلاصة

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

- الرسالة تمر بأدوار واضحة: برنامج البريد MUA، ثم بوابة الإرسال MSA بتسجيل دخول على 587 أو 465، ثم MTA يسأل DNS عن سجل MX ويسلم على المنفذ 25، ثم MDA يكتبها في الصندوق، ثم يقرؤها البرنامج عبر IMAP أو POP3 أو JMAP.
- SMTP محادثة نصية، والخانة الأولى من الرد هي القرار: 2xx نجاح، و3xx أكمل، و4xx حاول لاحقاً من الطابور، و5xx لا تحاول وأرسل رسالة مرتدة بمرسل فارغ إلى عنوان الظرف.
- الظرف `MAIL FROM` و`RCPT TO` تقرؤه السيرفرات، والرؤوس `From:` و`To:` يقرؤها الإنسان، والاثنان مستقلان، ومنه جاءت النسخة المخفية Bcc وجاء الانتحال الذي يعالجه DMARC.
- المنفذ 25 للسيرفرات بتشفير انتهازي، و465 و993 و995 بتشفير مباشر هي الأفضل لمستخدميك كما يوصي RFC 8314، و587 مع STARTTLS للبرامج التي تحتاجه.
- أعد استخدام اتصال SMTP في تطبيقك وفي Postfix، فقد أرسلنا 50 رسالة على اتصال واحد أسرع عدة مرات، وأرسل Postfix 50 رسالة على 14 اتصال TLS بدل 50 بعد تفعيل `smtp_tls_connection_reuse`، وأبق الاتصالات المتوازية قليلة لأن السيرفرات المستقبلة ترد بـ 421 وتحد من معدلك.

وهذه المقالات تكمل الصورة بحسب ما تريد أن تفعله بعد ذلك:

[![](https://arabroot.io/content/images/2026/10/email-hosting-guide-cover-cover.webp)دليلكيف تستضيف بريد مؤسستك بنفسك، من القرار إلى التشغيلمتى تستضيف بريد شركتك بنفسك ومتى يكون البريد المستضاف أنسب، وكيف تنقل المستخدمين على مراحل دون أن تضيع رسالة.](https://arabroot.io/articles/%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D8%B3%D8%AA%D8%B6%D8%A7%D9%81%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%8A%D8%AF-%D8%A7%D9%84%D8%A5%D9%84%D9%83%D8%AA%D8%B1%D9%88%D9%86%D9%8A-%D9%84%D9%84%D9%85%D8%A4%D8%B3%D8%B3%D8%A7%D8%AA/)[![](https://arabroot.io/content/images/2026/10/dns-records-cover-cover.webp)دليلشرح DNS وسجلاته للمبتدئين بمثال حقيقيكيف يتحول اسم نطاقك إلى عنوان سيرفرك، وما وظيفة كل سجل تضيفه في لوحة النطاق، والأخطاء التي تضيع فيها الساعات عادة.](https://arabroot.io/articles/%D8%B4%D8%B1%D8%AD-dns-%D9%88%D8%B3%D8%AC%D9%84%D8%A7%D8%AA%D9%87-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/)[![](https://arabroot.io/content/images/2026/10/email-authentication-cover-cover.webp)دليلشرح SPF وDKIM وDMARC للمبتدئين: كيف تثبت أن رسائلك منك فعلاًلماذا يستطيع أي شخص أن يرسل باسم نطاقك، وكيف يسد كل سجل من هذه السجلات الثلاثة ثغرة تركها الذي قبله.](https://arabroot.io/articles/%D8%B4%D8%B1%D8%AD-spf-%D9%88-dkim-%D9%88-dmarc-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/)[![](https://arabroot.io/content/images/2026/10/postfix-dovecot-cover-cover.webp)دليلبناء خادم بريد بيدك مع Postfix وDovecot على Ubuntuنبني خادم بريد كاملاً من حزم Ubuntu دون Docker، فتعرف دور كل مكون وأين تبحث عندما تتوقف رسالة.](https://arabroot.io/articles/%D8%AE%D8%A7%D8%AF%D9%85-%D8%A8%D8%B1%D9%8A%D8%AF-postfix-%D9%88-dovecot-%D9%8A%D8%AF%D9%88%D9%8A%D8%A7/)[![](https://arabroot.io/content/images/2026/10/transactional-email-cover-cover.webp)دليلTransactional Email: كيف تصل رسائل تطبيقك في وقتهالماذا تفصل رسائل تطبيقك مثل استعادة كلمة المرور عن النشرات البريدية، وكيف ترسلها بحيث تصل في وقتها ولا تذهب إلى Spam.](https://arabroot.io/articles/%D8%A7%D9%84%D8%A8%D8%B1%D9%8A%D8%AF-%D8%A7%D9%84%D8%AA%D9%81%D8%A7%D8%B9%D9%84%D9%8A-transactional-email/)[![](https://arabroot.io/content/images/2026/10/connection-pooling-cover-cover.webp)دليلConnection Pooling: لماذا الاتصال بقاعدة البيانات مكلفلماذا تظهر رسالة too many clients عندما تزيد نسخ تطبيقك، وكيف يحل مجمع الاتصالات وPgBouncer هذه المشكلة.](https://arabroot.io/articles/%D8%AA%D8%AC%D9%85%D9%8A%D8%B9-%D8%A7%D9%84%D8%A7%D8%AA%D8%B5%D8%A7%D9%84%D8%A7%D8%AA-connection-pooling-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/)

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

- أكتوبر 2026: كتابة المقال واختباره على Postfix 3.10.13 من حزمة Debian 13 وDovecot 2.4.5 وMailpit 1.31.4 وswaks 20240103.0 مع Docker Engine 29.8.0.
- أكتوبر 2026: إضافة رابط إلى مقال الفرق بين SMTP والترحيل Relay في قسم حجب المنفذ 25، وتصحيح جملة منافذ الإرسال لأن بعض المزودين يحجبونها أيضاً.