Migrar desde MailerSend
Esta página mapea el payload de envío, las listas de supresión y los webhooks de MailerSend a Bird. Sigue la guía principal de migración en orden y usa estos mapeos para los pasos 1, 3 y 4.
MailerSend mantiene cinco listas de supresión y una de ellas es temporal por diseño. Lee Exportar supresiones antes del paso 3: importar esa lista convierte una retención de 72 horas en un bloqueo permanente.
Pasa esto a tu agente
Pega esto en Claude Code, Cursor o Codex. El agente recorre esta página contra tu propio repositorio, usando la superficie de Bird que ya tenga: el servidor MCP si hay uno conectado, o CLI si está instalado y con sesión iniciada.
Ejemplo de código
I am moving an email integration from MailerSend 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/mailersend.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 MailerSend usage in this repository before you change anything: calls to /v1/email and any SDK wrappers around them, whether I send with template_id and personalization or with html, 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 MailerSend 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. MailerSend keeps five lists under /v1/suppressions: hard bounces, spam complaints, unsubscribes and the blocklist are the four to carry over. Do NOT import the On Hold list: it is a temporary 72-hour hold that MailerSend clears by itself, and importing it would suppress those addresses permanently. 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. Both providers sign with HMAC-SHA256, so this is a re-implementation rather than new code: MailerSend sends one Signature header, Bird follows the Standard Webhooks scheme with webhook-id, webhook-timestamp and webhook-signature, and the signed string is constructed differently. Keep the constant-time comparison. 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 MailerSend path is a separate step that comes later: ask me again and wait for me to reply with the words retire the MailerSend 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.Mapear la llamada de envío
POST /v1/email de MailerSend y nuestro POST /v1/email/messages comparten estructura. Las diferencias que requieren código son el límite de tags y cómo se transportan los datos por destinatario.
| Función | MailerSend | Bird |
|---|---|---|
| Remitente | from ({email, name}) | from |
| Destinatarios | to (máx. 50), cc / bcc (máx. 10 cada uno) | to / cc / bcc (arrays) |
| Asunto | subject (máx. 998 caracteres) | subject |
| Cuerpo | html / text | html / text (al menos uno) |
| Reply-to | reply_to ({email, name}) | reply_to (array) |
| Cabeceras personalizadas | headers ({name, value}, planes superiores) | headers (objeto string → string) |
| Etiquetas filtrables | tags (array de strings, máx. 5) | pares tags: {name, value} |
| Plantilla almacenada | template_id + personalization | template + template.parameters (ver más abajo) |
| Adjuntos | attachments (content, filename, disposition, id) | attachments |
| Programación | send_at (hasta 72 horas de anticipación) | scheduled_at |
| Precedencia masiva | precedence_bulk | (sin equivalente, ver más abajo) |
| Categoría | (ninguna) | category: marketing (predeterminado) o transactional |
| Threading | in_reply_to | headers |
Los límites y valores predeterminados de nuestros campos (cantidad de destinatarios, límites de tags y metadatos) están en Envío de email.
Notas de migración:
- Las direcciones son objetos allí y strings aquí. {"email": "a@x.com", "name": "A"} se convierte en "A <a@x.com>" o simplemente "a@x.com", tanto para from, to, cc, bcc como para reply_to.
- Los tags son strings simples con un máximo de cinco. Nuestros tags son pares. Un tag como "welcome" se convierte en {"name": "category", "value": "welcome"}. Elige un name estable para que tus dashboards filtren como lo hacían tus estadísticas de tags en MailerSend.
- personalization son datos de plantilla por destinatario. Es un array indexado por email del destinatario. Nuestro template.parameters se aplica al envío completo, así que un mensaje cuyo contenido realmente difiere por destinatario se convierte en un envío por destinatario o en una entrada de batch cada uno. Si tu array personalization lleva los mismos valores para todos los destinatarios, se reduce a un solo objeto template.parameters.
- El contexto de ida y vuelta no tiene equivalente en MailerSend que copiar. Si reconstruías el contexto a partir de tags, usa metadata en su lugar: lo devolvemos en cada evento de webhook junto con email_id/recipient_id, y no tiene un límite de cinco entradas.
- precedence_bulk no tiene equivalente, y category no lo es. precedence_bulk establece una cabecera Precedence: bulk, que pide a los autoresponders y agentes de fuera de oficina que no respondan. Nuestro category decide qué registros de supresión y preferencias de cancelación de suscripción pueden bloquear un mensaje, y nada más. Usar category en su lugar cambia el comportamiento de supresión y no hace nada respecto a los autoresponders. Si necesitas la cabecera, ten en cuenta que headers rechaza direcciones y nombres de plataforma, pero no esta.
- Las cabeceras personalizadas y list_unsubscribe están restringidas por plan en MailerSend. Si tu plan no las incluía, aquí están disponibles; consulta envío de email y categorías para ver cómo gestionamos list-unsubscribe en correo de marketing.
Exportar supresiones
MailerSend mantiene cinco listas bajo /v1/suppressions, un endpoint por lista. Cuatro son permanentes y se transfieren; la quinta no debe transferirse.
Exporta y procesa con el bucle de importación:
- Rebotes duros, por ejemplo GET https://api.mailersend.com/v1/suppressions/hard-bounces
- Quejas de spam
- Cancelaciones de suscripción
- Lista de bloqueo, las direcciones y patrones que añadiste manualmente
No importes la lista On Hold. La propia descripción de MailerSend indica que contiene direcciones que "have soft bounced 5 times within 30 days", que "these emails will be blocked for 72 hours", y que luego son "automatically removed from the list". Es un período de enfriamiento que el proveedor limpia por sí mismo, así que importarla convierte una retención temporal en una supresión permanente y deja de enviar correo silenciosamente a direcciones que estaban a punto de ser liberadas. Nuestro equivalente de ese comportamiento es el aplazamiento, que gestionamos a partir de resultados de entrega en tiempo real en lugar de una lista importada.
Los tipos de lista de MailerSend se corresponden con nuestras razones hard_bounce, complaint y manual; Supresiones tiene la taxonomía completa.
Traducir eventos de webhook
| Resultado | MailerSend | Bird |
|---|---|---|
| Aceptado/procesado | activity.sent | email.accepted → email.processed |
| Entregado | activity.delivered | email.delivered |
| Fallo temporal | activity.soft_bounced / activity.deferred | email.deferred |
| Rebote permanente | activity.hard_bounced | email.bounced / email.out_of_band_bounce |
| Queja de spam | activity.spam_complaint | email.complained |
| Apertura | activity.opened / activity.opened_unique | email.opened |
| Clic | activity.clicked / activity.clicked_unique | email.clicked |
| Cancelación de suscripción | activity.unsubscribed | email.unsubscribed / email.list_unsubscribed |
| Retenido temporalmente | recipient.on_hold_added / ..._removed | (sin equivalente; ver más arriba) |
Dos diferencias determinan cuánto cambia tu handler.
Ambos lados firman con HMAC-SHA256, así que es una reimplementación, no código nuevo. MailerSend envía una sola cabecera Signature con un hash del payload calculado con el secreto de firma de ese webhook. Nosotros seguimos el esquema Standard Webhooks, que usa webhook-id, webhook-timestamp y webhook-signature y firma una cadena construida a partir del id, el timestamp y el body, por lo que el timestamp también te da protección contra repetición. Conserva la comparación en tiempo constante que ya tienes y reemplaza la construcción; la receta está en Webhooks y eventos.
MailerSend distingue aperturas y clics de sus variantes únicas. Nosotros no. activity.opened y activity.opened_unique llegan ambos como email.opened, así que un handler que contaba solo la variante única necesita deduplicar por recipient_id directamente. Nuestros eventos de entrega tienen alcance por destinatario, de modo que un envío a tres destinatarios produce tres resultados de entrega en lugar de uno.
Transición
Sigue dominios y DNS y la prueba de humo en sandbox de la guía principal. Ambos son independientes del proveedor.
Próximos pasos
- Dominios de envío: registro, ciclo de vida de verificación y los registros DNS que estás publicando
- Webhooks y eventos: configuración de endpoints y verificación de Standard Webhooks
- Sandbox de pruebas: prueba de humo de la nueva integración antes de la transición
- Supresiones: confirma tu lista importada y cómo la mantenemos a partir de ahora
Recursos relacionados
Continúa con la documentación, guías y ejemplos sobre este tema. Los recursos están en inglés.
Ver la guíaGetting started with emailExplorar la funcionalidadEmailSeguir la ruta de aprendizajeBuild your first integrationGuía de implementaciónSend your first email
Prueba el ejercicio y obtén un resumen de implementación