Sign inGet started

Migrer depuis Postmark

Cette page fait correspondre le payload d'envoi, les exports de suppressions et les webhooks de Postmark avec Bird. Suivez le guide de migration principal dans l'ordre et utilisez ces correspondances pour les étapes 1, 3 et 4.
La documentation de Postmark indique qu'il "does not currently support HMAC webhook signature verification" (consulté en septembre 2026), l'étape 4 ajoute donc une vérification que votre handler n'a pas aujourd'hui. Lisez Traduire les événements webhook avant de planifier la bascule.

Confiez cette page à votre agent

Collez ceci dans Claude Code, Cursor ou Codex. L'agent parcourt cette page en regard de votre propre dépôt, en utilisant la surface Bird dont il dispose déjà : le serveur MCP s'il est connecté, le CLI s'il est installé et authentifié.
Exemple de code
I am moving an email integration from Postmark to Bird. Route through it with me.
1. Check what you already have before setting anything up. If Bird's MCP server is connected, use its tools. If the Bird CLI is installed and signed in, use that. Either one is enough, and every step below is an action you take with whichever you have. Only if neither is present, follow https://bird.com/docs/ai/set-up-your-agent.md to set one up and sign me in. Every Bird docs page serves Markdown at its own URL with `.md` appended, so fetch that rather than the HTML.
2. Read https://bird.com/docs/guides/email/migrate/postmark.md for the payload, suppression and webhook mapping, and https://bird.com/docs/guides/email/migrate.md for the order the steps go in.
3. Find and list my Postmark usage in this repository before you change anything: calls to /email and /email/withTemplate and any SDK wrappers around them, every MessageStream name I send on, the webhook handler and the URL it is registered at, and every domain I send from. Tell me the list before you edit anything.
4. Register each of those sending domains with Bird and give me the DNS records to publish, following https://bird.com/docs/guides/email/sending-domains.md. Leave every DNS record Postmark uses exactly as it is: Bird's records are published alongside them and both providers authenticate side by side until I switch traffic. Publishing DNS affects mail for the whole domain, so show me the records and let me publish them.
5. Export my suppressions and import them into Bird before any production traffic goes through Bird, so my first sends do not reach addresses that already bounced or complained. Postmark keeps suppressions per message stream, so dump GET /message-streams/{stream_id}/suppressions/dump once for every stream I send on rather than only the default outbound stream. The Bird import takes one address per request and is idempotent, so a partial re-run is safe. https://bird.com/docs/guides/email/suppressions.md has the reason taxonomy.
6. Port the send call and the webhook handler using the mapping tables on the provider page. Postmark's docs say it does not currently support HMAC webhook signature verification, so my handler probably has no signature check and adding one is new code rather than a swap. If my registered Postmark webhook URL carries HTTP Basic credentials, take them out and tell me to rotate that pair rather than reusing it on the Bird endpoint: a URL-embedded credential should be treated as exposed. https://bird.com/docs/guides/webhooks.md and https://bird.com/docs/guides/email/events.md.
7. Run my whole integration against Bird's mail sandbox before any production traffic, following https://bird.com/docs/guides/email/testing-sandbox.md. Sandbox sends run the real pipeline without reaching an inbox or touching my sending reputation.
8. Stop and ask me wherever a step needs a decision. Do not point production traffic at Bird until I have seen the sandbox results and replied with the words cut over to Bird. Retiring the Postmark path is a separate step that comes later: ask me again and wait for me to reply with the words retire the Postmark path. A reply that agrees without naming what it is authorising is not authorisation. Finish by telling me what is left that only a person can do.

Faire correspondre l'appel d'envoi

Postmark sépare l'envoi en deux endpoints : POST /email pour un message composé et POST /email/withTemplate pour un template enregistré. Notre POST /v1/email/messages est un endpoint unique pour les deux, le template étant référencé dans un champ.
FonctionPostmarkBird
AuthentificationEn-tête X-Postmark-Server-TokenAuthorization: Bearer
ExpéditeurFromfrom
DestinatairesTo / Cc / Bcc (séparés par des virgules, max 50)to / cc / bcc (tableaux)
ObjetSubjectsubject
CorpsHtmlBody / TextBodyhtml / text (au moins un)
Reply-toReplyTo (séparés par des virgules)reply_to (tableau)
En-têtes personnalisésHeaders (objets Name/Value)headers (objet string → string)
Libellé filtrableTag (un par message)tags : paires {name, value}
Contexte aller-retourMetadatametadata : JSON arbitraire
Template enregistréTemplateId / TemplateAlias + TemplateModeltemplate + template.parameters
Suivi des ouverturesTrackOpenstrack_opens (par défaut true)
Suivi des clicsTrackLinks (None/HtmlAndText/HtmlOnly/TextOnly)track_clicks (booléen, voir ci-dessous)
Pièces jointesAttachments (Name, Content, ContentType)attachments
Séparation du traficMessageStream(pas d'équivalent, voir ci-dessous)
Catégorie(aucune)category : marketing (par défaut) ou transactional
Planification(aucune)scheduled_at
Les limites et valeurs par défaut de nos champs (nombre de destinataires, limites de tags et de métadonnées) se trouvent dans Envoyer des e-mails.
Notes de portage :
  • Les destinataires sont des chaînes dans Postmark et des tableaux ici. "a@x.com, b@x.com" devient ["a@x.com", "b@x.com"]. Si votre code construit cette chaîne en joignant une liste, supprimez la jointure plutôt que la liste.
  • Tag est une seule chaîne par message. Nos tags sont des paires, et il peut y en avoir plusieurs. Un tag comme "welcome" devient {"name": "category", "value": "welcome"}. Choisissez un name stable pour que vos tableaux de bord filtrent comme le faisaient vos statistiques de tags Postmark.
  • Metadata se porte directement, et nous le renvoyons. Nous retournons votre metadata (et tags) dans chaque événement webhook aux côtés de email_id/recipient_id, pour que vos handlers récupèrent votre contexte sans lookup.
  • Le suivi des clics est un enum là-bas et un booléen ici. TrackLinks: "None" correspond à track_clicks: false ; les trois valeurs activées deviennent toutes track_clicks: true, car nous ne suivons pas les parties HTML et texte séparément.
  • Les templates passent dans le même appel. Il n'y a pas d'endpoint de template séparé : TemplateId ou TemplateAlias devient template (par ID ou slug) et TemplateModel devient template.parameters, sur POST /v1/email/messages. Voir envoyer avec un template.
  • Un flux de messages n'a pas d'équivalent, et category n'en est pas un. Un flux est un conteneur disposant de sa propre liste de suppressions, de ses propres statistiques et de ses propres webhooks. Notre catégorie est un indicateur par message avec un seul effet : il détermine quels enregistrements de suppression et quelles préférences de désinscription peuvent bloquer ce message. Définir category: transactional parce qu'un message provient d'un flux transactionnel est souvent correct, mais c'est une déclaration sur la raison de l'envoi plutôt qu'un portage du flux. Rien ici ne reproduit les statistiques par flux ou le périmètre de suppression par flux ; utilisez les tags pour la segmentation des rapports.

Exporter les suppressions

Postmark conserve les suppressions par flux de messages, il n'y a donc pas de liste unique à l'échelle du compte à extraire. Pour chaque flux sur lequel vous envoyez, exportez-le et passez le résultat dans la boucle d'import :
  • GET /message-streams/{stream_id}/suppressions/dump
Énumérez d'abord vos flux et exportez chacun de ceux sur lesquels vous envoyez encore. Traiter le flux outbound par défaut comme s'il était la seule liste importe les suppressions transactionnelles et oublie les broadcast, et vous le découvrez en envoyant des messages à des personnes qui se sont désinscrites. Les valeurs SuppressionReason sont HardBounce, SpamComplaint et ManualSuppression, qui correspondent à nos raisons hard_bounce, complaint et manual. Suppressions contient la taxonomie complète.

Traduire les événements webhook

Postmark envoie un type de webhook par événement et l'identifie par le champ RecordType dans le payload.
RésultatPostmarkBird
Accepté/traité(la réponse API)email.acceptedemail.processed
DélivréDeliveryemail.delivered
Échec temporaireBounce avec un Type transitoireemail.deferred
Rebond permanentBounce avec Type: HardBounceemail.bounced / email.out_of_band_bounce
Plainte pour spamSpamComplaintemail.complained
Bloqué/supprimé(aucun)email.rejected
OuvertureOpenemail.opened
ClicClickemail.clicked
DésinscriptionSubscriptionChangeemail.unsubscribed / email.list_unsubscribed
Deux différences déterminent l'ampleur des modifications de votre handler.
La vérification est du nouveau code, pas un remplacement. La documentation de Postmark indique qu'il "does not currently support HMAC webhook signature verification" (consulté en septembre 2026), et recommande des identifiants HTTP Basic intégrés dans l'URL enregistrée (https://<username>:<password>@example.com/webhook) ainsi que ses plages IP dans votre pare-feu. Nous signons chaque livraison selon le schéma HMAC de Standard Webhooks, votre handler gagne donc une étape de vérification qu'il n'avait pas. La procédure est dans Webhooks et événements. Faites cette étape en premier : un handler qui accepte des requêtes non signées est la seule chose que la migration ne doit pas conserver.
Renouvelez les identifiants plutôt que de les réutiliser. Un nom d'utilisateur et un mot de passe intégrés dans une URL de webhook doivent être considérés comme exposés, car les URL se retrouvent dans les logs d'accès, les exports de configuration et la console du fournisseur. Retirez-les de l'endpoint et émettez une nouvelle paire si autre chose en a encore besoin ; ne reportez pas l'ancienne paire sur l'endpoint Bird, qui s'authentifie par signature.
Postmark signale les rebonds définitifs et temporaires dans un seul enregistrement Bounce avec un champ Type. Nous les signalons comme des événements distincts. Un handler qui branche sur Type dans un payload de rebond branche ici sur le nom de l'événement : les échecs temporaires arrivent en tant que email.deferred et les permanents en tant que email.bounced. Chaque type de rebond distingué par Postmark figure dans sa référence Bounce API ; ce qui compte pour le portage, c'est de quel côté de cette séparation chacun se trouve.
Nos événements de livraison sont à l'échelle du destinataire (recipient_id à côté de email_id), un envoi à trois destinataires produit donc trois résultats de livraison plutôt qu'un seul.

Bascule

Suivez domaines et DNS et le test de fumée sandbox dans le guide principal. Les deux sont indépendants du fournisseur.

Étapes suivantes

  • Domaines d'envoi : enregistrement, cycle de vie de la vérification et enregistrements DNS que vous publiez
  • Webhooks et événements : configuration de l'endpoint et vérification Standard Webhooks
  • Sandbox de test : testez la nouvelle intégration avant la bascule
  • Suppressions : confirmez votre liste importée et la façon dont nous la maintenons à partir de maintenant