Aller à la documentation
PHP

Diffusions

`broadcasts->preview`, `send`, `list`, `listAll`, `iterate`, `get`, `listRecipients`, `listAllRecipients`, `iterateRecipients`, `getRecipient`, `stats`, `analytics` et `cancel`.

Toutes les méthodes

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;}

Une diffusion envoie un message à tous les membres d'une ou plusieurs audiences, sous forme de copie distincte pour chaque personne. Chaque copie a exactement un destinataire et ni cc ni bcc, si bien que personne ne voit à qui d'autre elle est partie, et chaque copie est un e-mail ordinaire avec son propre identifiant msg_, ses événements, son suivi et ses webhooks. listRecipients les liste avec ce qu'il est advenu de chacune. Les copies ne sont pas classées dans le dossier Envoyés, car la diffusion en fait foi.

send retourne immédiatement avec la diffusion en queued, ou en scheduled quand le corps porte scheduledAt, et l'envoi s'exécute en arrière-plan. send exige emails:send et audiences:read, et preview exige audiences:read. list, listAll, iterate, get, listRecipients, listAllRecipients, iterateRecipients, getRecipient, stats et analytics exigent emails:read, et cancel exige emails:send.

Chaque send porte un Idempotency-Key, le vôtre via idempotencyKey: ou un que génère le client : un réessai après un échec réseau répond donc avec la diffusion créée par la première tentative, avec replayed à true, au lieu d'envoyer deux fois. preview, get, cancel et toutes les lectures peuvent être répétés sans risque et sont réessayés.

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;

Les champs d'une diffusion sont les clés d'un tableau aux noms en camelCase de l'API (audienceIds, scheduledAt). idempotencyKey: et apiKey: sont des arguments nommés de l'appel et ne sont jamais envoyés comme champs. Décompresser un brouillon dans un nouveau tableau à côté d'un champ envoie le même brouillon avec ce seul changement : send([...$draft, 'scheduledAt' => 'P1D']) l'envoie donc un jour plus tard. scheduledAt prend un DateTimeInterface, une chaîne ISO 8601 ou une durée comme PT2H, et un DateTimeInterface part comme un instant UTC. preview n'envoie que audienceIds de ce que vous lui donnez : il prend donc le même tableau que send. Une réponse est un tableau à clés en camelCase : $broadcast['status'] lit donc le statut.

Champs de fusion

subject, html et text sont remplis pour chaque personne à partir de son contact. {{firstName}} est le premier mot du nom du contact, {{lastName}} le reste, {{name}} le nom complet, {{email}} l'adresse à laquelle part la copie et {{unsubscribeUrl}} le lien qui la désabonne.

Chaque champ accepte une valeur de repli après une barre, utilisée quand le contact n'a pas de valeur pour lui : {{firstName|there}} devient donc "there" pour un contact enregistré sans nom. Les valeurs sont échappées dans html, et tout autre {{…}} est laissé exactement tel qu'il est écrit.

Passez template au lieu de html et text pour envoyer un modèle stocké, sous forme de tableau avec id et optionnellement version, props et slots. Les cinq mêmes valeurs lui parviennent comme props, mais seulement les props que le modèle déclare : un modèle qui déclare firstName le reçoit, et un modèle qui ne le déclare pas n'est jamais refusé pour autant. Tout ce qui se trouve dans ses props va à chaque copie à l'identique.

Désabonnement

Chaque copie porte les en-têtes de désabonnement en un clic qui permettent à un client de messagerie d'afficher son propre bouton de désabonnement, ce que les grands fournisseurs de boîtes exigent du courrier en masse. Un corps html ou text qui ne place pas {{unsubscribeUrl}} lui-même reçoit un pied de page d'une ligne avec le lien. Un modèle est envoyé exactement tel quel : mettez donc {{unsubscribeUrl}} dans le modèle.

Le désabonnement marque la personne comme désabonnée dans chaque audience à laquelle cette diffusion a été envoyée, et audiences->listContacts l'indique dans le unsubscribedAt de sa ligne, comme le décrit la page Audiences. Elle reste dans l'audience et dans le carnet d'adresses, ses autres audiences ne sont pas touchées, et le courrier qui lui est envoyé un message à la fois part toujours. La retirer de l'audience puis l'y rajouter la réabonne.

Qui est ignoré

Une diffusion atteint chaque contact d'au moins une des audienceIds, une fois quel que soit le nombre d'audiences qui le contiennent. Elle ignore le contact qui s'est désabonné de chacune de ces audiences dont il fait partie, et l'adresse figurant sur la liste de suppression après un rebond ou une plainte, ou parce que quelqu'un l'y a ajoutée. Un contact ajouté à l'une des audiences après send, mais avant que l'envoi ne l'atteigne, est inclus.

preview renvoie les mêmes chiffres sans envoyer : recipients, unsubscribed et suppressed. Un send qui n'atteindrait personne lève un 422 no_recipients sous la forme d'une ValidationException.

L'envoi entier est confronté aux envois mensuels du forfait avant que quoi que ce soit ne soit écrit : une diffusion que le quota ne peut pas couvrir lève donc un 429 send_quota_exceeded sous la forme d'une RateLimitException et ne laisse rien derrière elle. Chaque copie compte comme un envoi.

Statut et avancement

get lit counts en direct à partir des copies : interrogez-le donc régulièrement pendant l'envoi d'une diffusion, avec sleep() entre les appels comme le fait l'exemple ci-dessus. status passe de scheduled ou queued à sending et s'arrête sur sent une fois que chaque copie transmise est partie ou a échoué. Il reste à sending tant que des copies attendent encore, même après que completedAt indique que la dernière personne a été atteinte. failed signifie que toute la diffusion s'est arrêtée, et lastError dit pourquoi : l'adresse from ne peut plus servir à envoyer, le modèle a cessé de se résoudre, le forfait s'est épuisé en cours de route, l'envoi lui-même a échoué à répétition, ou pas une seule copie n'a pu être écrite.

cancel arrête une diffusion qui est scheduled, queued ou sending. Plus personne n'est ajouté et chaque copie encore en attente est annulée, tandis que les copies parties ne peuvent pas être rappelées. Une fois toutes les copies parties, cancel lève un 409 broadcast_not_cancellable sous la forme d'une ConflictException, et annuler une diffusion déjà annulée la renvoie telle quelle.

Qui elle a atteint

listRecipients renvoie une OpenEmail\Result\Page des personnes auxquelles une diffusion a été envoyée, une ligne par copie, triées par adresse, avec items, hasMore et nextCursor. listAllRecipients parcourt toutes les pages dans un seul tableau, et iterateRecipients renvoie un Generator qui fournit les copies une par une et ne récupère la page suivante que lorsque la boucle la demande. limit: va de 1 à 200, 50 par défaut, et un cursor: se renvoie avec les mêmes filter: et q:.

`filter:`Garde
pendingCopies encore en file d'attente, programmées ou en cours d'envoi.
sentCopies parties.
deliveredCopies acceptées par le serveur destinataire.
openedCopies ouvertes au moins une fois.
not_openedCopies envoyées et jamais ouvertes.
clickedCopies avec au moins un clic suivi.
bouncedCopies qui ont rebondi.
complainedCopies que la personne a signalées comme spam.
failedCopies échouées ou annulées.
unsubscribedPersonnes qui se sont désabonnées après le départ de la diffusion.

OpenEmail\Constants\BroadcastRecipientFilters nomme chaque filtre, et q: cherche dans l'adresse et le nom, sans tenir compte de la casse. Les ouvertures et les clics excluent les proxys d'images et les scanners de liens, et restent à 0 quand la diffusion est partie avec le suivi désactivé.

getRecipient($id, $emailId) renvoie une copie : la même ligne, plus subject, html et text exactement tels que cette personne les a reçus, avec les champs de fusion remplis et son propre lien de désabonnement. Passez l'emailId d'une ligne comme deuxième argument. Le HTML est celui d'avant l'ajout du suivi des ouvertures et des clics. Un emailId qui n'est pas une copie de cette diffusion lève un 404 recipient_not_found, et une diffusion inconnue un 404 broadcast_not_found, tous deux sous la forme d'une NotFoundException.

stats renvoie les totaux et une série. totals compte les copies sent, delivered, bounced, complained et failed, avec pending pour celles qui attendent encore, et les personnes qui ont opened, clicked et unsubscribed, avec opens et clicks comme nombres d'événements. series est clairsemée et commence par la plus ancienne, un intervalle par grain: (minute, hour ou day, hour par défaut) dans lequel il s'est passé quelque chose, découpé dans le fuseau situé offsetMinutes: à l'est d'UTC. Passez intdiv((int) date('Z'), 60) pour le fuseau local. Elle compte chaque personne une fois, la première fois où l'événement lui est arrivé : elle s'additionne donc pour donner les totaux.

Passez days: ou minutes: à stats pour lire aussi ce qui s'est passé récemment. window compte alors ce qui a été livré, a rebondi, a été signalé comme spam, ouvert, cliqué et désabonné dans cette fenêtre, et series ne garde que ses intervalles, tandis que totals couvre toujours toute la diffusion. Sans l'un ni l'autre, window vaut null.

Une clé limitée à certaines adresses ou certains domaines n'atteint que les diffusions envoyées depuis une adresse ou un domaine qu'elle détient. list, listAll et iterate omettent les autres, et get, les méthodes de destinataires, stats et cancel lèvent pour elles un 404 broadcast_not_found.

Réponse : une diffusion

send, get et cancel en renvoient chacun une, sous forme de tableau à clés en camelCase, et send ajoute replayed. list en renvoie une OpenEmail\Result\Page, de la plus récente à la plus ancienne, listAll les renvoie toutes dans un tableau et iterate renvoie un Generator qui les parcourt. preview renvoie un tableau avec audienceIds, recipients, unsubscribed et suppressed. listRecipients renvoie une Page de lignes de destinataires, getRecipient une ligne avec son contenu, et stats un tableau avec broadcastId, grain, totals, window et series. analytics renvoie un tableau avec totals, series et une ligne par diffusion dans broadcasts. Les dates sont des chaînes ISO 8601, que lit new \DateTimeImmutable().

idstring
L'identifiant durable, `brd_` suivi de 24 caractères hexadécimaux.
statusstring
`scheduled`, `queued`, `sending`, `sent`, `cancelled` ou `failed`. `OpenEmail\Constants\BroadcastStatuses` nomme chacun d'eux.
modestring
`live` ou `test`, selon la clé qui l'a créée. Les copies d'une diffusion de test sont marquées envoyées et ne sont remises à personne.
sourcestring
D'où elle a été lancée : `api` pour une clé, `oauth` pour une application connectée, `composer` pour l'application, `mcp` pour un assistant.
audienceIdsarray
Les audiences auxquelles elle est partie, chacune une fois.
fromstring
L'adresse depuis laquelle chaque copie est envoyée.
subjectstring
L'objet tel qu'écrit, champs de fusion compris. Vide quand un modèle fournit l'objet.
countsarray
`recipients` est l'estimation prise au `send`. `created` compte les copies écrites, `skipped` les personnes laissées de côté parce que leur adresse était supprimée à ce moment-là, et `failedToQueue` les personnes dont la copie n'a pas pu être écrite. `queued`, `sending`, `sent`, `failed` et `cancelled` comptent les copies selon l'état où chacune se trouve maintenant.
lastErrorstring or null
Pourquoi la diffusion a échoué, ou la copie la plus récente qui n'a pas pu être écrite et pourquoi. null tant que rien ne s'est mal passé.
scheduledAtstring or null
ISO-8601 UTC, quand l'envoi doit commencer. null pour une diffusion envoyée immédiatement.
startedAtstring or null
ISO-8601 UTC, quand l'envoi a atteint les premières personnes.
completedAtstring or null
ISO-8601 UTC, quand la dernière personne a été atteinte. Des copies peuvent encore attendre de partir après.
cancelledAtstring or null
ISO-8601 UTC, quand `cancel` l'a arrêtée.
createdAtstring
ISO-8601 UTC, quand `send` a été appelé. Fixe l'ordre de la liste.
updatedAtstring
ISO-8601 UTC, mis à jour à mesure que l'envoi avance.

Réponse : une ligne de destinataire

Chaque ligne de listRecipients, listAllRecipients et iterateRecipients, sous forme de tableau à clés en camelCase. Le tableau que renvoie getRecipient ajoute subject, html et text.

emailIdstring
L'id `msg_` de la copie de cette personne. `getRecipient` la lit avec son contenu, et `emails->get` la lit comme un e-mail envoyé, comme le décrit la page Lister et récupérer.
contactIdstring or null
Le contact auquel elle est partie, ou null quand le contact a été supprimé depuis.
emailstring
L'adresse à laquelle la copie est partie.
namestring or null
Le nom du contact.
statusstring
L'état de la copie : `queued`, `scheduled`, `sending`, `sent`, `failed` ou `cancelled`.
sentAtstring or null
ISO-8601 UTC, moment où la copie est partie.
deliveredAtstring or null
ISO-8601 UTC, moment où le serveur destinataire l'a acceptée, le premier `email.delivered`.
bouncedAtstring or null
ISO-8601 UTC, moment où elle a rebondi, le premier `email.bounced`.
complainedAtstring or null
ISO-8601 UTC, moment où la personne l'a signalée comme spam, le premier `email.complained`.
failurestring or null
Pourquoi la copie a échoué, le cas échéant.
opensint
Ouvertures enregistrées, sans celles des proxys d'images et des scanners. 0 quand le suivi était désactivé.
firstOpenAtstring or null
ISO-8601 UTC, la première ouverture.
clicksint
Clics enregistrés sur les liens suivis, sans les scanners.
firstClickAtstring or null
ISO-8601 UTC, le premier clic.
unsubscribedAtstring or null
ISO-8601 UTC, quand cette personne s'est désabonnée de l'une des audiences de la diffusion après son départ, via son lien ou autrement.