پرش به مستندات
Python

ارسال دسته‌ای

`emails.send_batch`: تا 100 پیام، با نتیجه به ازای هر مورد.

emails.send_batch

send_batch.py
import sys from openemail import openemailfrom openemail.types import EmailSend invoices = {'[email protected]': 'INV-4021', '[email protected]': 'INV-4022'} messages: list[EmailSend] = [    {'from': '[email protected]', 'to': to, 'subject': f'Invoice {number}', 'text': 'Attached.'}    for to, number in invoices.items()] result = openemail.emails.send_batch(messages) print(result['sent'], 'sent,', result['failed'], 'failed') for item in result['items']:    if item['status'] == 'error':        print(item['index'], item['error']['code'], item['error']['message'], file=sys.stderr)    else:        print(item['index'], item['email']['id'])

items به ازای هر ورودی یک درایه دارد، به همان ترتیب، که هرکدام یا ok است با پیامش، یا error است با پاکتی که آن پیام با آن رد می‌شد. هیچ‌چیز بازگردانده نمی‌شود، پس failed > 0 فهرستی برای اقدام است نه دلیلی برای فرستادن دوبارهٔ دسته.

یک کلید idempotency کل دسته را پوشش می‌دهد و سرور آن را به ازای هر مورد گسترش می‌دهد، پس دسته‌ای که دوباره فرستاده شود هر پیام را بازپخش می‌کند، نه اینکه همه را روی اولی جمع کند.

پارامترها: emails.send_batch

emailsSequence[EmailSend]الزامی
یک تا 100 پیام، که به شکل `{ "emails": [...] }` سریال می‌شوند و یکی‌یکی به همان ترتیب داده‌شده پذیرفته می‌شوند. فهرست خالی، بیش از 100 مورد، یا بیش از 10 موردی که `translate` دارند، کل فراخوانی را با یک `validation_error` روی `emails` رد می‌کند. نبودِ اسکوپ `emails:send` و یک `idempotency_key` بدشکل هم همین کار را می‌کنند، هر دو پیش از آنکه حتی یک پیام فرستاده شود.
idempotency_keystr
دسته را در میان پردازه‌ها یکتاسازی می‌کند. کلاینت در هر حال روی هر فراخوانی کلیدی تازه‌ساخته می‌چسباند، پس بازفرست‌های خودش هرگز دوبار نمی‌فرستند، و سرور هر کلیدی را که بگیرد به ازای هر مورد به شکل `key/0`، `key/1` و همین‌طور ادامه گسترش می‌دهد، جداشده با اسلشی که کلید خودِ شما اجازهٔ داشتنش را ندارد، تا یک کلید روی صد پیام نتواند همه را روی اولی جمع کند.
emails[].fromRecipientInputالزامی
فرستنده، به شکل نشانی خام، `Name <addr@host>` یا یک دیکشنری. هیچ فرستندهٔ جایگزینی وجود ندارد و کلید باید اجازهٔ این نشانی را داشته باشد؛ رد شدن فقط همان یک مورد را شکست می‌دهد، به شکل یک `permission_error` با کد `from_address_forbidden`.
emails[].toRecipientInput | list[RecipientInput]الزامی
دست‌کم یک گیرنده، و اگر یکی تنها بدهید کلاینت آن را در یک فهرست می‌پیچد. حداکثر 50 نشانی روی هم در `to`، `cc` و `bcc`، که به ازای هر پیام شمرده می‌شود نه در کل دسته.
emails[].ccRecipientInput | list[RecipientInput]
پیش‌فرض: هیچ، و به همان سقف 50 نشانی شمرده می‌شود که `to` و `bcc` هم به آن شمرده می‌شوند.
emails[].bccRecipientInput | list[RecipientInput]
پیش‌فرض: هیچ، و به همان سقف 50 نشانی شمرده می‌شود. `Bcc` یکی از نام‌هایی است که `headers` اجازهٔ تنظیمش را ندارد، پس این تنها راه رونوشت پنهان است. شکل هدری، همان پاکتِ به‌ازای‌هر‌گیرنده را که نشانی را پنهان نگه می‌دارد از بین می‌برد.
emails[].replyToRecipientInput
جایی که پاسخ‌ها می‌روند. پس از `headers` اعمال می‌شود، پس `Reply-To`ای را که آنجا هم گذاشته باشید بازنویسی می‌کند، نه اینکه دومی اضافه کند.
emails[].subjectstr
حداکثر 998 نویسه، همان حد طول خط RFC 5322، با پیش‌فرض رشتهٔ خالی. موضوع خالی، وقتی `template` موضوعی داشته باشد، به موضوع خودِ قالب می‌افتد.
emails[].htmlstr
بخش HTML، حداکثر یک میلیون نویسه، و همان بخشی که وقتی هر دو بدنه داده شوند گیرندگان می‌بینند. یکی از `html`، `text`، `template` یا `draftId` الزامی است، و موردی که هیچ‌کدام را نداشته باشد با یک `validation_error` روی `html` شکست می‌خورد.
emails[].textstr
بخش متن ساده، حداکثر یک میلیون نویسه. هر دو را می‌شود فرستاد، و هر حمل‌ونقلی در این مسیر از یک رشته یک بدنه می‌سازد، پس هرجا `html` باشد همان برنده است.
emails[].headersdict[str, str]
فقط `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[].attachmentslist[AttachmentInput]
حداکثر 20 فایل به ازای هر پیام، با مجموع 5 MB برای فایل‌های درون‌خطی پس از رمزگشایی، که به ازای هر پیام شمرده می‌شود نه به ازای دسته. `content` روی سیم base64 است؛ بایت بدهید تا کلاینت رمزگذاری‌اش کند. درایهٔ `{'fileId': ...}` فایلی را نام می‌برد که از پیش در فضای کاری هست و در سقف درون‌خطی شمرده نمی‌شود.
emails[].threadIdstr
پاسخ‌دادن درون یک thread موجود، حداکثر 256 نویسه. حمل‌ونقل In-Reply-To و References را از روی آن می‌نویسد، و همین است که باعث می‌شود پاسخ داخل گفت‌وگو بنشیند نه کنارش.
emails[].draftIdstr
محتوای یک پیش‌نویس ذخیره‌شده را زیر این پاکت بفرستید، حداکثر 256 نویسه. گیرندگان، موضوع و هدرهایی که اینجا ساخته می‌شوند همان‌هایی‌اند که روی سیم می‌روند.
emails[].templateEmailSendTemplate
یک قالب ذخیره‌شده را سمت سرور رندر می‌کند، با شناسه (`tpl_…`) یا slug، که `version` یک بازنگری را سنجاق می‌کند و `props`/`slots` آن را پر می‌کنند. یک‌بار و هنگام پذیرفته‌شدن مورد حل می‌شود، و در کنار `html`/`text` و در کنار `draftId` رد می‌شود، چون هرکدام از آن‌ها پاسخی دوم به این پرسش است که پیام چه چیزی دارد.
emails[].scheduledAtdatetime | str
یک `datetime`، یک لحظهٔ ISO-8601، یا مدتی مانند `PT1H`؛ دست‌کم یک ثانیه در آینده و حداکثر 365 روز بعد. موردها مستقل از هم زمان‌بندی می‌شوند، پس یک دسته می‌تواند صد زمان ارسال متفاوت داشته باشد.
emails[].cancellableForSecondsint
پنجرهٔ لغو بر حسب ثانیه روی یک ارسال فوری، عددی صحیح از 0 تا 900 با پیش‌فرض 0. هر مقدار بالای 0 در کنار `scheduledAt` روی همان مورد رد می‌شود، چون پیام زمان‌بندی‌شده تا وقتی نرفته از پیش قابل لغو است.
emails[].trackingTrackingRequest
`opens` و `clicks`، که هرکدام جداگانه اختیاری‌اند و هرکدام تنظیم را فقط برای همین یک پیام بازنویسی می‌کنند. کلیدی که ننویسید از نشانی‌ای که پیام از آن فرستاده می‌شود (یا catch-all‌ای که آن را گرفته) پیروی می‌کند، که خاموش است مگر همان نشانی روشنش کرده باشد.
emails[].tagsdict[str, str]
حداکثر 10 برچسب، با کلیدهای 1 تا 64 نویسه از میان `A-Za-z0-9_-` و مقدارهای تا 256 نویسه. روی پیام بازتاب داده می‌شوند و هرگز تفسیر نمی‌شوند: `emails.list` فقط بر پایهٔ `status`، `from_`، `broadcast_id`، `scheduled_from` و `scheduled_to` فیلتر می‌کند و بس، پس برچسب چیزی است که از روی پیامی که از پیش در دست دارید بخوانید، نه راهی برای یافتنش.
emails[].translateSendTranslateOptions
این مورد را به زبانی دیگر بفرستید، که در زمان پذیرش حل می‌شود تا کلماتی که تأیید شده‌اند همان کلماتی باشند که بیرون می‌روند. حداکثر 10 مورد در یک دسته می‌توانند آن را داشته باشند: هرکدام چند فراخوانی مدل خرج می‌کند و موردها به ترتیب اجرا می‌شوند، پس دسته‌ای بزرگ‌تر وسط ارسال کشته می‌شد. بیش از آن، کل فراخوانی با `too_many_items` روی `emails` رد می‌شود، پیش از آنکه چیزی فرستاده شود.

پاسخ: BatchResultResource

itemslist[BatchItemResource]
به ازای هر ورودی یک درایه، به همان ترتیبی که فرستاده‌اید. هیچ‌چیز بازگردانده نمی‌شود، پس این سابقهٔ آن است که بر سر هر پیام چه آمد، نه گزارشی دربارهٔ یک تراکنش. API چه همهٔ پیام‌ها پذیرفته شوند، چه بعضی و چه هیچ‌کدام، 207 پاسخ می‌دهد، پس فراخوانی در هر حال برمی‌گردد و آنچه باید رویش شاخه بزنید `status` هر مورد است.
sentint
چند مورد ACCEPTED شده‌اند، که همان تعداد موردهایی نیست که رفته‌اند. یک مورد می‌تواند `ok` باشد و باز هم `email.status` برابر `failed` یا `partial` داشته باشد، چون حمل‌ونقلی که پس از ساخته‌شدن ردیف پیام را رد کند، نتیجه‌ای از تحویل است نه درخواستی ردشده.
failedint
چند درایه `error` دارند. `failed > 0` فهرستی برای اقدام است نه دلیلی برای فرستادن دوبارهٔ دسته. پیام‌های پذیرفته‌شده پیش از این رفته‌اند.
items[].indexint
جایگاهی که پیامِ این درایه در فهرست فرستاده‌شده داشت. علاوه بر ترتیب، به شکل یک فیلد هم حمل می‌شود، تا کدی که `items` را فیلتر یا مرتب می‌کند باز هم بتواند بگوید کدام ورودی شکست خورده است.
items[].statusLiteral['ok', 'error']
تفکیک‌کنندهٔ union: `ok` حامل `email` است، `error` حامل `error`، و هیچ درایه‌ای هر دو را حمل نمی‌کند.
items[].emailSentEmailResource
پیام پذیرفته‌شده، فقط روی درایهٔ `ok`، با همان شکلی که یک ارسال تکی برمی‌گرداند. کلید `tracking` ندارد، چون تعامل بعداً گزارش می‌شود و در زمان پذیرش چیزی برای گزارش نیست.
items[].email.replayedbool
وقتی true است که `Idempotency-Key` مشتق‌شده با ارسالی که از پیش وجود داشته مطابقت کرده باشد، پس چیز تازه‌ای فرستاده نشده و این همان پیام اصلی است.
items[].errorBatchItemResourceErrorError
چرا همین یک پیام رد شد، فقط روی درایهٔ `error`. این همان پاکت خطای API است منهای `docUrl` و `requestId`: آن دو خودِ درخواست را توصیف می‌کنند و درخواست به‌عنوان یک کل موفق بوده است.
items[].error.typestr
دسته‌ای که کلاینت می‌تواند رویش شاخه بزند: `validation_error`، `permission_error`، `not_found_error`، `conflict_error` و بقیه. این مجموعه منجمد است و بزرگ‌تر نخواهد شد، برخلاف `code`.
items[].error.codestr
شکست مشخص: `from_address_forbidden`، `invalid_email_address`، `too_many_recipients`، `reserved_header`، `message_too_large`، `unknown_parameter`. باز و افزودنی است، پس با کدی که نمی‌شناسید مثل `type` خودش رفتار کنید.
items[].error.messagestr
یک جملهٔ نوشته‌شده برای آدم، که مقدار خطاساز را در جایی که وجود دارد نام می‌برد. شناسه‌ای پایدار نیست. روی `code` شاخه بزنید.
items[].error.paramNotRequired[str]
فیلدی که رد شد، به شکل مسیری نقطه‌دار درون همان یک پیام: `to.0`، `from`، `attachments`. وقتی شکست هیچ فیلدی را نام نبرد غایب است، و هرگز با جایگاه مورد در دسته پیشوند نمی‌گیرد؛ آن کارِ `index` است.

مرجع