Migrer depuis Mandrill
Cette page fait correspondre le payload messages/send de Mandrill (Mailchimp Transactional), la liste de rejet et les webhooks à Bird. Suivez le guide de migration principal dans l'ordre et utilisez ces correspondances pour les étapes 1, 3 et 4.
Deux changements de structure dominent le portage. Mandrill imbrique tout sous un objet message et s'authentifie avec une key dans le corps de la requête. Nous acceptons un payload plat au premier niveau et un en-tête Authorization: Bearer standard. Et le type de destinataire de Mandrill (to/cc/bcc en tant que champ sur chaque adresse) devient nos tableaux to/cc/bcc séparés.
Confiez ceci à 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 Mandrill 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/mandrill.md for the payload, suppression and event mapping, and https://bird.com/docs/guides/email/migrate.md for the order the steps go in.
3. Find and list my Mandrill usage in this repository before you change anything: the messages/send and messages/send-template call sites and any SDK wrappers around them, the webhook handler and the URL it is registered at, and every domain I send from. Mandrill authenticates with an API key passed in the request body rather than a header, so tell me every place that key appears in my code: the port changes how I authenticate, not just what I send, and that key is a secret currently sitting in a payload.
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 my current provider 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 rejects from Mandrill 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. Read the list through rejects/list, and skip the soft-bounce rows: those are transient failures rather than suppressions, and importing them would suppress addresses that are fine. Show me how many rows you skipped. 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. Move the API key out of the request body and into the Authorization header as a bearer token while you are there. Bird signs deliveries per Standard Webhooks rather than Mandrill's scheme, so treat verification as a rewrite rather than a URL change: 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 Mandrill path is a separate step that comes later: ask me again and wait for me to reply with the words retire the Mandrill 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
| Fonction | Mandrill (messages/send) | Bird |
|---|---|---|
| Auth | key dans le corps de la requête | En-tête Authorization: Bearer bk_... |
| Expéditeur | message.from_email / from_name | from : string ou { "email", "name" } |
| Destinataires | message.to : [{ email, name, type }] | to / cc / bcc : séparés par le champ type |
| Objet | message.subject | subject |
| Corps | message.html / message.text | html / text (au moins un) |
| Reply-to | message.headers["Reply-To"] | reply_to : tableau |
| En-têtes personnalisés | message.headers | headers : objet string → string |
| Libellés filtrables | message.tags : chaînes simples | tags : paires { name, value } |
| Contexte aller-retour | message.metadata | metadata : JSON arbitraire |
| Template enregistré | messages/send-template + merge_vars | template + template.parameters |
| Planification | send_at | scheduled_at |
| Suivi ouverture/clic | message.track_opens / track_clicks | track_opens / track_clicks (par défaut true) |
| Pièces jointes | message.attachments : { type, name, content } | attachments : { content_type, filename, content } |
| Images inline | message.images : { type, name, content } | attachments avec content_id |
| Catégorie | convention subaccount / tags | category : marketing (par défaut) ou transactional |
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 :
- Aplatir et ré-authentifier. Supprimez l'enveloppe message (ses champs passent au premier niveau) et déplacez la clé API du corps vers l'en-tête Authorization. Le champ key n'a pas d'équivalent ici.
- Séparer les destinataires par type. Mandrill marque chaque destinataire to, cc ou bcc sur l'objet d'adresse. Nous utilisons trois tableaux séparés. Répartissez la liste to par son champ type lors du portage.
- Les tags deviennent des paires nom/valeur. Les tags Mandrill sont des chaînes simples ("welcome"). Nos tags sont des paires { name, value }. Choisissez un name stable, par exemple { "name": "category", "value": "welcome" }, pour que vos filtres et analyses se regroupent comme vos statistiques Mandrill. metadata se porte directement en JSON.
- Les templates enregistrés se portent, avec une réserve. Le messages/send-template de Mandrill devient notre champ template (référencé par ID ou slug) avec les valeurs dans template.parameters. Voir envoyer avec un template. Nos variables de template sont par message et non par destinataire, donc les merge_vars par destinataire deviennent une entrée batch par destinataire, chacune avec son propre parameters.
- Les pièces jointes se portent directement. Le content en base64 de Mandrill est notre content, et les images inline (référencés comme cid: dans le HTML) deviennent des entrées attachments avec content_id. Voir pièces jointes.
Exporter les suppressions
Mandrill conserve les adresses indésirables dans sa liste de rejet (rejection blacklist). Récupérez-la avec rejects/list API (ou exportez depuis la vue Rejection Blacklist). Chaque entrée a une raison (hard-bounce, soft-bounce, spam, unsub, custom). Ignorez les lignes soft-bounce car elles décrivent des échecs transitoires et non de vraies suppressions. Passez le reste par la boucle d'import.
Traduire les événements webhook
Mandrill envoie des tableaux d'événements groupés ; faites correspondre la valeur event au vocabulaire des événements de Bird :
| Résultat | Mandrill | Bird |
|---|---|---|
| Envoyé / accepté | send | email.accepted → email.processed |
| Délivré | delivered | email.delivered |
| Échec temporaire | deferral | email.deferred |
| Rebond permanent | hard_bounce | email.bounced / email.out_of_band_bounce |
| Rebond temporaire | soft_bounce | email.deferred (puis email.bounced s'il abandonne) |
| Plainte pour spam | spam | email.complained |
| Désinscription | unsub | email.unsubscribed / email.list_unsubscribed |
| Rejeté/bloqué | reject | email.rejected |
| Ouverture | open | email.opened |
| Clic | click | email.clicked |
Deux différences à prendre en compte dans le code :
- L'acceptation se divise en deux événements chez nous. Le send de Mandrill signifie que le message a été injecté et delivered signifie que le serveur destinataire l'a accepté, ce qui est la même distinction que nous faisons. La différence se situe uniquement de notre côté : nous séparons l'acceptation (email.accepted) du traitement (email.processed) avant email.delivered, donc un handler qui se basait uniquement sur send a maintenant deux événements entre lesquels choisir.
- Les événements sont par destinataire et signés différemment. Nos événements de livraison incluent recipient_id à côté de email_id, avec un flux par destinataire. Nous envoyons un événement par requête et le signons selon la spécification Standard Webhooks. Mandrill signe plutôt des tableaux groupés avec un X-Mandrill-Signature HMAC. Voir Webhooks et événements pour la vérification.
Basculer
Suivez domaines et DNS et le test de fumée en sandbox dans le guide principal. Les deux sont indépendants du fournisseur.
Étapes suivantes
- Domaines d'envoi : enregistrement, cycle de vérification et enregistrements DNS que vous redirigez
- 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 : vérifiez votre liste importée et la façon dont nous la maintenons à partir de maintenant
Ressources associées
Poursuivez avec la documentation, les guides et les exemples sur ce sujet. Les ressources sont en anglais.
Regarder le guideGetting started with emailExplorer la fonctionnalitéEmailSuivre le parcours d'apprentissageBuild your first integrationGuide d'implémentationSend your first email
Essayez la pratique et obtenez un guide d'implémentation