تخطَّ إلى المستندات
SDK

إرسال دفعة

`emails.sendBatch`: حتى 100 رسالة، مع نتيجة لكل عنصر.

emails.sendBatch

send-batch.ts
const result = await openemail.emails.sendBatch(invoices.map(toMessage)) console.log(result.sent, 'sent,', result.failed, 'failed') for (const item of result.items) {  if (item.status === 'error') console.error(item.index, item.error.code, item.error.message)  else console.log(item.index, item.email.id)}

يحمل items مدخلة واحدة لكل عنصر مُدخَل، بالترتيب نفسه، وكل منها إما ok مع رسالتها أو error مع المُغلَّف الذي كانت تلك الرسالة سترفض به. ولا شيء يُتراجع عنه، فـ failed > 0 قائمة للتصرف بناءً عليها لا سبب لإعادة إرسال الدفعة.

مفتاح واحد لمنع التكرار يغطي الدفعة كلها ويوسّعه الخادم لكل عنصر، فالدفعة المُعاد إرسالها تعيد تشغيل كل رسالة بدل أن تطويها كلها على الرسالة الأولى.

المعاملات: emails.sendBatch

emailsEmailSend[]مطلوب
من رسالة واحدة إلى 100، تُسلسل بالشكل `{ "emails": [...] }` وتُقبل واحدة تلو الأخرى بالترتيب المعطى. ومصفوفة فارغة، أو أكثر من 100، أو أكثر من 10 عناصر تحمل `translate`، ترفض الاستدعاء كله بـ `validation_error` على `emails`. ويسري الأمر نفسه على غياب صلاحية `emails:send`، وعلى جسم ليس مصفوفة ولا `{ emails: [...] }`، وعلى `Idempotency-Key` مشوّه، وكل ذلك قبل إرسال رسالة واحدة.
options.idempotencyKeystring
يمنع تكرار الدفعة عبر العمليات المختلفة. ويرفق العميل مفتاحًا مولَّدًا حديثًا مع كل استدعاء على أي حال، فإعادات محاولته لا تُرسل مرتين أبدًا، ويوسّع الخادم أي مفتاح يصله لكل عنصر بالشكل `key/0` و`key/1` وهكذا، مفصولًا بشرطة مائلة، وهي محرف لا يجوز أن يحتويه مفتاحك، فلا يمكن لمفتاح واحد على مئة رسالة أن يطويها على الأولى.
emails[].fromRecipientInputمطلوب
المرسل، كعنوان مجرد أو بالشكل `Name <addr@host>` أو ككائن. ولا يوجد مرسل احتياطي ويجب أن يكون المفتاح مسموحًا له بهذا العنوان؛ والرفض يُفشل ذلك العنصر وحده، كـ `permission_error` برمز `from_address_forbidden`.
emails[].toRecipientInput | RecipientInput[]مطلوب
مستلم واحد على الأقل، والمستلم المفرد يلفّه العميل داخل مصفوفة. وبحد أقصى 50 عنوانًا عبر `to` و`cc` و`bcc` مجتمعة، تُحسب لكل رسالة لا عبر الدفعة.
emails[].ccRecipientInput | RecipientInput[]
الافتراضي لا أحد، وتُحسب ضمن إجمالي الخمسين عنوانًا نفسه مع `to` و`bcc`.
emails[].bccRecipientInput | RecipientInput[]
الافتراضي لا أحد، وتُحسب ضمن إجمالي الخمسين عنوانًا نفسه. و`Bcc` من الأسماء التي لا يجوز لـ `headers` ضبطها، فهذه هي الطريقة الوحيدة للنسخ المخفي. إذ إن صيغة الترويسة كانت ستنقض المُغلَّف المنفصل لكل مستلم وهو ما يبقي العنوان مخفيًا.
emails[].replyToRecipientInput
إلى أين تذهب الردود. يُطبَّق بعد `headers`، فيطمس `Reply-To` الذي ضبطته هناك أيضًا بدلًا من إضافة ترويسة ثانية.
emails[].subjectstring
بحد أقصى 998 حرفًا، وهو حد السطر في RFC 5322، والافتراضي سلسلة فارغة. والموضوع الفارغ يسقط إلى موضوع القالب نفسه عندما يوفّر `template` واحدًا.
emails[].htmlstring
جزء HTML، بحد أقصى مليون حرف، وهو الجزء الذي يراه المستلمون عندما يُعطى الجسمان معًا. ويلزم واحد من `html` أو `text` أو `template` أو `draftId`، والعنصر الخالي منها جميعًا يفشل بـ `validation_error` على `html`.
emails[].textstring
جزء النص العادي، بحد أقصى مليون حرف. ويمكن إرسال الاثنين، وكل وسيلة نقل على هذا المسار تبني جسمًا واحدًا من سلسلة واحدة، فيغلب `html` حيث يوجد.
emails[].headersRecord<string, string>
`X-*` و`List-*` وReply-To وPrecedence وAuto-Submitted وImportance وPriority وFeedback-ID فقط؛ وأي ترويسة يضبطها النقل بنفسه (From وTo وBcc وSubject وMessage-ID وترويسات DKIM وARC) تُرفض كـ `reserved_header` بدل أن تُسقط بصمت. والقيم بحد أقصى 998 حرفًا ولا يجوز أن تحمل CR أو LF أو NUL، لأن سطرًا ثانيًا يعني ترويسة ثانية.
emails[].attachmentsAttachmentInput[]
بحد أقصى 20 ملفًا لكل رسالة، بمجموع 5 ميغابايت للملفات المضمّنة بعد فك الترميز، ويُحسب ذلك لكل رسالة لا لكل دفعة. والحقل `content` يُرسل بترميز base64 على الشبكة؛ مرّر بايتات ويتولى العميل ترميزها، وهذا هو الموضع الوحيد الذي يفجّر فيه ترميز base64 اليدوي مكدس الاستدعاءات بشكل موثوق. أما مدخلة `{ fileId }` فتسمي ملفًا موجودًا بالفعل في مساحة العمل ولا تُحسب ضمن حد الملفات المضمّنة.
emails[].threadIdstring
الرد داخل محادثة قائمة، بحد أقصى 256 حرفًا. ويكتب النقل منه ترويستي In-Reply-To وReferences، وهو ما يجعل الرد يحط داخل المحادثة لا بجانبها.
emails[].draftIdstring
أرسل محتوى مسودة محفوظة تحت هذا المُغلَّف، بحد أقصى 256 حرفًا. والمستلمون والموضوع والترويسات المبنية هنا هي ما يذهب على الشبكة.
emails[].template{ id, version?, props?, slots? }
اعرض قالبًا مخزَّنًا على الخادم، بالمعرّف (`tpl_…`) أو بالـ slug، مع `version` لتثبيت مراجعة و`props`/`slots` لملئه. يُحل مرة واحدة عند قبول العنصر، ويُرفض مع `html`/`text` ومع `draftId`، لأن كلًّا منها إجابة ثانية عن سؤال ما الذي تحتويه الرسالة.
emails[].scheduledAtDate | string
كائن `Date` أو لحظة بصيغة ISO-8601 أو مدة مثل `PT1H`؛ على الأقل بعد ثانية من الآن وبحد أقصى 365 يومًا. وتُجدوَل العناصر بشكل مستقل، فبإمكان دفعة واحدة أن تحمل مئة وقت إرسال مختلف.
emails[].cancellableForSecondsnumber
نافذة تراجع بالثواني على إرسال فوري، عدد صحيح من 0 إلى 900، والافتراضي 0. وأي قيمة فوق 0 تُرفض مع `scheduledAt` على العنصر نفسه، لأن الرسالة المجدولة قابلة للإلغاء أصلًا حتى تنطلق.
emails[].trackingTrackingRequest
`opens` و`clicks`، كل منهما اختياري بشكل مستقل ويتجاوز الإعداد لهذه الرسالة وحدها. والمفتاح الذي تحذفه يرجع إلى إعداد العنوان الذي تُرسل منه الرسالة، وإلا فإلى إعداد All addresses، وهو مفعّل ما لم يعطّله أحدهما.
emails[].tagsRecord<string, string>
بحد أقصى 10 وسوم، بمفاتيح من 1 إلى 64 حرفًا من المجموعة `A-Za-z0-9_-` وقيم حتى 256 حرفًا. تُعاد كما هي على الرسالة ولا تُفسَّر أبدًا: فـ `emails.list` يأخذ `status` و`from` و`limit` و`cursor` لا غير، فالوسم شيء تقرؤه من رسالة تملكها بالفعل لا وسيلة للعثور عليها.
emails[].translateSendTranslateOptions
أرسل هذا العنصر بلغة أخرى، ويُحل ذلك عند القبول فتكون الكلمات التي اعتُمدت هي الكلمات التي تخرج. ولا يجوز أن يحمله أكثر من 10 عناصر في دفعة واحدة: فكل عنصر ينفق عدة استدعاءات للنموذج والعناصر تُنفَّذ بالترتيب، فدفعة أكبر كانت ستُقتل في منتصف الإرسال. وفوق ذلك يُرفض الاستدعاء كله بـ `too_many_items` على `emails`، قبل إرسال أي شيء.

الاستجابة: BatchResultResource

itemsBatchItemResource[]
مدخلة واحدة لكل عنصر مُدخَل، بالترتيب الذي أرسلته. ولا شيء يُتراجع عنه، فهذا سجل لما حدث لكل رسالة لا تقرير عن معاملة واحدة. وتجيب واجهة API بـ 207 سواء قُبلت كل الرسائل أو بعضها أو لم تُقبل أي منها، فالوعد يُحل في الحالتين، و`status` لكل عنصر هو ما تفرّع عليه.
sentnumber
كم عنصرًا قُبل، وهو ليس نفسه كم عنصرًا خرج. فقد يكون العنصر `ok` ومع ذلك يحمل `email.status` بالقيمة `failed` أو `partial`، لأن وسيلة نقل ترفض الرسالة بعد وجود السجل تمثل نتيجة تسليم لا طلبًا مرفوضًا.
failednumber
كم مدخلة تحمل `error`. و`failed > 0` قائمة للتصرف بناءً عليها لا سبب لإعادة إرسال الدفعة. فالرسائل المقبولة قد ذهبت بالفعل.
items[].indexnumber
الموضع الذي احتلته رسالة هذه المدخلة في المصفوفة التي أرسلتها. محمول كحقل لا كترتيب فحسب، فيظل بوسع الشيفرة التي ترشّح `items` أو ترتبها أن تقول أي مُدخَل فشل.
items[].status'ok' | 'error'
مميّز الاتحاد: فـ `ok` تحمل `email`، و`error` تحمل `error`، ولا تحمل أي مدخلة الاثنين معًا.
items[].emailSentEmailResource
الرسالة المقبولة، في مدخلة `ok` فقط، بالشكل نفسه الذي يعيده إرسال مفرد. ولا تحمل مفتاح `tracking`، لأن التفاعل يُبلَّغ عنه لاحقًا ولا شيء يُبلَّغ عنه وقت القبول.
items[].email.replayedboolean
صحيحة عندما يطابق `Idempotency-Key` المشتق عملية إرسال موجودة أصلًا، فلا شيء جديد أُرسل وهذه هي الرسالة الأصلية.
items[].error{ type: string; code: string; message: string; param?: string }
لماذا رُفضت هذه الرسالة وحدها، في مدخلة `error` فقط. وهو مُغلَّف الخطأ الخاص بواجهة API منقوصًا منه `docUrl` و`requestId`: فهذان يصفان الطلب، والطلب ككل قد نجح.
items[].error.typestring
الفئة التي يجوز للعميل التفريع عليها: `validation_error` و`permission_error` و`not_found_error` و`conflict_error` وغيرها. والمجموعة مجمّدة ولن تكبر، بخلاف `code`.
items[].error.codestring
الفشل المحدد: `from_address_forbidden` و`invalid_email_address` و`too_many_recipients` و`reserved_header` و`message_too_large` و`unknown_parameter`. مفتوحة وقابلة للإضافة، فعامل أي رمز لا تعرفه معاملة `type` الخاص به.
items[].error.messagestring
جملة واحدة مكتوبة لإنسان، تسمي القيمة المخالفة حيث توجد واحدة. وليست معرّفًا ثابتًا. فرّع على `code`.
items[].error.paramstring
الحقل الذي رُفض، كمسار منقوط داخل تلك الرسالة: `to.0` أو `from` أو `attachments`. وغائب عندما لا يسمي الفشل أي حقل، ولا يُسبق أبدًا بموضع العنصر في الدفعة، فذاك ما يفيده `index`.