バッチ送信する
`emails->sendBatch`:最大 100 件のメッセージ、アイテムごとの結果。
emails->sendBatch
$invoices = [ ['number' => 'INV-1042', 'email' => '[email protected]'], ['number' => 'INV-1043', 'email' => '[email protected]'],]; $messages = []; foreach ($invoices as $invoice) { $messages[] = [ 'from' => '[email protected]', 'to' => $invoice['email'], 'subject' => 'Invoice ' . $invoice['number'], 'text' => 'Your invoice is attached.', ];} $result = $client->emails->sendBatch($messages, idempotencyKey: 'invoices:2026-09'); echo $result->sent, ' sent, ', $result->failed, ' failed', PHP_EOL; foreach ($result as $item) { if ($item['status'] === 'error') { error_log($item['index'] . ' ' . $item['error']['code'] . ' ' . $item['error']['message']); } else { echo $item['index'], ' ', $item['email']['id'], PHP_EOL; }}sendBatch はメッセージの配列のリストを受け取ります。それぞれの形は emails->send が受け取る配列とまったく同じで、OpenEmail\Result\BatchResult を返します。その items にはメッセージごとに 1 つの配列が順番に入り、それぞれメッセージ付きの ok か、そのメッセージが拒否された理由を示すエンベロープ付きの error です。結果をループすると、これらを順にたどれます。何もロールバックされないため、failed の件数が 0 より大きいときは、バッチを再送する理由ではなく、対処すべき一覧として扱ってください。
1 つの冪等性キーがバッチ全体を対象とし、サーバーはそれをアイテムごとに拡張するため、リトライしたバッチはメッセージを最初のものにまとめてしまうことなく、すべてのメッセージをリプレイします。リトライするときは同じリストを同じ順序で送ってください。位置が変わったアイテムは別の位置のキーに結びつけられ、idempotency_key_reuse エラーとして返ってきます。
拒否されたメッセージは例外をスローしません。例外をスローするのはバッチ全体の問題だけです。空のリスト、100 件を超えるメッセージ、translate を含むメッセージが 10 件を超える場合、キーまたはスコープの失敗、サーバー障害がそれにあたります。途中で起きたサーバー障害は前のアイテムが送られた後に起きており、クライアントは同じキーでリトライするため、それらのアイテムは二重に送られずにリプレイされます。
アイテムは 1 つのリクエストの中で順番に送られるため、即時送信の大きなバッチは 1 回の send よりかなり時間がかかります。クライアントの timeout: は余裕を持たせてください。
パラメーター:emails->sendBatch
emailsarray必須- 1〜100 件のメッセージで、`{"emails": [...]}` として送られ、指定された順に 1 件ずつ受け付けられます。各メッセージは `emails->send` と同じ処理を経るため、受信者が 1 人なら包まれ、`DateTimeInterface` は時刻に変換され、添付ファイルのバイト列はエンコードされます。配列ではないエントリは、何かが送信される前に `InvalidArgumentException` をスローします。空のリスト、100 件を超える場合、または `translate` を含むメッセージが 10 件を超える場合は、呼び出し全体が `emails` に対する `validation_error` で拒否されます。`emails:send` スコープがない場合や `idempotencyKey:` の形式が不正な場合も、1 件も送信される前に呼び出し全体が拒否されます。
idempotencyKeystring- プロセスをまたいでバッチの重複を防ぎます。クライアントはいずれにせよ呼び出しごとに新しく生成したキーを付与するため、自身のリトライで二重送信することはありません。サーバーは受け取ったキーをアイテムごとに `key/0`、`key/1` のように拡張します。区切りのスラッシュは独自のキーに使えない文字なので、100 件のメッセージに 1 つのキーを使っても、すべてが最初のものにまとめられることはありません。
apiKeystring- クライアントのキーではなく、このキーでバッチを送信します。
emails の各メッセージ
fromstring or array必須- 送信者で、素のアドレス、`Name <addr@host>`、または `email` と `name` を持つ配列。代わりの送信者はなく、キーにこのアドレスが許可されている必要があります。拒否された場合はそのアイテムだけが、コード `from_address_forbidden` の `permission_error` として失敗します。
tostring or array必須- 受信者は少なくとも 1 人で、1 人だけの場合はクライアントがリストに包みます。`to`、`cc`、`bcc` を合わせて最大 50 アドレスで、バッチ全体ではなくメッセージごとに数えます。
ccstring or array- 既定ではなしです。`to` や `bcc` と同じ合計 50 アドレスの上限に数えられます。
bccstring or array- 既定ではなしです。同じ合計 50 アドレスの上限に数えられます。`Bcc` は `headers` で設定できない名前の 1 つなので、ブラインドコピーの手段はこれだけです。ヘッダー形式では、アドレスを隠すための受信者ごとのエンベロープが台無しになってしまいます。
replyTostring or array- 返信の宛先。`headers` の後に適用されるので、そこで設定した `Reply-To` に 2 つ目を足すのではなく上書きします。
subjectstring- 最大 998 文字で、RFC 5322 の行の上限です。既定値は空文字列です。`template` が件名を持つ場合、空の件名はテンプレート自身の件名になります。
htmlstring- HTML パート。最大 100 万文字で、両方の本文が与えられたときに受信者が見るのはこちらです。`html`、`text`、`template`、`draftId` のいずれか 1 つが必要で、どれも持たない項目は `html` に対する `validation_error` として失敗します。
textstring- プレーンテキストのパート。最大 100 万文字です。両方を送ることもできますが、この経路のすべてのトランスポートは 1 つの文字列から 1 つの本文を作るので、`html` があるときはそちらが勝ちます。
headersarray- `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- メッセージごとに最大 20 ファイルで、インラインファイルはデコード後の合計 5 MB まで。バッチ全体ではなくメッセージごとに数えます。`content` は通信上では base64 です。`fopen` のストリーム、`SplFileInfo`、PSR-7 ストリームを渡せばクライアントが読み込んでエンコードし、文字列を渡す場合はあらかじめ base64 にしておきます。`fileId` だけを持つ配列はすでにワークスペースにあるファイルを指し、インラインの上限には数えられません。
threadIdstring- 既存のスレッドへ返信します。最大 256 文字。トランスポートはこれをもとに In-Reply-To と References を書き込み、それによって返信が会話の横ではなく中に着地します。
draftIdstring- 保存済みの下書きの内容を、このエンベロープで送信します。最大 256 文字。ここで組み立てた受信者、件名、ヘッダーが実際に送られます。
templatearray- 保存済みのテンプレートを、id(`tpl_…`)または slug でサーバー側でレンダリングします。`version` でリビジョンを固定し、`props` と `slots` で内容を埋めます。アイテムが受け付けられた時点で一度だけ確定し、`html` や `text`、`draftId` と一緒に指定すると拒否されます。どれもメッセージの内容に対する 2 つ目の答えになってしまうからです。
scheduledAtDateTimeInterface or string- `DateTimeInterface`、ISO 8601 の時刻、または `PT1H` のような期間で、少なくとも 1 秒先、最大 365 日先まで。時刻のない日付文字列は、その日の UTC 午前 0 時を意味します。アイテムは個別にスケジュールされるため、1 つのバッチに 100 通りの送信時刻を持たせることもできます。
cancellableForSecondsint- 即時送信の取り消し猶予を秒で指定し、0〜900、既定値は 0。同じアイテムで `scheduledAt` と一緒に 0 より大きい値を指定すると拒否されます。スケジュールされたメッセージは送られるまですでにキャンセルできるからです。
trackingarray- `opens` と `clicks`。どちらも省略可能で、それぞれこのメッセージに限って設定を上書きします。省略したキーは、送信元アドレス(またはそれを受け取った catch-all)の設定に従い、そのアドレスで有効にしていない限りオフです。
tagsarray- 最大 10 個のラベル。キーは `A-Za-z0-9_-` から成る 1〜64 文字、値は最大 256 文字です。メッセージ上にそのまま返され、解釈されることはありません。`emails->list` が絞り込みに使うのは `status:`、`from:`、`broadcastId:` とスケジュールの期間だけなので、タグはメッセージを探す手段ではなく、すでに手元にあるメッセージから読み取るものです。
translatearray- このアイテムを別の言語で送信します。受け付けの時点で確定するため、承認された文面がそのまま送られます。1 つのバッチでこれを指定できるのは最大 10 アイテムです。それぞれがモデル呼び出しを何回か消費し、アイテムは順番に処理されるため、それより大きなバッチは送信の途中で打ち切られてしまいます。それを超えると、何かが送信される前に呼び出し全体が `emails` に対する `too_many_items` として拒否されます。
レスポンス:OpenEmail\Result\BatchResult
結果は読み取り専用で、items に対する IteratorAggregate であり、Countable でもあります。そのため foreach ($result as $item) でアイテムをたどり、count($result) で数えられます。
itemsarray- メッセージごとに 1 つの配列が、送った順に入ります。何もロールバックされないため、これはトランザクションの報告ではなく、各メッセージに何が起きたかの記録です。API は、すべてのメッセージが受け付けられた場合も、一部だけの場合も、1 件も受け付けられなかった場合も 207 を返すため、呼び出しはどの場合も正常に戻ります。分岐には各アイテムの `status` を使ってください。
sentint or null- 「受け付けられた」アイテムの数で、送り出された数とは同じではありません。アイテムが `ok` でも、その `email` の `status` が `failed` や `partial` のことがあります。行が作られた後にトランスポートがメッセージを拒否するのは配信の結果であって、リクエストの拒否ではないからです。応答に件数が含まれていなかったときだけ null です。
failedint or null- `error` を持つアイテムの数。0 より大きければ、バッチを再送する理由ではなく、対処すべき一覧です。受け付けられたメッセージはすでに送られています。
各アイテム
indexint- このアイテムのメッセージが、送ったリストの中で占めていた位置。順序としてだけでなくキーとしても保持されるため、`items` を絞り込んだり並べ替えたりするコードでも、どのメッセージが失敗したかが分かります。
statusstring- `ok` または `error`。`ok` には `email` が、`error` には `error` が含まれ、両方を持つアイテムはありません。
emailarray- 受け付けられたメッセージで、`ok` のアイテムにだけ存在し、単独の送信が返すのと同じ形です。導出された `Idempotency-Key` が既存の送信と一致した場合は `replayed` が true で、新たには何も送信されておらず、これは元のメッセージです。`tracking` キーは含みません。エンゲージメントは後から報告されるもので、受け付けの時点では報告することが何もないからです。
errorarray- このメッセージだけが拒否された理由で、`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` として扱ってください。ここで `code` という名前なのは、これがデコードされたエンベロープだからです。例外では同じ値を `errorCode` として持ちます。
messagestring- 人向けに書かれた 1 文で、問題の値があればそれを名指しします。安定した識別子ではありません。分岐は `code` で行ってください。
paramstring- 拒否されたフィールドを、そのメッセージ内のドット区切りパスで示します。`to.0`、`from`、`attachments` のような形です。フィールドを特定できない失敗では存在せず、バッチ内の位置が前置されることはありません。そちらは `index` の役目です。