バッチ送信する
`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 はメッセージの Hash の Array を受け取ります。それぞれの形は emails.send のボディとまったく同じで、OpenEmail::BatchResult を返します。その items にはメッセージごとに 1 つの Hash が順番に入り、それぞれメッセージ付きの ok か、そのメッセージが拒否された理由を示すエンベロープ付きの error です。何もロールバックされないため、failed の件数が 0 より大きいときは、バッチを再送する理由ではなく、対処すべき一覧として扱ってください。
1 つの冪等性キーがバッチ全体を対象とし、サーバーはそれをアイテムごとに拡張するため、リトライしたバッチはメッセージを最初のものにまとめてしまうことなく、すべてのメッセージを再生します。リトライするときは同じ Array を同じ順序で送ってください。位置が変わったアイテムは別の位置のキーに結びつけられ、idempotency_key_reuse エラーとして返ってきます。
拒否されたメッセージは例外を送出しません。例外を送出するのはバッチ全体の問題だけです:空の Array、100 件を超えるメッセージ、translate を含むメッセージが 10 件を超える、キーまたはスコープの失敗、サーバー障害。途中で起きたサーバー障害は前のアイテムが送られた後に起きており、クライアントは同じキーでリトライするため、それらのアイテムは二重に送られずに再生されます。
アイテムは 1 つのリクエストの中で順番に送られるため、即時送信の大きなバッチは 1 回の send よりかなり時間がかかります。クライアントの timeout: は余裕を持たせてください。
パラメーター:emails.send_batch
emailsArray<Hash>必須- 1〜100 件のメッセージで、`{"emails": [...]}` として送られ、指定された順に 1 件ずつ受け付けられます。各メッセージは `emails.send` と同じ処理を経るため、受信者が 1 人なら包まれ、Time は時刻に変換され、添付ファイルのバイト列はエンコードされます。空の Array、100 件を超える場合、または `translate` を含むメッセージが 10 件を超える場合は、呼び出し全体が `emails` に対する `validation_error` で拒否されます。`emails:send` スコープがない場合や `idempotency_key:` の形式が不正な場合も、1 件も送信される前に呼び出し全体が拒否されます。
idempotency_keyString- プロセスをまたいでバッチの重複を防ぎます。クライアントはいずれにせよ呼び出しごとに新しく生成したキーを付与するため、自身のリトライで二重送信することはありません。サーバーは受け取ったキーをアイテムごとに `key/0`、`key/1` のように拡張します。区切りのスラッシュは独自のキーに使えない文字なので、100 件のメッセージに 1 つのキーを使っても、すべてが最初のものにまとめられることはありません。
api_keyString- クライアントのキーではなく、このキーでバッチを送信します。
emails の各メッセージ
fromString or Hash必須- 送信者で、素のアドレス、`Name <addr@host>`、または `email` と `name` を持つ Hash。代わりの送信者はなく、キーにこのアドレスが許可されている必要があります。拒否された場合はそのアイテムだけが、コード `from_address_forbidden` の `permission_error` として失敗します。
toString, Hash or Array必須- 受信者は少なくとも 1 人で、1 人だけの場合はクライアントが Array に包みます。`to`、`cc`、`bcc` を合わせて最大 50 アドレスで、バッチ全体ではなくメッセージごとに数えます。
ccString, Hash or Array- 既定ではなしです。`to` や `bcc` と同じ合計 50 アドレスの上限に数えられます。
bccString, Hash or Array- 既定ではなしです。同じ合計 50 アドレスの上限に数えられます。`Bcc` は `headers` で設定できない名前の 1 つなので、ブラインドコピーの手段はこれだけです。ヘッダー形式では、アドレスを隠すための受信者ごとのエンベロープが台無しになってしまいます。
replyToString or Hash- 返信の宛先。`headers` の後に適用されるので、そこで設定した `Reply-To` に 2 つ目を足すのではなく上書きします。
subjectString- 最大 998 文字で、RFC 5322 の行の上限です。既定値は空の String です。`template` が件名を持つ場合、空の件名はテンプレート自身の件名になります。
htmlString- HTML パート。最大 100 万文字で、両方の本文が与えられたときに受信者が見るのはこちらです。`html`、`text`、`template`、`draftId` のいずれか 1 つが必要で、どれも持たない項目は `html` に対する `validation_error` として失敗します。
textString- プレーンテキストの部分で、最大 100 万文字。両方を送ることもできますが、この経路のトランスポートはどれも 1 つの String から 1 つのボディを作るため、`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 を含められません。2 行目は 2 つ目のヘッダーになってしまうからです。
attachmentsArray<Hash>- メッセージごとに最大 20 ファイルで、インラインファイルはデコード後の合計 5 MB まで。バッチ全体ではなくメッセージごとに数えます。`content` は通信上では base64 です。バイト列をバイナリの String、IO、Pathname として渡せば、クライアントがエンコードします。`fileId` だけを持つ Hash はすでにワークスペースにあるファイルを指し、インラインの上限には数えられません。
threadIdString- 既存のスレッドへ返信します。最大 256 文字。トランスポートはこれをもとに In-Reply-To と References を書き込み、それによって返信が会話の横ではなく中に着地します。
draftIdString- 保存済みの下書きの内容を、このエンベロープで送信します。最大 256 文字。ここで組み立てた受信者、件名、ヘッダーが実際に送られます。
templateHash- 保存済みのテンプレートを、id(`tpl_…`)または slug でサーバー側でレンダリングします。`version` でリビジョンを固定し、`props` と `slots` で内容を埋めます。アイテムが受け付けられた時点で一度だけ確定し、`html` や `text`、`draftId` と一緒に指定すると拒否されます。どれもメッセージの内容に対する 2 つ目の答えになってしまうからです。
scheduledAtTime, DateTime or String- Time または DateTime、ISO 8601 の時刻、または `PT1H` のような期間で、少なくとも 1 秒先、最大 365 日先まで。Ruby の Date はその日の UTC 午前 0 時を意味します。アイテムは個別にスケジュールされるため、1 つのバッチに 100 通りの送信時刻を持たせることもできます。
cancellableForSecondsInteger- 即時送信の取り消し猶予を秒で指定し、0〜900、既定値は 0。同じアイテムで `scheduledAt` と一緒に 0 より大きい値を指定すると拒否されます。スケジュールされたメッセージは送られるまですでにキャンセルできるからです。
trackingHash- `opens` と `clicks`。どちらも省略可能で、それぞれこのメッセージに限って設定を上書きします。省略したキーは、送信元アドレス(またはそれを受け取った catch-all)の設定に従い、そのアドレスで有効にしていない限りオフです。
tagsHash- 最大 10 個のラベル。キーは `A-Za-z0-9_-` から成る 1〜64 文字、値は最大 256 文字です。メッセージ上にそのまま返され、解釈されることはありません。`emails.list` が絞り込みに使うのは `status:`、`from:`、`broadcast_id:` とスケジュールの期間だけなので、タグはメッセージを探す手段ではなく、すでに手元にあるメッセージから読み取るものです。
translateHash- このアイテムを別の言語で送信します。受け付けの時点で確定するため、承認された文面がそのまま送られます。1 つのバッチでこれを指定できるのは最大 10 アイテムです。それぞれがモデル呼び出しを何回か消費し、アイテムは順番に処理されるため、それより大きなバッチは送信の途中で打ち切られてしまいます。それを超えると、何かが送信される前に呼び出し全体が `emails` に対する `too_many_items` として拒否されます。
レスポンス:OpenEmail::BatchResult
itemsArray<Hash>- 送った順に、メッセージごとに 1 つの Hash。何もロールバックされないため、これはトランザクションの報告ではなく、各メッセージに何が起きたかの記録です。API は、すべてのメッセージが受け付けられても、一部だけでも、1 件もなくても 207 を返すため、呼び出しはどの場合も戻り、分岐には各アイテムの `status` を使います。
sentInteger- 「受け付けられた」アイテムの数で、送り出された数と同じではありません。アイテムが `ok` でも、その `email` の `status` が `failed` や `partial` のことがあります。行が作られた後でトランスポートがメッセージを拒否するのは配信の結果であって、拒否されたリクエストではないからです。
failedInteger- `error` を持つアイテムの数。0 より大きければ、バッチを再送する理由ではなく、対処すべき一覧です。受け付けられたメッセージはすでに送られています。
各アイテム
indexInteger- このアイテムのメッセージが、送った Array の中で占めていた位置。順序としてだけでなくキーとしても保持されるため、`items` を絞り込んだり並べ替えたりするコードでも、どのメッセージが失敗したかが分かります。
statusString- `ok` または `error`。`ok` には `email` が、`error` には `error` が含まれ、両方を持つアイテムはありません。
emailHash- 受け付けられたメッセージで、`ok` のアイテムにだけ存在し、単独の送信が返すのと同じ形です。導出された `Idempotency-Key` が既存の送信と一致した場合は `replayed` が true で、新たには何も送信されておらず、これは元のメッセージです。`tracking` キーは含みません。エンゲージメントは後から報告されるもので、受け付けの時点では報告することが何もないからです。
errorHash- このメッセージだけが拒否された理由で、`error` のアイテムにだけ存在します。API のエラーエンベロープから `docUrl` と `requestId` を除いたものです。この 2 つはリクエストを説明するもので、リクエスト全体としては成功しているからです。
アイテムのエラー
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- 人向けに書かれた 1 文で、問題の値があればそれを名指しします。安定した識別子ではありません。分岐は `code` で行ってください。
paramString- 拒否されたフィールドを、そのメッセージ内のドット区切りパスで示します。`to.0`、`from`、`attachments` のような形です。フィールドを特定できない失敗では存在せず、バッチ内の位置が前置されることはありません。そちらは `index` の役目です。