ارسال دستهای
`emails.send_batch`: تا 100 پیام، با نتیجه به ازای هر مورد.
emails.send_batch
invoices = [ {number: "INV-1042", email: "[email protected]"}, {number: "INV-1043", email: "[email protected]"}] messages = invoices.map do |invoice| {from: "[email protected]", to: invoice[:email], subject: "Invoice #{invoice[:number]}", text: "Your invoice is attached."}end result = client.emails.send_batch(messages, idempotency_key: "invoices:2026-09") puts "#{result.sent} sent, #{result.failed} failed" result.items.each do |item| if item[:status] == "error" warn "#{item[:index]} #{item.dig(:error, :code)} #{item.dig(:error, :message)}" else puts "#{item[:index]} #{item.dig(:email, :id)}" endendsend_batch یک Array از Hashهای پیام میگیرد که هرکدام دقیقاً همشکل بدنهٔ emails.send است، و یک OpenEmail::BatchResult برمیگرداند. items آن برای هر پیام یک Hash دارد، به همان ترتیب، که هرکدام یا ok است با پیامش، یا error است با پاکتی که آن پیام با آن رد میشد. هیچچیز بازگردانده نمیشود، پس شمار failed بالاتر از 0 فهرستی برای اقدام است نه دلیلی برای فرستادن دوبارهٔ دسته.
یک کلید idempotency کل دسته را پوشش میدهد و سرور آن را برای هر مورد گسترش میدهد، پس دستهای که دوباره تلاش شود هر پیام را بازپخش میکند، نه اینکه همه را روی اولی جمع کند. وقتی دوباره تلاشش میکنید همان Array را به همان ترتیب بفرستید: موردی که جابهجا شده به کلید جایگاه دیگری گره میخورد و بهصورت خطای idempotency_key_reuse برمیگردد.
پیامی که رد شود خطا raise نمیکند. فقط مشکلی با کل دسته raise میشود: یک Array خالی، بیش از 100 پیام، بیش از 10 پیام دارای translate، شکست کلید یا اسکوپ، یا خطای سرور. خطای سرور در میانهٔ کار پس از رفتن موردهای پیشین رخ میدهد، و کلاینت با همان کلید دوباره تلاشش میکند، که آن موردها را بهجای دو بار فرستادن، بازپخش میکند.
موردها یکی پس از دیگری درون یک درخواست فرستاده میشوند، پس یک دستهٔ بزرگ از ارسالهای فوری بهطور محسوسی بیشتر از یک send طول میکشد. timeout: کلاینت را سخاوتمندانه تنظیم کنید.
پارامترها: emails.send_batch
emailsArray<Hash>الزامی- یک تا 100 پیام، که به شکل `{"emails": [...]}` فرستاده میشوند و یکییکی به همان ترتیب دادهشده پذیرفته میشوند. هرکدام همان پردازشی را میگذراند که `emails.send` دارد، پس گیرندهٔ تنها در Array پیچیده میشود، Time به یک لحظه تبدیل میشود و بایتهای پیوست رمزگذاری میشوند. یک Array خالی، بیش از 100 پیام، یا بیش از 10 پیام دارای `translate`، کل فراخوانی را با یک `validation_error` روی `emails` رد میکند. نبود اسکوپ `emails:send` و `idempotency_key:` بدشکل هم کل فراخوانی را رد میکنند، پیش از آنکه حتی یک پیام فرستاده شود.
idempotency_keyString- دسته را در میان فرایندها یکتاسازی میکند. کلاینت در هر حال روی هر فراخوانی کلیدی تازهساخته میچسباند، پس تلاشهای دوبارهٔ خودش هرگز دو بار نمیفرستند، و سرور هر کلیدی را که بگیرد برای هر مورد به شکل `key/0`، `key/1` و همینطور ادامه گسترش میدهد، جداشده با اسلش، نویسهای که کلید خودِ شما اجازهٔ داشتنش را ندارد، تا یک کلید روی صد پیام نتواند همه را روی اولی جمع کند.
api_keyString- دسته را بهجای کلید کلاینت با این کلید میفرستد.
هر پیام در emails
fromString or Hashالزامی- فرستنده، به شکل نشانی خام، `Name <addr@host>` یا یک Hash با `email` و `name`. هیچ فرستندهٔ جایگزینی وجود ندارد و کلید باید اجازهٔ این نشانی را داشته باشد. رد شدن فقط همان یک مورد را شکست میدهد، به شکل یک `permission_error` با کد `from_address_forbidden`.
toString, Hash or Arrayالزامی- دستکم یک گیرنده، و اگر یکی تنها بدهید کلاینت آن را در یک Array میپیچد. حداکثر 50 نشانی روی هم در `to`، `cc` و `bcc`، که به ازای هر پیام شمرده میشود نه در کل دسته.
ccString, Hash or Array- پیشفرض: هیچ، و به همان سقف 50 نشانی شمرده میشود که `to` و `bcc` هم به آن شمرده میشوند.
bccString, Hash or Array- پیشفرض: هیچ، و به همان سقف 50 نشانی شمرده میشود. `Bcc` یکی از نامهایی است که `headers` اجازهٔ تنظیمش را ندارد، پس این تنها راه رونوشت پنهان است. شکل هدری، همان پاکتِ بهازایهرگیرنده را که نشانی را پنهان نگه میدارد از بین میبرد.
replyToString or Hash- جایی که پاسخها میروند. پس از `headers` اعمال میشود، پس `Reply-To`ای را که آنجا هم گذاشته باشید بازنویسی میکند، نه اینکه دومی اضافه کند.
subjectString- حداکثر 998 نویسه، همان حد طول خط RFC 5322، با پیشفرض یک String خالی. موضوع خالی، وقتی `template` موضوعی داشته باشد، به موضوع خودِ قالب میافتد.
htmlString- بخش HTML، حداکثر یک میلیون نویسه، و همان بخشی که وقتی هر دو بدنه داده شوند گیرندگان میبینند. یکی از `html`، `text`، `template` یا `draftId` الزامی است، و موردی که هیچکدام را نداشته باشد با یک `validation_error` روی `html` شکست میخورد.
textString- بخش متن ساده، حداکثر یک میلیون نویسه. هر دو را میشود فرستاد، و هر لایهٔ انتقالی در این مسیر از یک String یک بدنه میسازد، پس هرجا `html` باشد همان برنده است.
headersHash- فقط `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 داشته باشند، چون خط دوم یعنی سرآیند دوم.
attachmentsArray<Hash>- حداکثر 20 فایل به ازای هر پیام، با مجموع 5 MB برای فایلهای درونخطی پس از رمزگشایی، که به ازای هر پیام شمرده میشود نه به ازای دسته. `content` روی سیم base64 است. بایتها را بهصورت یک String دودویی، یک IO یا یک Pathname بدهید تا کلاینت رمزگذاریشان کند. یک Hash فقط با `fileId` فایلی را نام میبرد که از پیش در فضای کاری هست و در سقف درونخطی شمرده نمیشود.
threadIdString- پاسخدادن درون یک thread موجود، حداکثر 256 نویسه. حملونقل In-Reply-To و References را از روی آن مینویسد، و همین است که باعث میشود پاسخ داخل گفتوگو بنشیند نه کنارش.
draftIdString- محتوای یک پیشنویس ذخیرهشده را زیر این پاکت بفرستید، حداکثر 256 نویسه. گیرندگان، موضوع و سرآیندهایی که اینجا ساخته میشوند همانهاییاند که روی سیم میروند.
templateHash- یک قالب ذخیرهشده را سمت سرور رندر میکند، با شناسه (`tpl_…`) یا slug، که `version` یک نسخه را سنجاق میکند و `props` و `slots` آن را پر میکنند. یک بار و هنگام پذیرفتهشدن مورد تعیین میشود، و در کنار `html` یا `text` و در کنار `draftId` رد میشود، چون هرکدام از آنها پاسخی دوم به این پرسش است که پیام چه چیزی دارد.
scheduledAtTime, DateTime or String- یک Time یا DateTime، یک لحظهٔ ISO 8601، یا مدتی مانند `PT1H`، دستکم یک ثانیه در آینده و حداکثر 365 روز بعد. یک Date در Ruby یعنی نیمهشب UTC همان روز. موردها مستقل از هم زمانبندی میشوند، پس یک دسته میتواند صد زمان ارسال متفاوت داشته باشد.
cancellableForSecondsInteger- پنجرهٔ لغو برحسب ثانیه روی یک ارسال فوری، از 0 تا 900 با پیشفرض 0. هر مقدار بالای 0 در کنار `scheduledAt` روی همان مورد رد میشود، چون پیام زمانبندیشده تا وقتی نرفته از پیش قابل لغو است.
trackingHash- `opens` و `clicks`، که هرکدام اختیاریاند و هرکدام تنظیم را فقط برای همین یک پیام بازنویسی میکنند. کلیدی که ننویسید از نشانیای که پیام از آن فرستاده میشود (یا catch-allی که آن را گرفته) پیروی میکند، که خاموش است مگر همان نشانی روشنش کرده باشد.
tagsHash- حداکثر 10 برچسب، با کلیدهای 1 تا 64 نویسه از میان `A-Za-z0-9_-` و مقدارهای تا 256 نویسه. روی پیام همانطور بازگردانده میشوند و هرگز تفسیر نمیشوند: `emails.list` فقط بر اساس `status:`، `from:`، `broadcast_id:` و بازهٔ زمانبندی فیلتر میکند و بس، پس برچسب چیزی است که از روی پیامی که از پیش در دست دارید بخوانید، نه راهی برای یافتنش.
translateHash- این مورد را به زبانی دیگر بفرستید، که در زمان پذیرش تعیین میشود تا کلماتی که تأیید شدهاند همان کلماتی باشند که بیرون میروند. حداکثر 10 مورد در یک دسته میتوانند آن را داشته باشند: هرکدام چند فراخوانی مدل خرج میکند و موردها به ترتیب اجرا میشوند، پس دستهای بزرگتر وسط ارسال قطع میشد. بیش از آن، کل فراخوانی با `too_many_items` روی `emails` رد میشود، پیش از آنکه چیزی فرستاده شود.
پاسخ: OpenEmail::BatchResult
itemsArray<Hash>- یک Hash برای هر پیام، به همان ترتیبی که فرستادهاید. هیچچیز بازگردانده نمیشود، پس این سابقهٔ آن است که بر سر هر پیام چه آمد، نه گزارشی دربارهٔ یک تراکنش. API چه همهٔ پیامها پذیرفته شوند، چه بعضی و چه هیچکدام، 207 پاسخ میدهد، پس فراخوانی در هر حال برمیگردد و آنچه باید رویش شاخه بزنید `status` هر مورد است.
sentInteger- چند مورد «پذیرفته» شدهاند، که همان تعداد موردهایی نیست که رفتهاند. یک مورد میتواند `ok` باشد و باز هم `email`ای داشته باشد که `status` آن `failed` یا `partial` است، چون لایهٔ انتقالی که پس از ساخته شدن ردیف پیام را رد کند، نتیجهای از تحویل است نه درخواستی ردشده.
failedInteger- چند مورد `error` دارند. شمار بالاتر از 0 فهرستی برای اقدام است نه دلیلی برای فرستادن دوبارهٔ دسته. پیامهای پذیرفتهشده پیش از این رفتهاند.
هر مورد
indexInteger- جایگاهی که پیامِ این مورد در Array فرستادهشده داشت. علاوه بر ترتیب، به شکل یک کلید هم حمل میشود، تا کدی که `items` را فیلتر یا مرتب میکند باز هم بتواند بگوید کدام پیام شکست خورده است.
statusString- `ok` یا `error`. `ok` حامل `email` است، `error` حامل `error`، و هیچ موردی هر دو را ندارد.
emailHash- پیام پذیرفتهشده، فقط روی مورد `ok`، با همان شکلی که یک ارسال تکی برمیگرداند. `replayed` آن وقتی true است که `Idempotency-Key` مشتقشده با ارسالی که از پیش وجود داشته مطابقت کرده باشد، پس چیز تازهای فرستاده نشده و این همان پیام اصلی است. کلید `tracking` ندارد، چون تعامل بعداً گزارش میشود و در زمان پذیرش چیزی برای گزارش نیست.
errorHash- چرا همین یک پیام رد شد، فقط روی مورد `error`. این همان پاکت خطای API است منهای `docUrl` و `requestId`: آن دو خودِ درخواست را توصیف میکنند و درخواست بهعنوان یک کل موفق بوده است.
خطای یک مورد
typeString- دستهای که باید رویش شاخه بزنید: `validation_error`، `permission_error`، `not_found_error`، `conflict_error` و بقیه. این مجموعه ثابت است و بزرگتر نخواهد شد، برخلاف `code`.
codeString- شکست مشخص: `from_address_forbidden`، `invalid_email_address`، `too_many_recipients`، `reserved_header`، `message_too_large`، `unknown_parameter`. باز و افزودنی است، پس با کدی که نمیشناسید مثل `type` خودش رفتار کنید.
messageString- یک جملهٔ نوشتهشده برای آدم، که مقدار خطاساز را در جایی که وجود دارد نام میبرد. شناسهای پایدار نیست. روی `code` شاخه بزنید.
paramString- فیلدی که رد شد، به شکل مسیری نقطهدار درون همان یک پیام: `to.0`، `from`، `attachments`. وقتی شکست هیچ فیلدی را نام نبرد غایب است، و هرگز با جایگاه مورد در دسته پیشوند نمیگیرد؛ آن کارِ `index` است.