جهات الاتصال والجماهير والبث
كل أمر لدفتر العناوين والجماهير والبث وقائمة المنع، مع أمثلة تطبيقية.
كيف تترابط
أربع مساحات أسماء تغطي الأشخاص الذين تكتب إليهم. جهات الاتصال هي دفتر عناوين مساحة العمل، والجماهير قوائم مسمّاة من جهات الاتصال، والبث يرسل رسالة واحدة إلى كل من في بعض الجماهير، وقائمة المنع تضم العناوين التي لن ترسل إليها مساحة العمل. كل أمر يستدعي طريقة واحدة من SDK، لذا تصف صفحات SDK الاستدعاءات نفسها بعمق أكبر.
- جهة الاتصال بلا معرّف. عنوانها هو المفتاح الذي يأخذه كل أمر
contacts، بعد تقليم المسافات وتحويله إلى أحرف صغيرة، فـ[email protected]و[email protected]جهة اتصال واحدة. وللجمهور معرّفaud_، وللبث معرّفbrd_، وللمنع المعرّف الذي يطبعهsuppressions list. - كل جهة اتصال موجودة في الجمهور الافتراضي ما دامت قائمة. ولا يمكن حذف ذلك الجمهور ولا إفراغه ولا إنقاصه، وقيمة
builtinفيهdefault. - دفتر العناوين ملك لمساحة العمل، لذا يقرأ كل عضو وكل مفتاح الدفتر نفسه ويكتب فيه.
- تستجيب كل مساحة أسماء أيضًا لصيغة المفرد، كما في
openemail contact get، وتعمل الأسماء البديلة المعتادة:lsوshowوnewوeditوrm. وفيsuppressions، التي أفعالهاaddوremove، يقودnewإلىaddوrmإلىremove.
يعرض openemail <namespace> <verb> --help كل خيار بنوعه، والنطاقات، ونقطة النهاية، وما يعيده الأمر. أضف --json لتحصل على الصفحة نفسها في صورة بيانات.
جهات الاتصال
دفتر عناوين مساحة العمل: الأشخاص الذين كتب إليهم عضو من محرّر الرسائل في التطبيق، إضافة إلى كل من حُفظ يدويًا. البريد الوارد لا يضيف أحدًا، ولا الإرسال عبر API أو CLI.
| الأمر | ما تفعله |
|---|---|
| openemail contacts list | صفحة واحدة من جهات الاتصال المحفوظة، الأحدث مراسلة أولًا. يُبقي --source جهات الاتصال manual أو auto، ويبحث --q في الأسماء والعناوين |
| openemail contacts get <email> | جهة اتصال واحدة، مع كل جمهور تنتمي إليه |
| openemail contacts create --email <value> | احفظ جهة اتصال جديدة، مع --name و--notes و--audience-ids. والعنوان الموجود بالفعل في الدفتر يُرفض بـ 409 contact_exists |
| openemail contacts update <email> | غيّر --name أو --notes، حيث تمسح null أيًّا منهما. ولا يمكن تغيير العنوان نفسه |
| openemail contacts delete <email> | احذف جهة الاتصال مع ملاحظاتها وصورتها وعضوياتها، وأخفِ العنوان كي لا يسجله محرّر الرسائل من جديد |
| openemail contacts set-audiences <email> --audience-ids <a,b> | اجعل الجماهير التي تنتمي إليها جهة الاتصال هذه القائمة بالضبط. ويُحتفظ دائمًا بالجمهور الافتراضي |
| openemail contacts list-people | كل من في صفحة جهات الاتصال: جهات الاتصال المحفوظة، ومع threads:read كل عنوان ظهر في البريد، مع أعداد المحادثات. ويضيّقها --sort و--q و--email و--blocked |
| openemail contacts save <email> | احفظ عنوانًا، أو أبقِ عنوانًا سُجّل من إرسال، أو أعِد عنوانًا محذوفًا. لا يعطي خطأ أبدًا، أيًّا كانت حالة العنوان |
| openemail contacts delete-many <emails...> | احذف من 1 إلى 200 عنوان وأخفِها في استدعاء واحد |
| openemail contacts set-photo <email> <data> | ارفع الصورة من ملف، أو من stdin عبر -: PNG أو JPEG أو WebP أو GIF حتى 5 MB |
| openemail contacts remove-photo <email> | أزل الصورة واحذف الصورة المخزنة |
| openemail contacts block <email> | ضع العنوان في قائمة حظر مساحة العمل، فيُرفض البريد القادم منه. ويُحذف وسم الزائد |
| openemail contacts unblock <email> | أزل كل قاعدة حظر تحظر العنوان، بما فيها قاعدة النطاق الكامل |
| openemail contacts list-threads <email> | المحادثات التي كتبها العنوان أو كُتبت إليه، في كل مجلد. ويبحث --q داخلها |
| openemail contacts activity <email> | البريد المستلم من العنوان والمرسل إليه خلال فترة، 90 يومًا ما لم يحدد --minutes غير ذلك، مع المحادثات التي تنتظر ردًا ووسيط زمن الرد في كل اتجاه |
الجماهير
قوائم مسمّاة من جهات الاتصال، حتى 100 في مساحة العمل. يجب أن يكون العنوان جهة اتصال قبل أن ينضم إلى إحداها، إلا عبر import-contacts الذي يحفظ العناوين الجديدة أثناء عمله.
| الأمر | ما تفعله |
|---|---|
| openemail audiences list | صفحة واحدة من الجماهير، الافتراضي أولًا ثم البقية الأحدث أولًا، لكل منها contactCount |
| openemail audiences growth | كيف نمت الجماهير خلال فترة، 30 يومًا ما لم يحدد --days أو --minutes غير ذلك: الانضمامات وإلغاءات الاشتراك في كل فترة، والمجاميع |
| openemail audiences get <id> | جمهور واحد، مع contactCount محدَّث |
| openemail audiences create --name <value> | أنشئ جمهورًا فارغًا، مع --description اختياري. الأسماء ليست فريدة |
| openemail audiences update <id> | غيّر --name أو --description. لا تُمَس العضوية |
| openemail audiences delete <id> | احذف الجمهور واحتفظ بجهات اتصاله. لا يمكن حذف الجمهور الافتراضي |
| openemail audiences empty <id> | أخرج كل جهة اتصال واحتفظ بالجمهور، بمعرّفه واسمه ووصفه |
| openemail audiences list-contacts <id> | صفحة واحدة من جهات الاتصال في الجمهور، مع وقت انضمام كل منها وما إذا ألغت اشتراكها. ويضيّقها --sort و--q و--source و--statuses |
| openemail audiences add-contact <id> --email <value> | ضع جهة اتصال موجودة واحدة في الجمهور. وإضافة من هو موجود فيه بالفعل لا تغيّر شيئًا |
| openemail audiences remove-contact <id> <email> | أخرج جهة اتصال واحدة. وجهة الاتصال غير الموجودة في الجمهور تعطي 404 |
| openemail audiences add-contacts <id> --emails <a,b> | ضع حتى 200 جهة اتصال موجودة فيه، وأبلغ في missing عن العناوين التي ليست جهات اتصال |
| openemail audiences remove-contacts <id> --emails <a,b> | أخرج حتى 200 جهة اتصال، وأبلغ عن تلك التي لم تكن فيه |
| openemail audiences import-contacts <id> --contacts <json|@file|-> | استورد حتى 500 صف { email, name }، مع حفظ العناوين التي ليست جهات اتصال بعد |
البث
رسالة واحدة إلى كل من في ما يصل إلى 10 جماهير، تُرسل نسخة منفصلة لكل شخص، مع ملء حقول الدمج ورابط لإلغاء الاشتراك. وكل نسخة بريد عادي له معرّف msg_ خاص به وأحداثه وخطافات الويب الخاصة به.
| الأمر | ما تفعله |
|---|---|
| openemail broadcasts preview --audience-ids <a,b> | احسب من سيصل إليهم بث إلى هذه الجماهير، ومن سيتخطاهم لأنهم ألغوا الاشتراك أو ممنوعون. لا يرسل شيئًا |
| openemail broadcasts send --audience-ids <a,b> --from <value> | أرسل بـ --subject و--html أو --text، أو بـ --template محفوظ، الآن أو في --scheduled-at |
| openemail broadcasts list | صفحة واحدة من البث، الأحدث أولًا، مع أعداد حية. ويُبقي --audience-id ما أُرسل إلى ذلك الجمهور |
| openemail broadcasts get <id> | بث واحد، مع حالته وأعداده الحية: الأمر الذي تستطلعه أثناء الإرسال |
| openemail broadcasts stats <id> | مجاميع المسلَّم والمرتد والمفتوح والمنقور عليه وملغى الاشتراك، وسلسلة لكل فترة --grain، ساعة ما لم تحدد غير ذلك |
| openemail broadcasts list-recipients <id> | إلى من ذهبت كل نسخة وما حدث لها. ويُبقي --filter مجموعة واحدة، مثل bounced أو not_opened |
| openemail broadcasts get-recipient <id> <email-id> | نسخة شخص واحد، بالموضوع وHTML والنص كما استلمها تمامًا |
| openemail broadcasts cancel <id> | أوقف بثًّا مجدولًا أو في الطابور أو لا يزال يُرسل. ولا يمكن استرجاع النسخ التي خرجت |
قائمة المنع
العناوين التي لن ترسل إليها مساحة العمل هذه: الارتدادات الصلبة والشكاوى، مسجلة لحظة حدوثها، وأي عنوان تضيفه يدويًا. والإرسال إلى أحدها يُرفض لذلك المستلم قبل أن يخرج أي شيء.
| الأمر | ما تفعله |
|---|---|
| openemail suppressions list | صفحة واحدة من القائمة، الأحدث أولًا. يُبقي --reason القيم bounce أو complaint أو manual، ويبحث --q |
| openemail suppressions get <id> | صف واحد: العنوان، والسبب، والتفاصيل التي حملها الارتداد أو الشكوى، وما إذا كان يمكن إزالته |
| openemail suppressions add --email <value> | أوقف الإرسال إلى عنوان. وإضافة عنوان موجود بالفعل تعيد الصف الذي يشغله |
| openemail suppressions remove <id> | اسمح بالبريد إلى العنوان من جديد. ولا يمكن إزالة الارتداد الصلب |
قائمة المنع وقائمة الحظر قائمتان مختلفتان. يوقف suppressions add البريد الخارج إلى عنوان، ويرفض contacts block البريد الوارد منه.
نطاقات الصلاحية
تحتاج معظم الأوامر إلى نطاق القراءة أو الكتابة لمساحة أسمائها. وبعضها يحتاج إلى نطاق آخر، لأنه يقرأ شيئًا آخر أو يغيّره:
| النطاق | الأوامر |
|---|---|
| contacts:read | contacts list وget وlist-people |
| contacts:write | contacts create وupdate وdelete وsave وdelete-many وset-photo وremove-photo، وaudiences import-contacts إلى جانب audiences:write |
| audiences:read | audiences list وgrowth وget وlist-contacts، وbroadcasts preview، كي يستطيع المفتاح الذي لا يرسل أن يعرض العدد |
| audiences:write | كل أمر audiences آخر، وcontacts set-audiences. ويحتاجه contacts create --audience-ids إلى جانب contacts:write |
| threads:read | contacts list-threads وactivity، والعناوين الظاهرة في البريد ضمن list-people |
| settings:read | suppressions list وget |
| settings:write | suppressions add وremove، وcontacts block وunblock |
| emails:read | broadcasts list وget وstats وlist-recipients وget-recipient |
| emails:send | broadcasts send، الذي يحتاج إلى audiences:read أيضًا، وbroadcasts cancel |
- المفتاح المقيّد بعناوين أو نطاقات معيّنة يقرأ دفتر العناوين نفسه الذي يقرؤه كل مفتاح آخر ويكتب فيه. لا يرى إلا البث المرسل من عنوان أو نطاق يحمله، ولا يحصل من
list-peopleإلا على جهات الاتصال المحفوظة، ويُرفض بـ 422capability_unsupportedفيcontacts list-threadsوactivityوblockوunblock، وفيsuppressions addوremove. - تسجيل الدخول عبر المتصفح لعضو لا يصل إلا إلى بعض العناوين يُرفض بـ 422
capability_unsupportedفي كل أمرcontactsوaudiencesوbroadcasts. ويرفضsuppressions addتسجيل الدخول عبر المتصفح لأي شخص غير مالك مساحة العمل.
أمثلة تطبيقية
ابنِ جمهورًا من ملف، ثم احسب من سيصل إليهم بث إليه. يحفظ import-contacts العناوين التي ليست جهات اتصال بعد، وتشغيله مرة أخرى لا ينشئ شيئًا ولا يضيف شيئًا مرتين.
[ { "email": "[email protected]", "name": "Ada Lovelace" }, { "email": "[email protected]", "name": "Grace Hopper" }, { "email": "[email protected]" }]AUDIENCE=$(openemail audiences create --name 'Product updates' --json | jq -r .id)openemail audiences import-contacts "$AUDIENCE" --contacts @contacts.jsonopenemail broadcasts preview --audience-ids "$AUDIENCE"افحص بثًّا بـ --dry-run، الذي يطبع الطلب ولا يرسل شيئًا، ثم أرسله. يُنشأ البث فورًا ويُرسل في الخلفية، لذا استطلع get لمتابعته. هذا الجسم لا يضع {{unsubscribeUrl}}، لذا تحصل كل نسخة على تذييل من سطر واحد لإلغاء الاشتراك.
{ "audienceIds": ["aud_4c1b8e2a7d9f05c36b4e8a71"], "from": "Acme <[email protected]>", "subject": "{{firstName|Hello}}, the September release is out", "html": "<p>Hi {{firstName|there}},</p><p>Here is what changed this month.</p>", "scheduledAt": "2026-10-01T09:00:00Z"}openemail broadcasts send --data @broadcast.json --dry-runBROADCAST=$(openemail broadcasts send --data @broadcast.json --yes --json | jq -r .id)openemail broadcasts get "$BROADCAST"openemail broadcasts stats "$BROADCAST" --grain dayاعرف من لم يصل إليه البث. يطبع --ndjson مستلمًا واحدًا في كل سطر، و--all --json مستندًا واحدًا بكل صفحة.
openemail broadcasts list-recipients brd_5a8c1e3f7b2d94a06c8e1f3b --filter bounced --ndjson | jq -r .emailopenemail broadcasts list-recipients brd_5a8c1e3f7b2d94a06c8e1f3b --filter not_opened --all --json | jq ".items | length"openemail suppressions list --reason bounce --all --max 50انسخ الأعضاء المشتركين في جمهور إلى جمهور آخر. يحوّل jq التدفق إلى الجسم الذي يأخذه add-contacts، ويقرؤه --data - من stdin. ويحصره --max 200 في 200 عنوان يقبلها الاستدعاء الواحد.
openemail audiences list-contacts aud_9f2c4b7e1a0d63d84c5f2e7b --statuses subscribed --max 200 --ndjson \ | jq -s '{ emails: map(.email) }' \ | openemail audiences add-contacts aud_1c4e7a9b2d0f36e85a7c1b4d --data -احذف كل جهة اتصال سجّلها محرّر الرسائل في نطاق واحد. يأخذ delete-many حتى 200 عنوان في الاستدعاء، لذا يقسّم xargs -n 200 القائمة الأطول. افحص الدفعات بـ --dry-run أولًا، لأنه لا تراجع.
openemail contacts list --source auto --all --ndjson \ | jq -r 'select(.email | endswith("@old-vendor.example")) | .email' > leaving.txtxargs -n 200 openemail contacts delete-many --dry-run < leaving.txtxargs -n 200 openemail contacts delete-many --yes < leaving.txtأوقف الإرسال إلى عنوان، واسمح بعنوان من جديد، واحظر مرسلًا. تبيّن removable الصفوف التي سيأخذها suppressions remove.
openemail suppressions add --email [email protected]openemail suppressions list --q [email protected] --json | jq -r '.items[] | select(.removable) | .id'openemail suppressions remove 7b1e2c3d-4f5a-4b6c-8d7e-9f0a1b2c3d4e --yesopenemail contacts block [email protected]التأكيدات ورموز التحقق
تطلب منك هذه الأوامر التأكيد في الطرفية قبل أن تعمل:
| مساحة الأسماء | يطلب التأكيد |
|---|---|
| contacts | delete وdelete-many وremove-photo وunblock |
| audiences | delete وempty وremove-contact وremove-contacts |
| broadcasts | send وcancel |
| suppressions | remove |
- يؤكد
--yesنيابةً عنك. ومن دون إشراف، مع--jsonأو--no-input، أو في CI، أو دون طرفية، يتوقف الأمر الذي كان سيسأل بالرسالةRefusing to run unattended. Pass --yes to confirm.ورمز الخروج2. - يطبع
--dry-runالطلب الذي كان الأمر سيرسله ويخرج بالرمز0، دون أن يسأل ودون أن يغيّر شيئًا. - مع تسجيل الدخول عبر المتصفح، يطلب
audiences deleteرمز تحقق أولًا، كما يفعل تطبيق الويب. لا يتخطاه--yesأبدًا، ومن دون إشراف يتوقف الأمر برمز الخروج4. شغّلopenemail verifyمسبقًا، أو استخدم مفتاح API، الذي لا يُطلب منه ذلك أبدًا. - لا يطلب
audiences emptyرمز تحقق أبدًا، لذا تحقّق من المعرّف قبل أن تمرّر--yes.
التصفح
كل أمر يسرد يقرأ صفحة واحدة. وحين يبقى المزيد، مرّر المؤشر الذي طبعه إلى --cursor، مع المرشّحات نفسها، أو اقرأها كلها:
- يقرأ
--allكل صفحة ويبث العناصر: جدولًا في الطرفية، وكائن JSON واحدًا في كل سطر عند التمرير عبر أنبوب أو مع--ndjson. - يتوقف
--max <n>بعد هذا العدد من العناصر، ويتضمن--all. - يطبع
--jsonمستند{ items, hasMore, nextCursor }واحدًا، ومع--allكذلك. - المؤشر المشوَّه أو المنتهي يعطي 400
invalid_cursor. ابدأ من جديد دونه.
| الأمر | حجم الصفحة |
|---|---|
| openemail contacts list | من 1 إلى 200، و50 ما لم يحدد --limit غير ذلك |
| openemail contacts list-people | من 1 إلى 100، و25 ما لم يحدد --limit غير ذلك |
| openemail contacts list-threads | من 1 إلى 100، و25 ما لم يحدد --limit غير ذلك |
| openemail audiences list | من 1 إلى 100، و25 ما لم يحدد --limit غير ذلك |
| openemail audiences list-contacts | من 1 إلى 200، و50 ما لم يحدد --limit غير ذلك |
| openemail broadcasts list | من 1 إلى 100، و25 ما لم يحدد --limit غير ذلك |
| openemail broadcasts list-recipients | من 1 إلى 200، و50 ما لم يحدد --limit غير ذلك |
| openemail suppressions list | من 1 إلى 100، و25 ما لم يحدد --limit غير ذلك |
من المفيد معرفته
- يرفض
contacts createالعنوان الموجود بالفعل في الدفتر بـ 409contact_exists، فلا تكتب إعادة المحاولة أبدًا فوق اسم عدّله أحدهم. أماcontacts saveفلا يرفض أبدًا: يحفظ العنوان أو يبقيه أو يعيده، أيًّا كانت حالته. - يأخذ
contacts deleteأيضًا عنوانًا لم يظهر إلا في البريد، فيُخرج ذلك الشخص منlist-people. ويبقى البريد. ولا تراجع: حفظ العنوان من جديد يبدأ جهة اتصال بلا اسم ولا ملاحظات ولا جمهور سوى الافتراضي. - العنوان هو هوية جهة الاتصال، لذا لا يستطيع
contacts updateتغييره. ونقل جهة اتصال هوdeleteثمcreate. - يقرأ
contacts set-photoالصورة من ملف، أو من stdin عبر-. مرّر--content-type، مثلimage/jpeg: فمن دونه قد تُرسل الصورة على أنهاapplication/octet-stream، وهو ما يرفضه الخادم بـ 422invalid_image. - يأخذ
broadcasts send --scheduled-atوقتًا بصيغة ISO 8601 مثل2026-10-01T09:00:00Z، أو مدة بصيغة ISO 8601 مثلPT2HأوP1D، حتى 365 يومًا من الآن. والمهل القصيرة التي يأخذهاsend --at، مثل2h، تُرفض هنا. - تعمل حقول الدمج في
--subjectو--htmlو--text:{{firstName}}و{{lastName}}و{{name}}و{{email}}و{{unsubscribeUrl}}، ولكل منها قيمة احتياطية بعد خط عمودي، كما في{{firstName|there}}. والجسم الذي لا يضع{{unsubscribeUrl}}يحصل على تذييل من سطر واحد لإلغاء الاشتراك. أما القالب فيُرسل كما هو، لذا ضع الرابط في القالب. - يُفحص البث مقابل عمليات الإرسال الشهرية للخطة قبل كتابة أي شيء، وكل نسخة تُحتسب إرسالًا واحدًا. والبث الذي لا تكفيه الحصة يُرفض بـ 429
send_quota_exceeded، ولا يبقى منه شيء. - مرّر
--idempotency-keyخاصًا بك إلىbroadcasts sendحين قد يعيد سكربت تشغيل الخطوة. والمفتاح نفسه يجيب بالبث الذي أنشأه بدلًا من إرسال بث جديد. - جهة الاتصال التي تلغي اشتراكها من بث تبقى في الجمهور مع ضبط
unsubscribedAt، ويتخطاها البث اللاحق إلى ذلك الجمهور. ويسردهاaudiences list-contacts --statuses unsubscribed. - يبقى الارتداد الصلب في قائمة المنع. يرفضه
suppressions removeبـ 409suppression_not_removable، وتقولremovableفي كل صف ذلك مسبقًا.