Sign inGet Started

Envoi programmé

Définissez scheduled_at pour retenir un message jusqu'à une heure précise. Lorsque cette heure arrive, le message entre dans le cycle de livraison normal et produit les mêmes événements qu'un envoi immédiat. Votre application n'a pas besoin de gérer son propre planificateur.

Programmer un envoi

Ajoutez un horodatage scheduled_at à un envoi POST /v1/email/messages normal. Rien d'autre ne change dans le payload.

const msg = await bird.email.send({
  from: "news@yourdomain.com",
  to: ["delivered@messagebird.dev"],
  subject: "Your weekly digest",
  html: '<p>Here is what happened this week...</p><p><a href="{{ bird.unsubscribe_url }}">Unsubscribe</a></p>',
  category: "marketing",
  scheduled_at: "2027-01-15T09:00:00Z",
});
console.log(msg.id, msg.status); // "em_…", "accepted"

L'appel renvoie immédiatement 202 Accepted avec l'ID de message préfixé par em_ et status: accepted. C'est le même objet message qu'un envoi immédiat renvoie, plus scheduled_at renvoyé en UTC, ce qui vous permet de confirmer l'heure d'envoi sans lecture supplémentaire. L'acceptation est synchrone ; la livraison est différée. Omettez scheduled_at de la requête et le message part tout de suite ; sa réponse ne contient alors pas de clé scheduled_at.

Les lectures sont mises à jour de manière asynchrone. Un message que vous venez de programmer peut d'abord renvoyer 404 via Récupérer un message et ne pas apparaître dans la liste des messages ni dans le tableau de bord. Un contenu volumineux ou des pièces jointes peuvent prolonger cette attente pendant leur stockage. Conservez l'ID et scheduled_at de la réponse 202, puis réessayez les lectures avec cet ID en espaçant les tentatives. Vous pouvez aussi annuler avec cet ID avant que le message apparaisse.

Lorsqu'un message apparaît alors qu'il attend encore son envoi, les lectures affichent status: scheduled et son scheduled_at :

Exemple de code
{
  "id": "em_01ky7q24hafjgvzfg02v3m177p",
  "status": "scheduled",
  "scheduled_at": "2027-01-15T09:00:00Z",
  "category": "marketing"
}

Lorsque l'heure arrive, nous libérons le message et son statut progresse à travers les états habituels (accepted, puis processed, puis delivered, etc.). scheduled_at reste défini après coup, ce qui vous permet de toujours voir pour quand un message était programmé.

L'envoi d'un message peut commencer avant la mise à jour des lectures. Vous pouvez donc voir d'abord un état ultérieur. Aucun délai fixe ne garantit qu'une lecture affichera ensuite le message.

La programmation consomme une unité de l'enveloppe d'e-mails programmés de votre organisation pour la période de facturation. Dépasser cette enveloppe est rejeté avec un 422 (E10003).

Programmer du contenu inline ou un modèle

Utilisez scheduled_at avec du contenu inline ou un modèle enregistré, construit comme un envoi avec modèle immédiat. Nous fixons la version publiée, la langue sélectionnée et les valeurs des paramètres lors de l’acceptation de la requête et envoyons cette version à l’heure planifiée. La publication d’une version plus récente ne change pas cette sélection. Si le modèle est supprimé avant l’heure planifiée, le message est rejeté sans être envoyé.

Un message de catégorie marketing reçoit un lien de désinscription sous forme de petit pied de page à la fin de son corps. Pour placer le lien vous-même, insérez {{ bird.unsubscribe_url }} dans chaque corps que vous fournissez ou, pour un envoi avec modèle, dans les corps du modèle.

Un élément de batch accepte scheduled_at aux mêmes conditions, ce qui permet à un batch de mélanger messages programmés et immédiats. Chaque élément programmé consomme sa propre unité de l'enveloppe, et le batch entier est rejeté si l'heure d'un élément est hors de la plage autorisée. Chaque élément programmé porte son propre scheduled_at dans la réponse du batch, et un élément envoyé immédiatement n'a pas de clé scheduled_at ; la référence batch montre les deux dans une même réponse.

Un payload d'envoi immédiat peut tout de même être trop volumineux pour être programmé. Si son corps, sa liste de destinataires ou ses métadonnées dépassent la limite de programmation, API renvoie 422. Réduisez ces champs ou envoyez le message immédiatement.

Choisir l'heure d'envoi

scheduled_at est un horodatage absolu RFC 3339. Deux règles le gouvernent :

  • L'heure doit se situer entre 30 secondes et 30 jours dans le futur. Moins de 30 secondes ou plus de 30 jours est rejeté avec un 422. Le seuil minimal empêche un envoi programmé d'entrer en concurrence avec un envoi immédiat. Trente jours est l'horizon le plus lointain pour lequel nous retenons un message.
  • Fournissez un instant exact. Incluez un suffixe UTC Z (2027-01-15T09:00:00Z) ou un décalage explicite (2026-07-30T09:00:00-04:00, le même instant que 13:00:00Z). Nous comparons l'instant à l'heure courante et n'interprétons jamais une heure locale brute ni n'appliquons le fuseau horaire du destinataire. Pour envoyer à 9 h dans l'heure locale de chaque destinataire, calculez vous-même ces instants et programmez un envoi par fuseau horaire.

Les expressions relatives comme "in 2 hours" ne sont pas acceptées. Envoyez un horodatage résolu.

Lister les messages programmés

Filtrez la liste des messages par état pour voir les messages déjà visibles qui attendent encore leur envoi. Un envoi programmé qui vient d'être accepté peut être absent pendant le chargement de son contenu ou la mise à jour des lectures :

for await (const message of bird.email.list({ status: "scheduled" })) {
  console.log(message.id, message.scheduled_at);
}

status=canceled liste ceux que vous avez annulés avant leur envoi. Une fois qu'un message programmé est déclenché, il entre dans le pipeline et apparaît avec les statuts de livraison, comme tout autre envoi. Le journal des e-mails du tableau de bord propose les mêmes filtres Scheduled et Canceled.

Annuler un envoi programmé

Annulez un message à tout moment avant qu'il ne commence à partir avec POST /v1/email/messages/{message_id}/cancel :

await bird.email.cancel("em_abc123");

Une annulation réussie renvoie 204 No Content. Le statut du message devient canceled, il n'est jamais envoyé, et un webhook email.canceled se déclenche. Quatre points à retenir :

  • Seul un message encore programmé peut être annulé. Un message dont l'envoi a déjà commencé, qui a déjà été envoyé ou déjà annulé renvoie 409 :

    Exemple de code
    {
      "error": {
        "type": "conflict_error",
        "code": "E10005",
        "name": "EmailNotCancelable",
        "message": "This message cannot be canceled.",
        "remediation": "Only a scheduled message that has not started sending can be canceled. Once sending begins there is no way to pull it back."
      }
    }

    À l'approche de l'heure d'envoi, une annulation peut aussi perdre la course face à l'envoi lui-même et renvoyer 409 pour la même raison.

  • Vous pouvez annuler pendant le téléversement du contenu. Un envoi programmé avec des pièces jointes ou un corps volumineux peut encore être en cours de stockage après la réponse 202. Une annulation réussie reste effective même si le téléversement se termine ensuite.

  • L'annulation ne restitue pas l'enveloppe d'e-mails programmés. L'unité consommée au moment de la programmation reste consommée, ce qui empêche une boucle programmer-puis-annuler de contourner l'enveloppe. Votre enveloppe d'envoi normale n'est pas affectée, car elle n'est débitée que lorsqu'un message part effectivement.

  • L'annulation peut être réessayée en toute sécurité avec un Idempotency-Key, comme toute autre écriture.

Pour déplacer un envoi programmé à une autre heure, annulez-le et soumettez un nouvel envoi avec le nouveau scheduled_at. Vous obtenez un nouvel ID em_.

Ce qui se passe à l'heure d'envoi

La programmation ne change que le moment où un message est libéré. Sa construction et sa gouvernance restent identiques. Les pièces jointes, la catégorie, les tags et métadonnées se comportent exactement comme lors d'un envoi immédiat et sont renvoyés de la même façon sur les événements webhook. Cinq vérifications se répartissent entre les deux moments :

  • La validation du payload et du domaine s'effectue en amont. Un envoi programmé malformé échoue lors de l'appel API avec un 422, ce qui vous informe tout de suite plutôt qu'à 9 h.
  • Le domaine de l'expéditeur est revérifié à l'heure d'envoi. Si votre domaine from n'est plus vérifié lorsque l'heure programmée arrive, le message n'est pas envoyé. Ses destinataires sont renvoyés en tant que rejected avec une raison, au lieu de recevoir un e-mail d'un domaine non vérifié. Maintenez le domaine vérifié pendant toute la fenêtre.
  • Votre enveloppe d'envoi est débitée à l'heure d'envoi. Le quota d'envoi normal est consommé lorsque le message part. La programmation laisse le quota inchangé. Si l'enveloppe est épuisée à l'heure d'envoi, les destinataires sont rejetés.
  • La suppression est évaluée à l'heure d'envoi, par rapport à votre liste de suppression telle qu'elle est à ce moment-là. Ainsi, une personne qui se désinscrit entre la programmation et l'envoi est bien prise en compte.
  • Un modèle enregistré doit toujours exister à l'heure d'envoi. Si vous supprimez le modèle après la programmation, le message n'est pas envoyé. Ses destinataires sont renvoyés en tant que rejected avec generation_failure.

Erreurs

StatutCodeQuand
422E10003L'enveloppe d'e-mails programmés de votre organisation pour la période de facturation est épuisée
422scheduled_at est à moins de 30 secondes ou à plus de 30 jours
422Le payload est trop volumineux pour être mis en attente ; réduisez le corps, les destinataires ou les métadonnées, ou envoyez maintenant
409E10005Le message ne peut plus être annulé : son envoi a déjà commencé, il a été envoyé ou a été annulé
404La lecture du message ne reflète pas encore son acceptation, ou aucun message portant cet ID n'existe dans cet espace de travail

Webhooks

Deux événements sont propres à la programmation, en plus des événements de livraison habituels :

  • email.scheduled signale un message en attente de l'heure future indiquée par scheduled_at. Pour les envois utilisant un modèle, la version sélectionnée est chargée à nouveau et son contenu est préparé au moment de l'envoi. Cet événement peut arriver avant la fin de cette préparation.
  • email.canceled se déclenche lorsqu'un message programmé est annulé avant son envoi.

Lorsque le message part, la chaîne email.accepted normale suit sans changement.

Les événements de programmation sont publiés de manière asynchrone. Un message peut quitter l'état programmé avant la publication de email.scheduled. La réception d'un webhook ne signifie pas que les endpoints de lecture affichent déjà cet état.

Étapes suivantes

Poursuivez avec la documentation, les guides et les exemples sur ce sujet.