Sign inGet Started

Modèles d'e-mail

Un modèle est un objet et un corps d'e-mail que vous enregistrez une fois et envoyez autant de fois que nécessaire. Vous écrivez les parties variables sous forme de placeholders {{ variable }}, publiez le modèle, puis l'envoyez par slug au lieu de coller le même HTML dans chaque appel API. Un modèle appartient à votre espace de travail.
Créez et gérez vos templates dans Email > Templates, via /v1/email/templates, avec le bird CLI, ou via le serveur MCP. Des méthodes typées sont disponibles dans les SDK TypeScript, Python, PHP et Go sous email.templates. Les schémas complets de requête et de réponse se trouvent dans la référence API. Envoyez un template publié via le endpoint d'envoi standard.

Contenu d'un modèle

Chaque modèle possède deux noms, et ils remplissent des rôles différents :
  • slug est le nom par lequel vous envoyez le modèle, par exemple welcome-email. Vous le choisissez à la création du modèle et il ne peut plus être modifié ensuite. Un slug peut contenir des lettres minuscules, des chiffres, des tirets et des underscores, doit commencer et finir par une lettre ou un chiffre, et peut compter jusqu'à 63 caractères. Deux préfixes sont interdits : bird_, réservé à nos modèles intégrés, et emt_, qui est le format utilisé pour les ID de modèles. Le tableau de bord appelle ce champ Alias.
  • name est un libellé d'affichage libre. Il prend par défaut la valeur du slug, et vous pouvez le modifier à tout moment. Rien ne se résout par le nom, donc renommer un modèle pour l'affichage ne casse jamais un envoi.
En complément, un modèle possède un ID emt_ permanent, fixé pour toute sa durée de vie. Il possède aussi une category, soit marketing soit transactional, et une source de création : html, du balisage finalisé que vous fournissez, éventuellement personnalisé avec Liquid. La catégorie et la source sont toutes deux fixées à la création du modèle.
Nous fournissons un catalogue de modèles intégrés, dont les slugs commencent tous par bird_. Un modèle intégré n'appartient à aucun espace de travail, ne peut pas être modifié, et est toujours prêt à être envoyé tel quel. Copiez-en un dans votre espace de travail pour vous l'approprier : il devient alors un modèle ordinaire que vous pouvez modifier. La copie arrive sous forme de brouillon non publié qui hérite de la catégorie, de la source et des paramètres de langue de l'original ; publiez-la avant de l'envoyer.

Brouillons et versions publiées

Chaque modèle possède exactement un brouillon, qui est la copie de travail que vous modifiez. Il possède aussi un nombre quelconque de versions publiées, chacune numérotée (1, 2, 3, etc.) et jamais modifiée une fois créée. Les modifications changent le brouillon sur place. La publication prend un instantané du brouillon actuel, le transforme en version numérotée suivante, et fait de cette version celle utilisée par les envois. Le brouillon lui-même reste modifiable, vous pouvez donc continuer à travailler sur le suivant.
La règle importante pour l'envoi est la suivante : un envoi utilise toujours la version publiée du modèle, et un brouillon n'est jamais envoyé seul. Vous pouvez continuer à modifier le brouillon pendant qu'une version stable continue d'être expédiée, puis publier quand la modification est prête. La publication d'une nouvelle version change ce que les envois suivants rendent. Un envoi déjà accepté n'est pas affecté par une publication ultérieure.
L'onglet Versions du modèle avec une ligne Brouillon et des lignes publiées v3, v2 et v1 affichant leurs dates de création et de publication
Les versions prennent en charge deux actions supplémentaires. Abandonner les modifications du brouillon pour réinitialiser le brouillon à l'état de la version publiée actuelle. Ou restaurer une version antérieure pour qu'une version publiée précédente redevienne celle utilisée par les envois. Vous ne pouvez restaurer qu'une version publiée, jamais le brouillon lui-même. La restauration remplace le brouillon par le contenu de cette version : tout ce qui n'a pas été enregistré dans le brouillon est perdu, et les modifications ultérieures partent de la version restaurée. Une restauration ne crée pas de nouvelle version.
Pour choisir une image existante, vous devez disposer d’un accès en lecture à la bibliothèque multimédia de l’espace de travail. Pour importer, coller ou déposer une nouvelle image, vous devez disposer d’un accès en écriture. Si Insérer une image est désactivé ou si vous ne pouvez pas parcourir la bibliothèque ou importer des images, demandez à un administrateur de l’espace de travail l’autorisation correspondante pour la bibliothèque multimédia. L’autorisation de modifier les modèles ne donne pas à elle seule accès à la bibliothèque multimédia.
Dans le tableau de bord, choisissez Visuel > Insérer une image pour rechercher dans votre bibliothèque multimédia ou importer une image PNG, JPEG, GIF ou WebP de 5 Mo maximum. Les images WebP statiques sont converties en PNG ou JPEG. Sélectionnez l’image pour définir sa Description de l’image, sa largeur d’affichage, son alignement et son lien. Activez Image décorative uniquement si l’image n’apporte aucune information ; une image liée doit avoir une description qui explique sa destination. Chaque langue conserve ses propres descriptions d’images et sa mise en page.
Utilisez Remplacer l’image pour changer l’image sélectionnée tout en conservant sa description, son lien, sa largeur et son alignement. Vous pouvez aussi coller ou déposer un fichier image à la fois dans l’éditeur visuel. Attendez la fin de l’importation, ou annulez-la, avant d’enregistrer ou d’envoyer un test. Vérifiez l’aperçu, puis ouvrez Autres actions > E-mail de test pour vous envoyer le contenu actuel. Le mode Code reste disponible pour modifier le HTML.
Supprimer une image de la bibliothèque multimédia ne la supprime pas des e-mails déjà envoyés. Le remplacement d’une image utilise une nouvelle URL : les messages précédents continuent donc d’afficher l’original.
L'enregistrement est protégé par un numéro de révision. Envoyez le revision que vous avez lu en dernier pour la langue que vous enregistrez. Si quelqu'un d'autre a modifié cette langue entre-temps, l'enregistrement est refusé comme conflit au lieu d'écraser son travail. Omettez revision pour enregistrer sans condition. La publication et la restauration utilisent le revision propre au brouillon de la même manière.

Contenu en plusieurs langues

Un modèle peut contenir du contenu dans 25 langues au maximum, chacune avec son propre objet et corps, identifiée par un code BCP-47 tel que en ou pt-BR. Une langue est la langue par défaut du modèle. La publication d'un modèle publie toutes les langues qu'il contient en même temps. Vous ne pouvez pas publier une seule langue individuellement : elles doivent donc toutes être terminées. Chaque langue a besoin d'un objet et d'un corps, et la langue par défaut du modèle doit faire partie des langues que vous avez renseignées. Si l'une de ces conditions manque, rien n'est publié, et l'erreur vous indique ce qui manque dans chaque langue afin que vous puissiez tout corriger en une seule passe. Vous n'êtes pas obligé de terminer toutes les langues dès le départ : publiez celles qui sont prêtes, et ajoutez les autres plus tard.
Une langue a besoin d'un corps HTML. Vous pouvez omettre son text : la publication crée alors automatiquement une alternative en texte brut à partir du HTML, vous obtenez donc les deux parties sans écrire la seconde vous-même.
Chaque langue peut aussi contenir un texte d'aperçu, parfois appelé preheader : la ligne qu'une boîte de réception affiche après l'objet dans sa liste de messages. Il est facultatif, limité à 255 caractères, et accepte les mêmes placeholders {{ variable }} que l'objet. Si vous l'omettez, la boîte de réception se rabat sur la première ligne du corps, ce qui est rarement la ligne que vous choisiriez. La publication refuse un texte d'aperçu sur une langue dont le corps n'a pas de partie HTML, car un client de messagerie ne lit la ligne d'aperçu que dans du balisage HTML masqué, et refuse {{ bird.unsubscribe_url }} à l'intérieur pour la même raison que l'objet ne peut pas le contenir : ni l'un ni l'autre n'est un emplacement où un lien peut figurer.
Deux paramètres couvrent le cas d'un envoi qui ne désigne pas une langue pour laquelle le modèle a du contenu, et ils protègent contre des erreurs différentes :
ParamètreCe qu'il contrôle
on_missing_languageCe qui se passe quand un envoi demande une langue que le modèle ne possède pas. fallback, la valeur par défaut, sert la correspondance la plus proche. Il essaie d'abord une forme plus large de la même langue, de sorte qu'un pt stocké peut répondre à une demande pour pt-BR. Il se rabat ensuite sur la langue par défaut du modèle. fail rejette l'envoi à la place, pour du contenu où envoyer la mauvaise langue est pire que de ne rien envoyer du tout.
language_source_requiredIndique si un envoi doit nommer une langue. Ce réglage est désactivé par défaut : un envoi qui n'en nomme aucune reçoit la langue par défaut. Activez-le, et cet envoi est refusé. Un broadcast nomme une seule langue pour toute son audience : un template avec ce réglage activé exige que cette langue soit choisie avant que le broadcast puisse partir.
Vous pouvez configurer ces deux paramètres indépendamment. Seul, fail ne s'applique que lorsqu'un envoi désigne une langue que nous n'avons pas, donc un envoi qui n'en désigne aucune passe quand même. Activez les deux paramètres ensemble quand vous voulez que chaque envoi désigne une langue intentionnellement.

Personnalisation avec des variables

Écrivez des placeholders {{ variable }} dans l'objet, le texte d'aperçu et le corps. Nous les détectons automatiquement, combinés à travers toutes les langues, vous n'avez donc jamais besoin de les déclarer séparément. Le préfixe du placeholder distingue les deux types. Un chemin commençant par bird. lit nos données, soit un enregistrement de contact, soit le lien de désinscription. Tout le reste est un paramètre auquel vous donnez une valeur lors de l'envoi.
Le nom d'un paramètre est un mot unique, comme {{ animal }}. Un nom avec des points tente d'accéder à une structure qu'un paramètre ne possède pas, donc sa publication est rejetée : écrivez la valeur comme son propre paramètre, ou lisez les données de contact avec bird.contact.<attribute> à la place.
Sur un envoi unique ou un lot, la valeur d'un paramètre provient de l'objet template.parameters de l'envoi, indexée par son nom. Un seul jeu de valeurs couvre tous les destinataires de cet envoi. bird est le seul nom que vous ne pouvez pas utiliser ici : une clé template.parameters nommée bird est rejetée avec une 422.
Un broadcast n'a pas d'objet parameters, donc son contenu ne peut utiliser que des placeholders bird.. bird.contact.<attribute> est renseigné à partir des propriétés de contact propres à chaque destinataire, ce qui personnalise le contenu par destinataire. Chaque propriété de contact est accessible par sa propre clé, ainsi que les trois champs intégrés : first_name, last_name et email.
Exemple de code
Hi {{ bird.contact.first_name }},
Chaque paramètre du modèle a besoin d'une valeur au moment de l'envoi. Sinon, la API renvoie une 422 qui nomme le paramètre manquant. Fournissez des valeurs pour les paramètres dans toutes les langues, car la langue sélectionnée peut dépendre des paramètres de repli. Une propriété de contact manquante est rendue comme une valeur vide ; ajoutez donc un repli pour le contenu visible par le client : {{ bird.contact.first_name | default: "there" }}.
Un broadcast est plus strict sur les noms qu'il accepte, car les propriétés de contact sont tout ce dont il dispose pour remplir les placeholders. Ses placeholders bird.contact.* ne peuvent nommer qu'un champ intégré ou une propriété de contact enregistrée dans l'espace de travail. Tout autre placeholder, y compris un paramètre, est un placeholder que le broadcast n'a aucun moyen de remplir. L'envoi est refusé, et l'erreur nomme le placeholder.
Ce que l'archivage d'une propriété change pour un template ne concerne que le nouveau contenu : la propriété disparaît du sélecteur dans l'éditeur, et la publication d'une version dont le contenu la lit est refusée en nommant la propriété. Les versions publiées avant l'archivage ne sont pas affectées.
Les placeholders utilisent Liquid, donc les filtres et le contrôle de flux fonctionnent en plus de la substitution simple. Une condition {% if %} et une boucle {% for %} sur une valeur de type tableau sont toutes deux acceptées. Quelques constructions sont rejetées lors de la publication, et l'erreur nomme exactement ce qu'il faut modifier :
  • Les inclusions partielles, avec {% include %} ou {% render %}.
  • Les balises increment, decrement et ifchanged.
  • Les filtres money, format_date, format_time, json, inspect et type.
  • Les comparaisons avec empty ou blank. Utilisez .size == 0 à la place.
  • Des blocs imbriqués bien plus profondément que ce que le balisage d'un e-mail réel nécessite.
Le template d'un broadcast ne peut pas du tout utiliser de boucle {% for %}, car un broadcast remplit une seule valeur par propriété de contact et n'a rien sur quoi itérer. Si votre contenu nécessite une boucle, envoyez-le via l'API messages à la place.
Chaque template utilise Liquid, y compris celui qui ne contient que des placeholders {{ variable }}. Avant la publication, nous validons l'objet, le texte d'aperçu, le HTML et le contenu en texte brut en tant que Liquid. Nous ajoutons aussi le filtre escape à chaque sortie HTML qui ne se termine pas déjà par escape ou escape_once, afin qu'une valeur contenant & ou < ne puisse pas altérer le balisage environnant. La sortie réservée de désinscription reste inchangée pour que l'envoi puisse la remplacer. L'objet et le corps en texte brut sont laissés tels quels. Comme la publication ajoute ces filtres, le HTML que vous lisez dans une version publiée peut ne pas être identique octet pour octet à ce que vous avez soumis.
Placez une URL complète directement dans un href, par exemple <a href="{{ sign_in_url }}">Sign in</a>. N'ajoutez pas url_encode à la valeur entière. Il encode en pourcentage https://, /, ? et &, ce qui empêche le résultat de fonctionner comme un lien absolu. Nous ajoutons l'échappement HTML tout en préservant la structure de l'URL. Quand un paramètre fournit un composant d'URL, encodez ce composant explicitement : <a href="https://example.com/search?q={{ query | url_encode }}">Search</a>.

Prévisualiser avant de publier

Rendez un template avec des valeurs d'exemple et récupérez l'objet ainsi que les corps HTML et texte brut qu'un envoi livrerait. La prévisualisation utilise notre moteur Liquid local et rend le brouillon par défaut, ce qui vous permet de vérifier une modification avant sa mise en production. Elle peut aussi rendre une version publiée. Elle fonctionne pour vos propres templates et pour nos templates intégrés, et rien n'est envoyé.
Vous pouvez aussi lui fournir le contenu vous-même au lieu de lui faire lire le brouillon. Passez un objet et des corps : ils sont rendus exactement comme le serait un brouillon, ce qui permet à un éditeur d'afficher une modification au fil de la saisie sans rien enregistrer au préalable.
La personnalisation est remplie pour vous, de sorte que le résultat se lit comme un texte finalisé au lieu de placeholders {{ }}. Nommez un contact et chaque bird.contact.<attribute> est résolu à partir des propriétés de ce contact, ce qui vous permet de vérifier votre formulation par rapport à un enregistrement réel avant que quiconque ne le reçoive. Les valeurs proviennent de la même projection qu'un broadcast utilise pour remplir ses placeholders, de sorte que la prévisualisation répond avec ce qu'un envoi répondrait.
Omettez contact et des valeurs de substitution sont utilisées à la place : Bird et Test pour le prénom et le nom, bird.test@example.com pour l'e-mail, et le fallback enregistré de chaque autre propriété. Une propriété référencée sans fallback est rendue sous forme de clé entre crochets, comme [loyalty_tier], ce qui vous indique à la fois que la valeur est un placeholder et quelle propriété attend encore un fallback.
Un contact est lu tel qu'il est à l'instant présent. Cela fait de la prévisualisation le bon outil pour vérifier un contenu que vous êtes sur le point d'envoyer, et le mauvais pour savoir ce qu'un envoi précédent contenait. Pour lire ce qu'un envoi a réellement livré, ouvrez ce message dans le journal des e-mails à la place, qui le rend à partir des valeurs que cet envoi portait.
Ajoutez language pour rendre une langue spécifique, ou omettez-le pour la langue par défaut du template. La réponse vous indique quelle langue a été rendue, ce qui compte quand celle que vous avez demandée n'est pas disponible et que le on_missing_language du template a servi une correspondance proche.
Si le brouillon contient une personnalisation qui serait rejetée lors de la publication, la prévisualisation renvoie la même erreur, ce qui en fait aussi un moyen de détecter les problèmes en amont.
Dans le constructeur de templates du tableau de bord, Preview with contact data en bas du panneau gauche affiche l'e-mail rendu à côté de ce que vous éditez, dans l'éditeur visuel comme dans l'éditeur de code. Le sélecteur en dessous choisit les données de qui remplissent les placeholders, et Sample data correspond aux valeurs de substitution ci-dessus.

Envoyer avec un template

Définissez le champ template de l'envoi sur un objet qui nomme le template, soit par id (emt_...), soit par slug, en utilisant exactement l'un des deux. Placez les valeurs de ses variables dans template.parameters. Ajoutez language pour choisir une langue spécifique, ou omettez-le pour envoyer la langue par défaut du template, sauf si le template exige que chaque envoi en nomme une. Omettez subject, html et text entièrement, car le template les fournit déjà.
Exemple de code
{
  "from": "hello@yourdomain.com",
  "to": ["delivered@messagebird.dev"],
  "category": "transactional",
  "template": {
    "slug": "welcome-email",
    "parameters": { "first_name": "Jane" }
  }
}
Un comportement à anticiper : la catégorie du template est une valeur par défaut, et le category de l'envoi la remplace. Omettez category, et l'envoi hérite de la catégorie du template : un template opérationnel envoie en transactionnel sans que vous le répétiez à chaque appel. Définissez category, et votre valeur l'emporte. Le reste du contrat côté envoi se trouve dans envoyer avec un template.

Créer en dehors du tableau de bord

L'ensemble du cycle de vie est disponible en dehors du tableau de bord. L'étape de publication s'appelle submit là-bas, et c'est l'opération qui transforme le brouillon en la prochaine version publiée :
Exemple de code
bird email templates create welcome-email --category marketing --source html
bird email templates versions languages set <emt_...> <emv_...> en --subject "Hi {{ bird.contact.first_name }}" --html "<p>Hello</p>"
bird email templates versions submit <emt_...> <emv_...> --validate-only   # report problems, freeze nothing
bird email templates versions submit <emt_...> <emv_...>                   # freeze, go live
create renvoie le template avec son draft_version_id, que chaque commande de version et de langue utilise. --validate-only exécute les mêmes vérifications de complétude qu'un vrai submit, sans figer quoi que ce soit : c'est le moyen économique de trouver tous les problèmes dans toutes les langues en une seule passe. Relire un template vous donne ses métadonnées et son état par langue, mais pas le contenu. Le contenu réside dans les langues d'une version, une langue à la fois.
Les SDK proposent le même cycle de vie sous forme de méthodes typées sous email.templates, avec les opérations de version et de langue imbriquées en dessous sous email.templates.versions et email.templates.versions.languages. Un agent accède aux mêmes opérations via les outils email_templates_* MCP.

Étapes suivantes

  • Envoyer un e-mail : le payload d'envoi complet, et comment les envois avec template s'y intègrent
  • Catégories : choisir marketing ou transactional pour chaque envoi
  • bird email templates : gérer les templates depuis le terminal
  • Référence API : schémas complets de requête et de réponse pour les dix-huit opérations de template
  • SDK : les méthodes typées email.templates en TypeScript, Python, PHP et Go
  • Serveur MCP : permettre à un agent de créer et publier des templates
  • Comment créer un template d'email : une vidéo qui en construit un dans le tableau de bord, puis fait construire l'autre par un agent

Ressources associées

Poursuivez avec la documentation, les guides et les exemples sur ce sujet. Les ressources sont en anglais.

Essayez la pratique et obtenez un guide d'implémentation