النطاقات
`domains->list` و`listAll` و`iterate` و`get` و`update`.
كل الدوالّ
$page = $client->domains->list(); foreach ($page as $row) { echo $row['domain'], ' ', $row['sending']['canSend'] ? 'can send' : 'cannot send yet', PHP_EOL;} $domain = $client->domains->get('b3e1f0a4-6c2d-4e8a-9f17-2d5c8a0b4e6f');echo $domain['receiving']['verified'] ? 'receiving' : 'not verified yet', ' ', $domain['sending']['status'], PHP_EOL; foreach ($domain['addresses'] as $entry) { echo $entry['address'], ' ', $entry['enabled'] ? 'on' : 'off', PHP_EOL;}الاستقبال والإرسال حقيقتان مستقلتان وتُعادان في صورة مصفوفتين منفصلتين. فـ receiving.verified تعني أن سجل MX الخاص بالنطاق يجلب بريده إلى هنا وأن تحدي إثبات الملكية منشور. أما sending فيبلّغ عن فحص التوقيع الصادر: تكون status إحدى القيم verified أو pending أو failed أو no_identity أو unknown، وتبيّن canSend ما إذا كان إرسال من هذا النطاق سيُقبل الآن. والحكم السلبي الأقدم من يوم يُعامل كمجهول لا كرفض، لذا فرّع على canSend، الذي يُقرأ عبر $domain['sending']['canSend']، لا على status.
يعيد list صفحة OpenEmail\Result\Page واحدة من النطاقات بالترتيب الأبجدي، ويعيدها listAll كلها في مصفوفة واحدة. ويعيد iterate كائن Generator يسلّمها واحدًا تلو الآخر.
$domainId = 'b3e1f0a4-6c2d-4e8a-9f17-2d5c8a0b4e6f'; $updated = $client->domains->update($domainId, ['trackingHost' => 'links.acme.com']);$record = $updated['tracking']['record'];echo $updated['tracking']['status'], ' ', $record['name'] ?? '', ' ', $record['value'] ?? '', PHP_EOL; $client->domains->update($domainId, ['trackingHost' => null]);يضبط update نطاق التتبّع المخصص للنطاق أو يعيد فحصه أو يزيله، وهو نطاق فرعي مثل links.acme.com، ويعيد المصفوفة نفسها التي يعيدها get. ويبلّغ tracking عنه في كل قراءة. وإلى أن ينجح فحص، تكون tracking.status بالقيمة pending وتظل الروابط المتتبَّعة وبكسل الفتح تستخدم مضيف OpenEmail الافتراضي. وبمجرد نجاح فحص تصبح active ويستخدم البريد الجديد الصادر من النطاق نطاق التتبّع للاثنين معًا.
يسرد get أيضًا العناوين الموجودة على النطاق. والاستدعاء ذو الصلة هو addresses->list: أي العناوين التي يجوز لهذا المفتاح وضعها في ترويسة From، وهي مجموعة أضيق، ولكل منها حكم canSend. ويعيد OpenEmail\Result\AddressBookPage، الذي يحملها في addresses لا في items، إلى جانب domains وunrestricted. ويعيد listAll الخاص به OpenEmail\Result\AddressBook واحدًا.
appHost مساحة أسماء مستقلة، $client->appHost. تقرأ get وset وverify وdelete عنوان تطبيق الويب لمساحة العمل وتغيّره، وهو نطاق فرعي مثل mailbox.acme.com على أحد هذه النطاقات أو على أي نطاق آخر تتحكم فيه مساحة العمل، يسجّل فيه أفرادها الدخول تحت علامة مساحة العمل. ويعيد set سجلات DNS الواجب نشرها، في record، وفي ownershipRecord إن كان النطاق خارج مساحة العمل. ويطلب delete، وكذلك set الذي يستبدل عنوانًا، من تطبيق OAuth رمز تحقق: وإلى أن يحصل عليه، يرمي الاستدعاء خطأ 403 تكون قيمة isStepUpRequired() فيه true.
يضبط branding تلك العلامة التجارية. يقرأ branding->get روابط الرمز والشعار وشعار الوضع الداكن وصورة تسجيل الدخول، والخطين، وخلفية تسجيل الدخول. ويغيّر branding->update الخطوط والخلفية، ويرفع branding->uploadImage($variant, $data, contentType: ...) إحدى الصور الأربع، ويزيل branding->removeImage($variant) واحدة منها. وقيمة الصيغة هي mark أو wordmark أو wordmark-dark أو login-background، ويسمّيها OpenEmail\Constants\BrandImageVariants. والبيانات سلسلة من البايتات، أو مورد تدفق، أو SplFileInfo، أو تدفق PSR-7 أو ملف مرفوع. وSplFileInfo مثل new \SplFileInfo('logo.svg')، أو تدفق مفتوح على ملف، أو ملف مرفوع في Laravel أو Symfony، يحمل نوعه معه. أما البايتات الأخرى فتحتاج إلى contentType:، والصورة بلا نوع تُرفض بالخطأ 422 invalid_image. والشعار هو ما يضفي العلامة التجارية على عنوان تطبيق الويب، وعلى الرسائل المرسلة لمساحة العمل في الخطة المدفوعة.
المعاملات: domains->get
idstringمطلوب- المعرّف المأخوذ من `domains->list`، وهو UUID يُنشأ عند إضافة النطاق، لا اسم المضيف، لذا فإن `get('example.com')` لا يجد شيئًا. والبحث مقيّد بمساحة عمل المفتاح نفسها كما هو مقيّد بالمعرّف، فنطاق مساحة عمل أخرى يعطي 404، يُرمى في صورة `NotFoundException`، لا 403. والمعرّف الفارغ يرمي `InvalidArgumentException` قبل إرسال أي شيء.
المعاملات: domains->update
idstringمطلوب- معرّف النطاق نفسه الذي يأخذه `get`. والصلاحية المطلوبة هي `domains:write`.
trackingHoststring or null- نطاق فرعي من النطاق، بحد أقصى 512 حرفًا، مثل `links.acme.com`. تُشذَّب المسافات ويُحوَّل إلى أحرف صغيرة، وتُزال بادئة `https://` أو `http://` والمسار والنقطة الأخيرة. والقيمة الجديدة يجري التحقق منها وحفظها وفحصها في الاستدعاء نفسه. أما القيمة التي يحملها النطاق بالفعل فتعيد تشغيل الفحص، إلا إذا كان الفحص الأخير قبل أقل من 30 ثانية. مرّر null أو سلسلة نصية فارغة لإزالة نطاق التتبّع، وأغفل المفتاح ليبقى كما هو.
المضيف المرفوض يرمي ApiException يذكر trackingHost في param: 422 مع invalid_tracking_host لاسم لا يمكن استخدامه، مثل اسم خارج النطاق، و409 مع domain_not_verified لمضيف جديد بينما receiving.verified قيمتها false وسجل TXT باسم _openemail-challenge الخاص بالنطاق لم يُنشر بعد، و409 مع tracking_host_in_use لاسم يستخدمه نطاق آخر بالفعل، أو حين يكون نطاق التتبّع مُدارًا من خادم OpenEmail مختلف. ويصل الخطأ 422 في صورة ValidationException وكل 409 في صورة ConflictException. والمفتاح المقيّد بعناوين بعينها يحصل على 422 مع capability_unsupported، لأن نطاق التتبّع ينطبق على كل عنوان في النطاق.
التعديل مصفوفة واحدة مفاتيحها أسماء API بصيغة camelCase، فيُرسل مفتاح مثل tracking_host كما كُتب ويُرفض بالخطأ 422 unknown_parameter. ويأخذ update أيضًا catchAll، وstorageHost لنطاق ملفات مثل files.acme.com، وdmarcPolicy. وكل مفتاح اختياري، ويشرح مرجع التوابع كلًّا منها. ويعيد العميل محاولة update كما يفعل مع القراءة، لأن التكرار يجد المضيف مضبوطًا أصلًا وفي أقصى الأحوال يفحصه مجددًا.
الاستجابة: نطاق (domains->get)
objectstring- دائمًا السلسلة `domain`، في سجلات `list` وفي هذا السجل على حد سواء.
idstring- UUID الخاص بالنطاق. ثابت طوال عمر الصف، وهو المقبض الوحيد الذي تقبله استدعاءات النطاق الأخرى.
domainstring- اسم المضيف المجرّد بأحرف صغيرة: `example.com`. فريد على مستوى المنتج كله، بمالك واحد لكل نطاق، فلا تستطيع مساحتا عمل المطالبة به معًا.
receiving.verifiedbool- صحيحة بمجرد أن يُظهر DNS أن سجل MX للنطاق يسمي مضيفًا يجلب بريده إلى هنا، وحيث يحمل السجل رمز تحدٍّ، أن سجل TXT المطابق `_openemail-challenge` منشور. وسجل MX وحده لا يثبت شيئًا، لأن كل نطاق نستقبل له ينشر أسماء المضيفات نفسها، ولهذا وُجد الرمز، ولهذا كانت هذه الراية هي البوابة التي يفحصها تسليم البريد الوارد قبل قبول أي رسالة.
receiving.verifiedAtstring or null- متى نجح التحقق، في صورة سلسلة نصية بصيغة ISO 8601. ويكون null ما دام لم ينجح، و`verified` مشتق من هذا العمود بالضبط، فلا يمكن أن يختلف الاثنان أبدًا.
receiving.catchAllbool- ما إذا كان أي جزء محلي مقبولًا. وهو مفعّل افتراضيًا للنطاقات المضافة منذ أن صار هذا هو القاعدة. ومع إيقافه لا تُقبل سوى العناوين المسمّاة على النطاق ويُرفض الباقي في وقت SMTP، فيتلقى المرسل ارتدادًا بدل الصمت.
receiving.lastCheckedAtstring or null- متى سُئل DNS آخر مرة عن هذا النطاق. ويكون null حين لم يُسأل DNS قط، وهو ما يُقرأ بشكل مختلف تمامًا عن الفشل بالنسبة لمن أضاف نطاقًا قبل دقيقة. وقراءة نطاق غير متحقق منه تسأل DNS مجددًا بمجرد أن يمضي على الفحص الأخير أكثر من 20 ثانية، فاستطلاع `get` طريقة لانتظار التحقق، ويفحص `verify` فورًا.
receiving.errorstring or null- لماذا لم ينجح الفحص الأخير، بكلمات يستطيع المالك التصرف بناءً عليها: ومن أمثلتها المعتادة `No MX records yet. DNS changes can take a few minutes to spread.` ويكون null بمجرد نجاح الفحص، وهو مخزَّن لا مشتق، فتقول إعادة التحميل وإعادة الفحص المجدولة الشيء نفسه.
sending.statusstring- حالة التوقيع الصادر كما رآها الفحص الأخير: `verified` أو `pending` أو `failed` أو `no_identity` أو `unknown`. وتُقرأ من الفحص المخزَّن، لذا تخبرك `sending.checkedAt` كم عمرها.
sending.canSendbool- ما إذا كان إرسال من هذا النطاق سيُقبل الآن. والحكم السلبي الأقدم من يوم يُعامل كمجهول لا كرفض، فقد تكون هذه القيمة صحيحة بينما `status` بالقيمة `pending`. فرّع عليها قبل الإرسال: فالقيمة الخاطئة تعني أن `emails->send` من هذا النطاق يُرفض بـ 409 مع `domain_not_sendable`.
sending.checkedAtstring or null- متى فُحصت حالة التوقيع آخر مرة، في صورة سلسلة نصية بصيغة ISO 8601. وتكون null حين لم تُفحص قط، وهو ما يُقرأ بشكل مختلف تمامًا عن الفشل.
sending.errorstring or null- آخر فشل في التوقيع موصوفًا بالكلمات، أو null بمجرد نجاحه.
sending.notestring- واحدة من خمس جمل، تُختار بحسب `sending.status`، تشرح معنى تلك الحالة بكلمات يستطيع مالك النطاق التصرف بناءً عليها. وهي نص للقراءة البشرية، لذا فرّع على `sending.canSend` لا على هذا الحقل.
trackingarray- نطاق التتبع المخصص للنطاق، في سجلات `list` وفي هذا السجل على حد سواء، وهو ما يغيّره `update`.
tracking.hoststring or null- نطاق التتبع، مثل `links.acme.com`، أو null عندما لا يكون مضبوطًا.
tracking.statusstring- تعني `none` أنه لا يوجد نطاق تتبع مضبوط، وتعني `pending` أنه لم ينجح في أي فحص قط، وتعني `active` أن البريد الجديد يستخدمه، وتعني `failed` أنه نجح من قبل ثم خرج من الاستخدام. والمضيف النشط يخرج من الاستخدام بعد ثلاثة فحوص فاشلة متتالية، أو حين يتجاوز عمر آخر فحص ناجح ساعتين.
tracking.activebool- صحيحة تمامًا حين تكون `status` هي `active`، أي حين تستخدم الروابط المتتبَّعة وبكسل الفتح في البريد الجديد من النطاق ذلك المضيف.
tracking.targetstring- العنوان الذي يشير إليه سجل CNAME، مجهّز لنطاق التتبع هذا وحده. وهو سلسلة فارغة ما دامت `host` فارغة، وكذلك ما دام العنوان الخاص بمضيف جديد قيد التجهيز.
tracking.recordarray or null- السجل الواجب نشره، مصفوفة فيها `type` (دائمًا `CNAME`) و`name` و`value`، باسم `host` وقيمته `target`. ويكون null عندما لا يوجد نطاق تتبّع، وكذلك ما دام عنوان مضيف جديد قيد الإعداد، لذا يقرؤه `$domain['tracking']['record']['value'] ?? null` بأمان.
tracking.checkedAtstring or null- متى فُحص المضيف آخر مرة، في صورة سلسلة نصية بصيغة ISO 8601. ويكون null حتى الفحص الأول.
tracking.verifiedAtstring or null- متى نجح فحص آخر مرة، في صورة سلسلة نصية بصيغة ISO 8601. ويكون null لمضيف لم ينجح في أي فحص قط.
tracking.errorstring or null- ما وجده الفحص الأخير، بكلمات يستطيع مالك النطاق التصرف بناءً عليها. ويكون null عندما ينجح الفحص الأخير أو عندما لا يكون أي فحص قد جرى. والمضيف الذي فشل في فحص أو فحصين يظل `active` ويحمل السبب هنا.
addressesarray- كل صفوف العناوين على النطاق، وهو ما يضيفه `get` على صف `list`. ويشمل ذلك الصفوف التي كتبها التسليم نفسه في ظل catch-all، وهذه تتوقف عن القبول فور إيقاف catch-all، فهذه القائمة ليست قائمة بما سيستقبل البريد.
addresses[].addressstring- العنوان الكامل، يُعاد بناؤه من الجزء المحلي المخزَّن واسم المضيف ويُحوَّل إلى أحرف صغيرة، فيطابق دائمًا `domain` أعلاه بدلًا من أن ينحرف عنه.
addresses[].enabledbool- القيمة false تعطّل العنوان، والعنوان المعطَّل يُرفض حتى حين يكون catch-all مفعّلًا. وكل صف يُسرد في الحالتين، فرشّح على هذا الحقل بدل قراءة القائمة كمجموعة العناوين العاملة.
createdAtstring- متى أُضيف صف النطاق، في صورة سلسلة نصية بصيغة ISO 8601. وليس وقت التحقق من النطاق: فذاك هو `receiving.verifiedAt`، الذي قد يكون null بينما هذا مضبوط.