ドキュメント本文へスキップ
PHP

一斉配信

`broadcasts->preview`、`send`、`list`、`listAll`、`iterate`、`get`、`listRecipients`、`listAllRecipients`、`iterateRecipients`、`getRecipient`、`stats`、`analytics`、`cancel`。

すべてのメソッド

broadcasts.php
use OpenEmail\Constants\BroadcastRecipientFilters;use OpenEmail\Constants\BroadcastStatuses; $draft = [    'audienceIds' => ['aud_4c1b8e2a7d9f05c36b4e8a71'],    'from' => 'Acme <[email protected]>',    'subject' => '{{firstName|Hello}}, the September release is out',    'html' => '<p>Hi {{firstName|there}},</p><p>Here is what changed this month.</p>',    'text' => 'Hi {{firstName|there}}, here is what changed this month. Unsubscribe: {{unsubscribeUrl}}',    'tags' => ['campaign' => 'release-2026-09'],]; $reach = $client->broadcasts->preview($draft);echo $reach['recipients'], ' ', $reach['unsubscribed'], ' ', $reach['suppressed'], PHP_EOL; $broadcast = $client->broadcasts->send($draft); $latest = $client->broadcasts->get($broadcast['id']); while (in_array($latest['status'], [BroadcastStatuses::SCHEDULED, BroadcastStatuses::QUEUED, BroadcastStatuses::SENDING], true)) {    sleep(5);    $latest = $client->broadcasts->get($broadcast['id']);} foreach ($client->broadcasts->iterateRecipients($broadcast['id']) as $copy) {    echo $copy['email'], ' ', $copy['status'], ' ', $copy['opens'], ' ', $copy['clicks'], PHP_EOL;} $bounced = $client->broadcasts->listRecipients($broadcast['id'], filter: BroadcastRecipientFilters::BOUNCED); foreach ($bounced as $row) {    echo $row['emailId'], ' ', $row['email'], PHP_EOL;} $copy = $client->broadcasts->getRecipient($broadcast['id'], 'msg_01dad25067bc4dac966d515d');echo $copy['subject'], ' ', $copy['bouncedAt'] ?? 'not bounced', PHP_EOL; $stats = $client->broadcasts->stats($broadcast['id'], grain: 'day');echo $stats['totals']['opened'], ' ', $stats['totals']['clicked'], ' ', $stats['totals']['unsubscribed'], PHP_EOL; $lately = $client->broadcasts->stats($broadcast['id'], days: 1);echo $lately['window']['opened'] ?? 0, PHP_EOL; $later = $client->broadcasts->send([...$draft, 'scheduledAt' => 'P1D']);$client->broadcasts->cancel($later['id']); $history = $client->broadcasts->list(audienceId: $draft['audienceIds'][0]);echo $latest['status'], ' ', $latest['counts']['sent'], ' ', count($history), PHP_EOL; $month = $client->broadcasts->analytics(days: 30); foreach ($month['broadcasts'] as $row) {    echo $row['subject'], ' ', $row['sent'], ' ', $row['opened'], PHP_EOL;}

一斉配信は、1 つ以上のオーディエンス内の全員に 1 通のメッセージを、一人ずつ別のコピーとして送ります。各コピーの受信者はちょうど一人で cc も bcc もないため、他に誰に送られたかは誰にも見えず、各コピーは独自の msg_ ID、イベント、トラッキング、Webhook を持つ普通のメールです。listRecipients で、それぞれがどうなったかとあわせて一覧できます。一斉配信そのものが記録なので、コピーは「送信済み」フォルダに保存されません。

send はすぐに queued の一斉配信を返し、ボディに scheduledAt がある場合は scheduled で返します。送信はバックグラウンドで続きます。send には emails:send と audiences:read、preview には audiences:read が必要です。list、listAll、iterate、get、listRecipients、listAllRecipients、iterateRecipients、getRecipient、stats、analytics には emails:read、cancel には emails:send が必要です。

どの send にも Idempotency-Key が付きます。idempotencyKey: で指定したもの、またはクライアントが作ったものです。そのため、ネットワーク障害後のリトライは、2 回送るのではなく、最初の試行が作った一斉配信を replayed が true の状態で返します。preview、get、cancel とすべての読み取りは安全に繰り返せ、リトライされます。

schedule_broadcast.php
$broadcast = $client->broadcasts->send([    'audienceIds' => ['aud_4c1b8e2a7d9f05c36b4e8a71'],    'from' => 'Acme <[email protected]>',    'subject' => 'Doors open on Friday',    'text' => 'Hi {{firstName|there}}, doors open at nine. Unsubscribe: {{unsubscribeUrl}}',    'scheduledAt' => new \DateTimeImmutable('+1 hour'),], idempotencyKey: 'doors-open-2026-10'); echo $broadcast['id'], ' ', $broadcast['status'], ' ', $broadcast['replayed'] ? 'replayed' : 'new', PHP_EOL;

一斉配信のフィールドは、API の camelCase の名前(audienceIds、scheduledAt)をキーとする 1 つの配列です。idempotencyKey: と apiKey: は呼び出しの名前付き引数で、フィールドとして送られることはありません。下書きをフィールドと並べて新しい配列に展開すると、その 1 か所だけを変えた同じ下書きが送られます。そのため send([...$draft, 'scheduledAt' => 'P1D']) は 1 日後に送ります。scheduledAt は DateTimeInterface、ISO 8601 の文字列、または PT2H のような期間を受け取り、DateTimeInterface は UTC の時刻として送られます。preview は渡されたものから audienceIds だけを送るため、send と同じ配列を受け取れます。レスポンスは camelCase のキーを持つ配列なので、$broadcast['status'] でステータスを読めます。

差し込み項目

subject、html、text は一人ひとりの連絡先から埋められます。{{firstName}} は連絡先の名前の最初の語、{{lastName}} は残り、{{name}} は名前全体、{{email}} はコピーの送り先アドレス、{{unsubscribeUrl}} はその人を配信停止にするリンクです。

各項目はバーの後に代替値を取り、連絡先に値がないときに使われるので、名前なしで保存された連絡先では {{firstName|there}} が "there" になります。html では値がエスケープされ、他の {{…}} は書かれたとおりに残ります。

保存済みのテンプレートを送るには、html と text の代わりに template を、id と省略可能な version、props、slots を持つ配列として渡します。同じ 5 つの値がプロパティとして渡されますが、テンプレートが宣言しているものに限られるので、firstName を宣言しているテンプレートはそれを受け取り、宣言していないテンプレートがそのせいで拒否されることはありません。props の内容はすべてのコピーに同じように入ります。

配信停止

どのコピーにもワンクリック配信停止ヘッダーが付き、メールクライアントが独自の配信停止ボタンを表示できます。これは大手のメールボックス事業者が一括メールに求めているものです。{{unsubscribeUrl}} を自分で置いていない html または text の本文には、リンク付きの 1 行のフッターが付きます。テンプレートはそのまま送られるので、テンプレートに {{unsubscribeUrl}} を入れてください。

配信停止すると、その一斉配信が送られたすべてのオーディエンスでその人が配信停止として記録され、オーディエンスのページで説明しているとおり、audiences->listContacts がその人の行の unsubscribedAt でそれを示します。その人はオーディエンスとアドレス帳に残り、他のオーディエンスには影響せず、1 通ずつ送るメールは引き続き届きます。オーディエンスから外して追加し直すと、改めて購読状態になります。

スキップされる人

一斉配信は audienceIds のうち少なくとも 1 つに入っているすべての連絡先に、いくつに入っていても 1 回だけ届きます。スキップされるのは、それらのオーディエンスのうち自分が入っているすべてで配信停止した連絡先と、バウンスや苦情のため、あるいは誰かが追加したために抑止リストにあるアドレスです。send の後、送信が届く前にオーディエンスに追加された連絡先には届きます。

preview は何も送らずに同じ数、recipients、unsubscribed、suppressed を返します。誰にも届かない send は 422 no_recipients を ValidationException としてスローします。

何かを書き込む前に送信全体がプランの月間送信数と照合されるので、割り当てで賄えない一斉配信は 429 send_quota_exceeded を RateLimitException としてスローし、何も残しません。コピー 1 通が 1 回の送信として数えられます。

状態と進み具合

get はコピーから counts を直接読むので、一斉配信の送信中は、上のサンプルのように呼び出しの間に sleep() を挟んでこれをポーリングしてください。status は scheduled または queued から sending に進み、渡したすべてのコピーが送られたか失敗すると sent で落ち着きます。completedAt が最後の人に届いたことを示した後でも、送信待ちのコピーがある間は sending のままです。failed は一斉配信全体が止まったことを意味し、lastError が理由を示します:from アドレスから送信できなくなった、テンプレートが解決できなくなった、途中でプランが尽きた、送信自体が失敗し続けた、またはコピーを 1 通も書き込めなかった、のいずれかです。

cancel は scheduled、queued、sending の一斉配信を止めます。新たに誰も追加されず、送信待ちのコピーはすべてキャンセルされますが、送られたコピーは取り消せません。すべてのコピーが送られた後の cancel は 409 broadcast_not_cancellable を ConflictException としてスローし、キャンセル済みの一斉配信をキャンセルするとその時点の状態で返します。

届いた相手

listRecipients は、一斉配信の宛先となった人たちを、コピーごとに 1 行、アドレス順に並べた OpenEmail\Result\Page を 1 つ、items、hasMore、nextCursor 付きで返します。listAllRecipients はすべてのページをたどって 1 つの配列にまとめ、iterateRecipients はコピーを 1 通ずつ yield し、ループが求めたときにだけ次のページを取得する Generator を返します。limit: は 1〜200 で既定は 50、cursor: は同じ filter: と q: とともに渡し返します。

`filter:`残すもの
pendingまだキューにある、予約済み、または送信中のコピー。
sent送信されたコピー。
delivered受信側サーバーが受け付けたコピー。
opened1 回以上開封されたコピー。
not_opened送信済みで一度も開封されていないコピー。
clickedトラッキング対象のクリックが 1 回以上あったコピー。
bouncedバウンスしたコピー。
complained受信者がスパムとして報告したコピー。
failed失敗またはキャンセルされたコピー。
unsubscribed一斉配信の送信後に登録解除した人。

OpenEmail\Constants\BroadcastRecipientFilters が各フィルターを定義し、q: はアドレスと名前を大文字と小文字を区別せずに検索します。開封とクリックには画像プロキシとリンクスキャナーによるものは含まれず、トラッキングをオフにして送信した一斉配信では 0 のままです。

getRecipient($id, $emailId) はコピーを 1 通返します。同じ行に加え、その人が受け取ったとおりの subject、html、text を、差し込み項目を埋め、その人専用の配信停止リンクを付けた状態で含みます。行の emailId を第 2 引数として渡してください。HTML は開封とクリックのトラッキングを追加する前のものです。この一斉配信のコピーではない emailId は 404 recipient_not_found を、存在しない一斉配信は 404 broadcast_not_found を、どちらも NotFoundException としてスローします。

stats は合計と系列を返します。totals は sent、delivered、bounced、complained、failed のコピー数と、まだ待機中のものを表す pending、そして opened、clicked、unsubscribed した人数を数え、opens と clicks をイベント数として持ちます。series は疎で古い順で、何かが起きた grain:(minute、hour、day、既定は hour)ごとに 1 つのバケットがあり、UTC から東へ offsetMinutes: 分ずらしたタイムゾーンで区切られます。ローカルのタイムゾーンには intdiv((int) date('Z'), 60) を渡してください。各人はそれが初めて起きた時点で 1 回だけ数えられるため、合計と一致します。

最近起きたことも読むには、stats に days: または minutes: を渡します。すると window がその期間内の配信、バウンス、迷惑メール報告、開封、クリック、配信停止を数え、series はその期間のバケットだけを残します。totals は引き続き一斉配信全体を対象とします。どちらも指定しなければ window は null です。

特定のアドレスやドメインに限定されたキーが届くのは、自分が持つアドレスやドメインから送られた一斉配信だけです。list、listAll、iterate はそれ以外を除外し、get、受信者系のメソッド、stats、cancel はそれらに対して 404 broadcast_not_found をスローします。

レスポンス:一斉配信

send、get、cancel はそれぞれこれを camelCase のキーを持つ配列として 1 つ返し、send は replayed を加えます。list はこれらの OpenEmail\Result\Page を新しい順で返し、listAll はすべてを 1 つの配列で返し、iterate はそれらをたどる Generator を返します。preview は audienceIds、recipients、unsubscribed、suppressed を持つ配列を返します。listRecipients は受信者の行の Page を返し、getRecipient は内容付きの行を 1 つ返し、stats は broadcastId、grain、totals、window、series を持つ配列を返します。analytics は totals、series と、broadcasts に一斉配信ごとに 1 行を持つ配列を返します。時刻は ISO 8601 の文字列で、new \DateTimeImmutable() で読めます。

idstring
永続的な識別子で、`brd_` に 16 進 24 文字が続きます。
statusstring
`scheduled`、`queued`、`sending`、`sent`、`cancelled`、`failed` のいずれか。`OpenEmail\Constants\BroadcastStatuses` がそれぞれを定義しています。
modestring
作成したキーに応じて `live` または `test`。テスト一斉配信のコピーは送信済みとして記録され、誰にも配信されません。
sourcestring
開始された場所。キーなら `api`、接続されたアプリなら `oauth`、アプリなら `composer`、アシスタントなら `mcp` です。
audienceIdsarray
送り先のオーディエンス。それぞれ 1 回ずつです。
fromstring
すべてのコピーの送信元アドレス。
subjectstring
書かれたとおりの件名で、差し込み項目もそのままです。テンプレートが件名を用意する場合は空です。
countsarray
`recipients` は `send` 時の見積もりです。`created` は書き込まれたコピーの数、`skipped` はその時点でアドレスが抑止されていたために飛ばされた人の数、`failedToQueue` はコピーを書き込めなかった人の数です。`queued`、`sending`、`sent`、`failed`、`cancelled` は、各コピーの現在の状態ごとの数です。
lastErrorstring or null
一斉配信が失敗した理由、または書き込めなかった最新のコピーとその理由。問題がない間は null です。
scheduledAtstring or null
ISO-8601 の UTC で、送信が始まる予定の日時。すぐに送った一斉配信では null です。
startedAtstring or null
ISO-8601 UTC で、送信が最初の人たちに届いた日時。
completedAtstring or null
ISO-8601 UTC で、最後の人に届いた日時。その後もコピーが送信待ちのことがあります。
cancelledAtstring or null
ISO-8601 UTC で、`cancel` が止めた日時。
createdAtstring
ISO-8601 UTC で、`send` が呼ばれた日時。一覧の順序を決めます。
updatedAtstring
ISO-8601 UTC で、送信が進むにつれて更新されます。

レスポンス:受信者の行

listRecipients、listAllRecipients、iterateRecipients の各行で、camelCase のキーを持つ配列です。getRecipient が返す配列は subject、html、text を加えたものです。

emailIdstring
この人のコピーの `msg_` id。`getRecipient` は内容とともにそれを読み、`emails->get` は、一覧と取得のページで説明しているとおり、送信済みメールとして読みます。
contactIdstring or null
送信先の連絡先。その後に連絡先が削除された場合は null。
emailstring
コピーの送信先アドレス。
namestring or null
連絡先の名前。
statusstring
コピーの状態: `queued`、`scheduled`、`sending`、`sent`、`failed`、`cancelled` のいずれか。
sentAtstring or null
ISO-8601 UTC、コピーが送信された日時。
deliveredAtstring or null
ISO-8601 UTC、受信側サーバーが受け付けた日時。最初の `email.delivered` です。
bouncedAtstring or null
ISO-8601 UTC、バウンスした日時。最初の `email.bounced` です。
complainedAtstring or null
ISO-8601 UTC、受信者がスパムとして報告した日時。最初の `email.complained` です。
failurestring or null
コピーが失敗した場合の、その理由。
opensint
記録された開封数。画像プロキシとスキャナーによるものは除きます。トラッキングがオフだった場合は 0。
firstOpenAtstring or null
ISO-8601 UTC、最初の開封。
clicksint
トラッキング対象のリンクで記録されたクリック数。スキャナーによるものは除きます。
firstClickAtstring or null
ISO-8601 UTC、最初のクリック。
unsubscribedAtstring or null
ISO-8601 の UTC で、送信後にこの人が一斉配信のオーディエンスのいずれかから、そのリンク経由またはその他の方法で配信停止した日時。