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

تثبيت listmonk لإدارة النشرات البريدية على خادمك

إذا كانت نشرتك البريدية تخرج اليوم من Gmail بخانة BCC أو من خدمة يرتفع سعرها مع كل مشترك، فسوف نثبت في هذا الدليل listmonk مع PostgreSQL على سيرفرك، ونربطه بمزود SMTP تختاره أنت، ثم نرسل أول حملة ونعالج الرسائل المرتدة، وتبقى قائمة المشتركين لديك.

تثبيت listmonk لإدارة النشرات البريدية على خادمك

في هذا الدليل سوف نثبت listmonk، وهو برنامج مفتوح المصدر Open Source لإدارة النشرات البريدية Newsletters وقوائم المراسلة Mailing Lists، يأتي في ملف تنفيذي واحد Single Binary مكتوب بلغة Go ولا يحتاج إلا إلى PostgreSQL، ففيه قوائم عامة وخاصة مع تأكيد مزدوج للاشتراك double opt-in، وحملات Campaigns بمحرر مرئي Visual Editor أو HTML أو Markdown، وقوالب Templates بلغة Go templates، وتقسيم المشتركين باستعلامات SQL، وإحصاءات الفتح والنقر، ومعالجة الرسائل المرتدة Bounces، وواجهة برمجية API للرسائل التعاملية transactional من تطبيقاتك. والسبب أن البديلين المعتادين لا يصمدان مع نمو القائمة، فخانة BCC في Gmail يحدها خمسمئة مستلم في اليوم ولا يوجد فيها رابط لإلغاء الاشتراك Unsubscribe، وخدمات مثل Mailchimp وBrevo يرتفع سعرها مع كل جهة اتصال Contact وتبقى القائمة على سيرفراتها.

ولاحظ أن listmonk ليس خادم بريد Mail Server، وإنما يدير القوائم والحملات، والإرسال الفعلي يمر عبر خادم SMTP وسيط SMTP Relay تحدده أنت مثل Amazon SES، وإذا كنت تحتاج إلى أتمتة تسويقية Marketing Automation بمسارات متعددة الخطوات فابق على خدمة متخصصة. أما لماذا لا ترسل النشرات من خادم البريد الأساسي لمؤسستك، فقد شرحناه في دليل استضافة البريد الإلكتروني للمؤسسات.

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

  • تثبيت listmonk مع PostgreSQL باستخدام Docker Compose، بسطر تشغيل واحد يثبت قاعدة البيانات مرة واحدة ويرقيها تلقائياً عند كل إصدار جديد.
  • ربط النطاق عبر ال Reverse Proxy، ثم الإعداد الأول وإعداد SMTP.
  • القوائم والمشتركون، وإرسال أول حملة، والقوالب، ومعالجة الرسائل المرتدة.
  • النسخ الاحتياطي والاستعادة، والتحديث، وأشهر المشكلات وحلولها.

المتطلبات

  • خادم Linux بمعالج CPU واحد وذاكرة RAM بحجم 1 GB، وهذا يكفي لقوائم بعشرات الآلاف، والسبب أن listmonk نفسه لا يستهلك إلا عشرات الميغابايتات، وأغلب الذاكرة تذهب إلى PostgreSQL.
  • Docker Engine مع ملحق Docker Compose، كما في دليل تثبيت Docker على Ubuntu.
  • نطاق فرعي Subdomain مثل lists.example.com يشير إلى الخادم، وReverse Proxy يصدر شهادة TLS مثل Nginx Proxy Manager، ويجب أن يكون النطاق عاماً، والسبب أن روابط إلغاء الاشتراك وتتبع النقرات Click Tracking في كل رسالة تستخدمه.
  • حساب SMTP للإرسال الجماعي Bulk Sending، مع سجلات SPF وDKIM وDMARC لنطاق المرسل Sender Domain كما شرحناها في شرح SPF وDKIM وDMARC للمبتدئين، والأفضل أن تخصص للنشرات نطاقاً فرعياً مثل news.example.com، حتى لا تتأثر سمعة Reputation البريد الأساسي للشركة إذا اشتكى بعض المشتركين من رسائلك.

التثبيت

المجلد وملف الأسرار Secrets

أول خطوة هي أن ننشئ مجلد التثبيت ومجلد الملفات المرفوعة:

sudo mkdir -p /opt/listmonk/uploads
cd /opt/listmonk

بعد ذلك نولد كلمة مرور لقاعدة البيانات Database وأخرى للمدير الأول، ونحفظهما في الملف .env المقروء للمالك فقط، والسبب أننا لا نريد أن نكتب كلمات المرور داخل ملف Compose فتظهر في كل نسخة منه:

sudo tee /opt/listmonk/.env >/dev/null <<EOF
POSTGRES_PASSWORD=$(openssl rand -hex 24)
LISTMONK_ADMIN_USER=admin
LISTMONK_ADMIN_PASSWORD=$(openssl rand -base64 18)
EOF
sudo chmod 600 /opt/listmonk/.env
sudo cat /opt/listmonk/.env

احتفظ بكلمة مرور المدير التي تظهر لك لأنك سوف تحتاجها عند الدخول الأول، ولاحظ أن listmonk يقرأ متغيرات البيئة Environment Variables LISTMONK_ADMIN_USER وLISTMONK_ADMIN_PASSWORD في التثبيت الأول فقط لينشئ حساب المدير Super Admin، وإذا تركتهما فارغين فسوف يطلب منك إنشاء الحساب من المتصفح عند الزيارة الأولى، كما يوضح دليل التثبيت الرسمي.

ملف docker-compose.yml

بنينا هذا الملف على الملف الرسمي للإصدار 6.2.0، وغيرنا فيه أربعة أمور: ثبتنا الوسوم Tags بدل latest، ونقلنا كلمة المرور إلى .env، وربطنا المنفذ بالعنوان المحلي localhost خلف ال Reverse Proxy، وجعلنا التطبيق ينتظر جاهزية Readiness قاعدة البيانات. افتح الملف:

sudo nano /opt/listmonk/docker-compose.yml

والملف سوف يكون كما يلي:

name: listmonk

services:
  app:
    image: listmonk/listmonk:v6.2.0
    restart: unless-stopped
    ports:
      - "127.0.0.1:9000:9000"
    hostname: lists.example.com
    depends_on:
      db:
        condition: service_healthy
    command: [sh, -c, "./listmonk --install --idempotent --yes --config '' && ./listmonk --upgrade --yes --config '' && ./listmonk --config ''"]
    environment:
      LISTMONK_app__address: 0.0.0.0:9000
      LISTMONK_db__host: db
      LISTMONK_db__port: 5432
      LISTMONK_db__user: listmonk
      LISTMONK_db__password: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env}
      LISTMONK_db__database: listmonk
      LISTMONK_db__ssl_mode: disable
      LISTMONK_db__max_open: 25
      LISTMONK_db__max_idle: 25
      LISTMONK_db__max_lifetime: 300s
      TZ: Etc/UTC
      LISTMONK_ADMIN_USER: ${LISTMONK_ADMIN_USER:-}
      LISTMONK_ADMIN_PASSWORD: ${LISTMONK_ADMIN_PASSWORD:-}
    volumes:
      - ./uploads:/listmonk/uploads:rw

  db:
    image: postgres:17.11-alpine
    restart: unless-stopped
    environment:
      POSTGRES_USER: listmonk
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env}
      POSTGRES_DB: listmonk
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U listmonk -d listmonk"]
      interval: 10s
      timeout: 5s
      retries: 6
    volumes:
      - listmonk-data:/var/lib/postgresql/data

volumes:
  listmonk-data:

أهم سطر في هذا الملف هو command، وفهمه يجنبك أشهر خطأ في تثبيتات listmonk القديمة، حيث كانت الأدلة السابقة تستخدم yes | ./listmonk --install ثم تطلب منك تعديل هذا السطر بعد التشغيل الأول، والسبب أن تكرار --install بهذا الشكل يمسح قاعدة البيانات في كل مرة يعاد فيها إنشاء ال Container، ومن ينسى التعديل يكتشف ذلك بعد أول تحديث. أما السطر الحالي فيجمع ثلاث خطوات آمنة، وفي الإعداد أعلاه لاحظ التالي:

  • --install --idempotent: ينشئ الجداول Tables فقط إذا كانت قاعدة البيانات فارغة، وفي التشغيلات اللاحقة يكتب في السجل أن القاعدة مثبتة مسبقاً ويتجاوز التثبيت.
  • --upgrade: ينفذ ترحيلات Migrations قاعدة البيانات حين تسحب إصداراً أحدث، ولا أثر له إذا كانت القاعدة محدثة.
  • --config '': يجعل listmonk يقرأ إعداداته من متغيرات LISTMONK_* وحدها وليس من الملف config.toml، والمتغير LISTMONK_db__host مثلاً يقابل المفتاح host في القسم [db]، وتجد قائمة هذه المتغيرات في توثيق الإعدادات.
  • منفذ الويب مربوط بالعنوان 127.0.0.1 فقط، والسبب أن ال Reverse Proxy وحده هو الذي يصل إليه، فلا يفتح أحد لوحة الإدارة عبر HTTP غير مشفر.

وبقية الإعدادات مثل SMTP والنطاق والرسائل المرتدة يحفظها listmonk في قاعدة البيانات، وتديرها أنت من الواجهة كما سيأتي.

التشغيل

الآن سوف نقوم بتشغيل الخدمتين ومتابعة سجل التطبيق:

cd /opt/listmonk
sudo docker compose up -d
sudo docker compose logs -f app

وعند التشغيل الأول سوف تجد في السجل Logs السطر creating superadmin user 'admin'، ثم السطر no upgrades to run. Database is up to date. وهو ناتج خطوة --upgrade، وأخيراً السطر http server started on [::]:9000 الذي يعني أن التطبيق جاهز. بعد ذلك تحقق أن الخدمة تعمل:

curl -s http://127.0.0.1:9000/health

والمخرج سوف يكون {"data":true}.

ربط النطاق عبر ال Reverse Proxy

في Nginx Proxy Manager أنشئ مضيفاً Proxy Host للنطاق lists.example.com يوجه إلى المنفذ 9000 على الخادم، مع شهادة Let's Encrypt وخيار Force SSL، ولأن رفع ملفات CSV كبيرة لاستيراد المشتركين قد يتجاوز الحد الافتراضي لحجم الطلب Request Body Size، فأضف في تبويب Advanced الإعداد التالي:

client_max_body_size 50m;

وإذا كنت تستخدم Caddy فيكفيك ما يلي:

lists.example.com {
    reverse_proxy 127.0.0.1:9000
}

الإعداد الأول

الإعدادات العامة

ادخل إلى https://lists.example.com/admin بحساب المدير، وابدأ بضبط ما يلي في Settings ← General:

  • Root URL: العنوان العام https://lists.example.com دون شرطة مائلة في آخره، والقيمة الافتراضية هي http://localhost:9000، فإذا نسيت تغييرها خرجت روابط إلغاء الاشتراك والتتبع في كل رسائلك معطلة.
  • Default from email: اسم المرسل وعنوانه، مثل Example Co Newsletter <[email protected]>، ويجب أن يكون العنوان من نطاق ضبطت له SPF وDKIM لدى مزود SMTP.
  • Admin notification e-mails: عنوان يصله إشعار عند انتهاء الحملات أو اكتمال الاستيراد.
  • إذا كانت لديك قوائم عامة، ففعل من قسم Subscriptions صفحة الاشتراك العامة وإرسال رسالة تأكيد الاشتراك.
الإعدادات العامة في listmonk وفيها Root URL وعنوان المرسل
Settings ← General: عنوان التثبيت العام وعنوان المرسل الافتراضي

ثم أنشئ من Users حسابات منفصلة لفريق التسويق بأدوار Roles محدودة الصلاحيات Permissions، ولا تقم بمشاركة حساب المدير بين الجميع، والسبب أنك لن تعرف من أرسل ماذا، ولن تستطيع سحب صلاحية شخص واحد دون تغيير كلمة المرور على الكل، والخيارات المتاحة مشروحة في توثيق الأدوار والصلاحيات.

إعداد SMTP

من Settings ← SMTP تضيف خادماً واحداً أو أكثر، وإذا فعلت عدة خوادم فإن listmonk يوزع الرسائل بينها، وهذا مفيد حين يكون لكل حساب حد يومي للإرسال Sending Limit. وتحت حقول الخادم أزرار جاهزة لمزودين مثل Gmail وAmazon SES وMailgun وSendgrid وPostmark تملأ المضيف والمنفذ لكل منهم، والقيم المعتادة كما يلي:

الحقلالقيمة المعتادة
Hostsmtp.example.com أو خادم مزودك
Port و TLS587 مع STARTTLS، أو 465 مع TLS
Auth protocolLOGIN أو PLAIN بحسب المزود
Username و Passwordبيانات حساب الإرسال، أو مفتاح SMTP الذي يصدره المزود
Max. connectionsعدد الاتصالات المتوازية Concurrent Connections، على ألا يتجاوز ما يسمح به المزود
Retries و Retry delayإعادة المحاولة حين يفشل إرسال رسالة فشلاً مؤقتاً
إعدادات خادم SMTP في listmonk
إعداد SMTP يوجه هنا إلى Mailpit، وهو خادم تجريبي محلي. أما في الإنتاج (Production) فضع خادم مزودك مع STARTTLS أو TLS
⚠️
يرفض listmonk إرسال كلمة المرور عبر اتصال غير مشفر، فإذا وجهته إلى خادم لا يدعم TLS مع المصادقة Authentication PLAIN فسوف تفشل رسائل الحملة كلها ويظهر في السجل الخطأ unencrypted connection، ومع ذلك تظهر الحملة بحالة «Finished» وعدد الرسائل المرسلة 0. لذلك استخدم STARTTLS أو TLS مع أي مزود حقيقي، وأما مع خادم تجريبي محلي غير مشفر فاجعل قيمة Auth protocol هي none.

بعد الحفظ يعيد listmonk تحميل إعداداته تلقائياً، وبعد الإرسال الأول راجع السجل لتتأكد أنه تم دون أخطاء:

cd /opt/listmonk
sudo docker compose logs --tail=50 app

القوائم والمشتركون

القائمة List هي مجموعة المشتركين التي ترسل إليها الحملة، والمشترك الواحد قد ينتمي إلى عدة قوائم. أنشئ قائمة من Lists ← New:

  • Type: القائمة من نوع Public تظهر في صفحة الاشتراك العامة وفي نماذج الاشتراك Signup Forms، والنوع Private للقوائم الداخلية التي تديرها أنت وحدك.
  • Opt-in: مع Double opt-in تصل المشترك رسالة تأكيد، ولا يرسل listmonk الحملات إلا لمن أكد اشتراكه، والسبب في أهمية ذلك أن أي شخص يستطيع أن يكتب في نموذج الاشتراك عنواناً ليس له أو عنواناً وهمياً، والرسائل إلى هذه العناوين ترتد أو تتحول إلى شكاوى تضر سمعة الإرسال، لذلك هو الخيار الموصى به للقوائم العامة.
نافذة إنشاء قائمة جديدة في listmonk
قائمة عامة بتأكيد مزدوج للاشتراك

أضف المشتركين يدوياً من Subscribers ← New، أو استوردهم دفعة واحدة من Subscribers ← Import بملف CSV فيه العمودان email وname على الأقل، أو عبر ال API من تطبيقك، وعند الاستيراد إلى قائمة بتأكيد مزدوج يمكنك اعتبار المستوردين مؤكدين إذا كانوا قد وافقوا مسبقاً في نظامك السابق. وصفحة Lists تعرض كل قائمة مع عدد مشتركيها:

قائمة القوائم في listmonk مع أعداد المشتركين
القائمة Monthly Newsletter بخمسة مشتركين مؤكدين، إلى جانب القائمتين التجريبيتين اللتين ينشئهما listmonk عند التثبيت

لاحظ أن القائمتين Default list وOpt-in list والحملة Test campaign بيانات تجريبية ينشئها التثبيت، فاحذفها قبل أن تبدأ العمل الفعلي حتى لا ترسل إليها حملة بالخطأ.

إنشاء حملة وإرسالها

من Campaigns ← Create new أدخل اسماً داخلياً للحملة وعنوان الرسالة Subject، واختر القائمة، ثم اضغط Continue:

نموذج إنشاء حملة جديدة
بيانات الحملة الأساسية، ومربع Send test message على اليمين

في تبويب Content تكتب الرسالة بالمحرر المرئي أو بلغة HTML أو Markdown أو نصاً عادياً، وتختار القالب، ويمكنك أن تستخدم في النص متغيرات المشترك مثل {{ .Subscriber.FirstName }} للاسم الأول، و{{ .Subscriber.Attribs.city }} لأي خاصية Attribute محفوظة في بيانات المشترك:

محرر محتوى الحملة مع متغير اسم المشترك
محتوى الحملة مع المتغير {{ .Subscriber.FirstName }} وزر Preview للمعاينة

وقبل الإرسال الفعلي أرسل نسخة تجريبية إلى عنوانك من مربع Send test message في تبويب Campaign، ولاحظ أن العنوان يجب أن يكون لمشترك موجود في listmonk، ثم افحص الشكل والروابط على الهاتف والحاسوب، وبعد ذلك اضغط Start campaign وأكد الإرسال. وسوف يعرض listmonk تقدم الإرسال وعدد الرسائل المرسلة، ويمكنك إيقاف الحملة مؤقتاً ثم استئنافها:

قائمة الحملات مع حملة منتهية أرسلت خمس رسائل
الحملة بحالة Finished وقد أرسلت 5 من 5

والصورة التالية تبين إحدى الرسائل كما وصلت إلى Mailpit، حيث حل اسم المشتركة محل المتغير، وفي أسفل الرسالة رابطان يضيفهما القالب الافتراضي، أحدهما لإلغاء الاشتراك والآخر للعرض في المتصفح:

رسالة الحملة كما التقطها Mailpit
الرسالة المستلمة، مع ترويسة (Header) List-Unsubscribe التي تظهر زراً باسم Unsubscribe في برامج البريد

ويضيف listmonk إلى كل رسالة ترويسة List-Unsubscribe تلقائياً ومعها الترويسة List-Unsubscribe-Post: List-Unsubscribe=One-Click التي تسمح بإلغاء الاشتراك بنقرة واحدة One-Click Unsubscribe وفق المعيار RFC 8058، وهذا مهم لأن Gmail وYahoo تشترطان على من يرسل 5000 رسالة أو أكثر في اليوم أن يدعم إلغاء الاشتراك بنقرة واحدة، وأن يضبط SPF وDKIM وDMARC، وأن تبقى نسبة البلاغات عن البريد المزعج تحت 0.3%. لذلك لا تقم بحذف رابط إلغاء الاشتراك من القوالب، ولا تقم بتعطيل الخيار الذي يضيف هذه الترويسة في إعدادات الخصوصية Privacy.

القوالب

من Campaigns ← Templates تدير قوالب الحملات والرسائل التعاملية، والقالب ملف HTML فيه الترويسة والتذييل Footer وشعار الشركة، ويضع listmonk محتوى الحملة مكان الوسم {{ template "content" . }}. انسخ القالب الافتراضي وعدله بدلاً من الكتابة من الصفر، ثم اجعله القالب الافتراضي للحملات الجديدة:

قائمة القوالب في listmonk
القوالب الافتراضية: قالب حملة، وقالب أرشيف، وقالب تعاملي، وقالب مرئي تحرره بالسحب والإفلات (Drag and Drop)

أما القوالب التعاملية Transactional فتستخدمها تطبيقاتك لإرسال رسائل فردية عبر POST /api/tx، مثل رسالة ترحيب أو إشعار، وتعتمد على إعدادات SMTP نفسها.

معالجة الرسائل المرتدة

الرسائل المرتدة bounces هي رسائل ترفضها الخوادم المستقبلة، فإذا كان العنوان غير موجود فهذا ارتداد دائم hard، وإذا كان الصندوق ممتلئاً مؤقتاً فهذا ارتداد مؤقت soft، والشكاوى complaints تصل حين يصنف المستلم رسالتك بريداً مزعجاً Spam. والاستمرار في الإرسال إلى هذه العناوين هو أسرع طريق إلى إيقاف حسابك لدى مزود الإرسال، لذلك فعل المعالجة من Settings ← Bounces وفق توثيق الرسائل المرتدة:

إعدادات معالجة الارتدادات في listmonk
عدد الارتدادات قبل اتخاذ إجراء لكل نوع (soft وhard وcomplaint)، ومصدر الارتدادات: webhooks أو صندوق بريد
  • الإجراءات: القيم الافتراضية معقولة، فلا يتخذ listmonk أي إجراء بعد ارتدادين مؤقتين، ويحظر العنوان Blocklist بعد ارتداد دائم واحد أو شكوى واحدة، والخيار Delete يحذف المشترك نهائياً.
  • Bounce webhooks: الطريقة الأفضل مع مزودي الإرسال، حيث يرسل المزود الرسائل المرتدة مباشرة إلى listmonk، والمسارات المدعومة هي /webhooks/service/ses لخدمة Amazon SES عبر SNS، و/webhooks/service/sendgrid، و/webhooks/service/postmark، و/webhooks/service/forwardemail، و/webhooks/service/lettermint، و/webhooks/service/azure، ومسار عام /webhooks/bounce لأي نظام آخر، وهذا المسار العام يحتاج إلى بيانات مستخدم API في كل طلب.
  • Bounce mailbox: إذا كنت ترسل عبر خادمك الخاص، فأنشئ صندوقاً مثل [email protected] واجعله عنوان Return-Path، ودع listmonk يقرؤه عبر POP3 ويحلل الرسائل المرتدة فيه.

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

  • لا تظهر أخطاء SMTP في Settings ← Logs بعد إرسال رسالة تجريبية.
  • أرسل رسالة تجريبية إلى Gmail وافتح Show original، وسوف تجد أن SPF وDKIM وDMARC بحالة PASS، وأن روابط إلغاء الاشتراك تشير إلى https://lists.example.com.
  • اشترك بعنوان تجريبي من صفحة الاشتراك العامة https://lists.example.com/subscription/form، وتأكد أن رسالة التأكيد وصلت وأنك صرت مؤكداً بعد النقر على رابطها.

نقطة فحص الصحة Health Check Endpoint تستجيب، وقاعدة البيانات تعمل بسلامة:

curl -s https://lists.example.com/health
cd /opt/listmonk
sudo docker compose ps

النسخ الاحتياطي والاستعادة Restore

كل بيانات listmonk موجودة في PostgreSQL، أي المشتركين والقوائم والحملات والقوالب والإعدادات، ويضاف إليها المجلد uploads وفيه الصور المرفوعة في الحملات، لذلك نأخذ النسخة الاحتياطية Backup لقاعدة البيانات بالأداة pg_dump ونضع معها المجلد والملفين .env وdocker-compose.yml:

sudo mkdir -p /opt/backup/listmonk
cd /opt/listmonk
sudo docker compose exec -T db pg_dump -U listmonk -Fc listmonk | sudo tee /opt/backup/listmonk/listmonk-$(date +%F).dump >/dev/null
sudo tar czf /opt/backup/listmonk/uploads-$(date +%F).tgz -C /opt/listmonk uploads .env docker-compose.yml

وللاستعادة على خادم جديد ضع الملفات في أماكنها، وشغل قاعدة البيانات وحدها وانتظر حتى تظهر بحالة healthy في docker compose ps، ثم استورد النسخة بالأداة pg_restore، وبعد ذلك شغل التطبيق:

cd /opt/listmonk
sudo tar xzf /opt/backup/listmonk/uploads-2026-09-26.tgz -C /opt/listmonk
sudo docker compose up -d db
sudo docker compose exec -T db pg_restore -U listmonk -d listmonk --clean --if-exists --no-owner < /opt/backup/listmonk/listmonk-2026-09-26.dump
sudo docker compose up -d

ولاحظ أن التطبيق يبدأ بعد الاستعادة دون أن يمس البيانات، والسبب أن --install --idempotent يجد الجداول موجودة فيتجاوز التثبيت.

📌
في 11 يناير 2023 اكتشف فريق الأمن في Mailchimp أن مهاجماً يصل إلى إحدى أدواته الداخلية، بعد هجوم هندسة اجتماعية Social Engineering على موظفين ومتعاقدين حصل منه على بيانات دخولهم، ومن خلالها وصل إلى 133 حساباً من حسابات العملاء، كما ذكرت الشركة في بيانها الرسمي. والدرس هنا أن قائمة المشتركين على خدمة سحابية يحميها موظفو تلك الخدمة أيضاً وليس أنت وحدك، وفي المقابل فإن القائمة على سيرفرك تجعل حمايتها ونسخها مسؤوليتك بالكامل.

وقائمة المشتركين بيانات شخصية Personal Data، لذلك شفر كل نسخة تخرج من الخادم، وأداة restic تفعل ذلك افتراضياً، وحدد مدة احتفاظ Retention بالنسخ تتوافق مع سياسة الخصوصية Privacy Policy لديك.

التحديث Upgrade إلى إصدار أحدث

بفضل الخيار --upgrade في سطر التشغيل صارت الترقية ثلاث خطوات: نسخة احتياطية، ثم تغيير الوسم، ثم سحب ال Image وإعادة التشغيل، وسوف يرحل listmonk قاعدة البيانات تلقائياً عند الإقلاع، كما يبين دليل الترقية الرسمي:

cd /opt/listmonk
sudo docker compose exec -T db pg_dump -U listmonk -Fc listmonk | sudo tee /opt/backup/listmonk/before-upgrade.dump >/dev/null
sudo sed -i 's|listmonk/listmonk:v6.2.0|listmonk/listmonk:v6.3.0|' docker-compose.yml
sudo docker compose pull app
sudo docker compose up -d
sudo docker compose logs --tail=30 app

ضع مكان v6.3.0 الإصدار المستقر Stable الذي تريده من صفحة الإصدارات على GitHub، واقرأ ملاحظاته أولاً، والسبب أن الإصدارات الرئيسية Major Versions تغير أحياناً طريقة الدخول والصلاحيات، فالإصدار 4 نقل المستخدمين إلى قاعدة البيانات مع صفحة دخول جديدة، والإصدار 6.0.0 أضاف التحقق بخطوتين 2FA وأغلق ثغرة في الصلاحيات. ولا تستخدم الوسمين latest أو nightly، ولا تقم بالترقية أثناء إرسال حملة، بل أوقفها مؤقتاً أو انتظر انتهاءها.

وإذا كان تثبيتك القديم يستخدم السطر yes | ./listmonk --install، فضع مكانه السطر الحالي المذكور أعلاه قبل أي ترقية، وإلا فقد تفقد بياناتك عند إعادة إنشاء ال Container.

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

انتهت الحملة وعدد الرسائل المرسلة صفر

افتح Settings ← Logs أو سجل ال Container، فالخطأ unencrypted connection يعني أن المصادقة تجري دون TLS فاضبط STARTTLS أو TLS، والخطأ 535 Authentication failed يعني أن البيانات خاطئة أو أن المزود يطلب كلمة مرور خاصة بالتطبيق، وGmail مثلاً تطلب App Password مع تفعيل التحقق بخطوتين 2FA، والخطأ i/o timeout يعني أن المزود يحجب المنفذ أو أن جدار الحماية Firewall يمنع الاتصال الصادر Outbound. وتذكر أن حملات القوائم ذات التأكيد المزدوج لا تصل إلا إلى المشتركين المؤكدين، فإذا كان كل المشتركين بانتظار التأكيد فلن يرسل listmonk شيئاً.

روابط إلغاء الاشتراك تفتح localhost

السبب أن قيمة Root URL ما زالت على وضعها الافتراضي، فغيرها إلى العنوان العام واحفظ الإعداد، ولاحظ أن الرسائل التي أرسلت قبل التغيير تبقى بروابطها القديمة.

الرسائل تصل إلى مجلد البريد المزعج

تحقق من سجلات SPF وDKIM وDMARC لنطاق عنوان المرسل لدى مزود SMTP، وابدأ بكميات صغيرة إذا كان الحساب جديداً، وتأكد أن المشتركين وافقوا فعلاً على الاشتراك. وإذا كان المزود يفرض حداً للإرسال، فخفض سرعة الإرسال Sending Rate من Settings ← Performance، أي عدد الاتصالات والرسائل في الثانية، كما يشرح توثيق الأداء.

اختفت البيانات بعد إعادة إنشاء ال Container

هذا بالضبط ما يفعله السطر القديم yes | ./listmonk --install في كل تشغيل، فاستعد آخر نسخة احتياطية واستخدم السطر الحالي الذي فيه --install --idempotent.

فشل رفع الصور أو ملفات الاستيراد

إذا ظهر الخطأ 413 من ال Reverse Proxy فارفع قيمة client_max_body_size، وإذا فشل رفع الصور بخطأ في الصلاحيات فتأكد أن المجلد /opt/listmonk/uploads موجود وأن ال Container يستطيع الكتابة فيه.

الخلاصة

  • الإرسال من Gmail بخانة BCC يتوقف عند 500 مستلم في اليوم ولا يعطيك إلغاء اشتراك ولا متابعة للرسائل المرتدة، والخدمات السحابية ترفع السعر مع كل مشترك وتبقي القائمة لديها، وlistmonk مع مزود SMTP تختاره أنت يحل المشكلتين.
  • السطر --install --idempotent ثم --upgrade في command يجعل التثبيت مرة واحدة والترقية تلقائية، فلا تستخدم السطر القديم yes | ./listmonk --install إطلاقاً.
  • غير Root URL قبل أول حملة، واستخدم STARTTLS أو TLS مع المزود، وفعل التأكيد المزدوج للقوائم العامة.
  • لا تحذف رابط إلغاء الاشتراك ولا ترويسة One-Click، وفعل معالجة الرسائل المرتدة عبر webhooks المزود، والسبب أن Gmail وYahoo قد يرفضان رسائل من لا يلتزم بذلك أو يحولانها إلى البريد المزعج.
  • خذ نسخة احتياطية مشفرة بالأداة pg_dump قبل كل ترقية، فالقائمة الآن مسؤوليتك أنت.

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

  • أكتوبر 2026: مراجعة تقنية وإعادة صياغة، مع اختبار التثبيت والتأكيد المزدوج وإرسال حملة إلى Mailpit والنسخ الاحتياطي والاستعادة من جديد، وما زال listmonk 6.2.0 أحدث إصدار مستقر.
  • سبتمبر 2026: كتابة الدليل واختباره على listmonk 6.2.0.
نشرة عرب رووت | ArabRoot

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

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

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

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