# Migration von MailerSend

Diese Seite ordnet den Send-Payload, die Suppressionslisten und die Webhooks von MailerSend Bird zu. Folgen Sie dem [Hauptleitfaden zur Migration](/docs/guides/email/migrate) der Reihe nach und verwenden Sie diese Zuordnungen für die Schritte 1, 3 und 4.

MailerSend führt fünf Suppressionslisten, und eine davon ist konstruktionsbedingt temporär. Lesen Sie [Suppressionen exportieren](#suppressionen-exportieren) vor Schritt 3: Der Import dieser Liste macht aus einer 72-Stunden-Sperre eine permanente Blockierung.

## Übergeben Sie dies Ihrem Agenten

Fügen Sie dies in Claude Code, Cursor oder Codex ein. Der Agent arbeitet diese Seite gegen Ihr eigenes Repository ab und nutzt die Bird-Oberfläche, die er bereits hat: den MCP-Server, falls einer verbunden ist, oder die CLI, falls sie installiert und angemeldet ist.

```text
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.
```

## Den Send-Call zuordnen

`POST /v1/email` von MailerSend und unser [`POST /v1/email/messages`](/docs/api/reference/create-email-message) haben dieselbe Struktur. Die Unterschiede, die Code erfordern, sind das Tag-Limit und die Art, wie empfängerspezifische Daten übergeben werden.

| Funktion               | MailerSend                                                 | Bird                                                    |
| ---------------------- | ---------------------------------------------------------- | ------------------------------------------------------- |
| Absender               | `from` (`{email, name}`)                                   | `from`                                                  |
| Empfänger              | `to` (max. 50), `cc` / `bcc` (max. 10 je)                  | `to` / `cc` / `bcc` (Arrays)                            |
| Betreff                | `subject` (max. 998 Zeichen)                               | `subject`                                               |
| Inhalt                 | `html` / `text`                                            | `html` / `text` (mindestens eins)                       |
| Reply-to               | `reply_to` (`{email, name}`)                               | `reply_to` (Array)                                      |
| Eigene Header          | `headers` (`{name, value}`, höhere Tarife)                 | `headers` (String-→-String-Objekt)                      |
| Filterbare Labels      | `tags` (Array von Strings, max. 5)                         | `tags`: `{name, value}`-Paare                           |
| Gespeichertes Template | `template_id` + `personalization`                          | `template` + `template.parameters` (siehe unten)        |
| Anhänge                | `attachments` (`content`, `filename`, `disposition`, `id`) | `attachments`                                           |
| Zeitplanung            | `send_at` (bis zu 72 Stunden im Voraus)                    | `scheduled_at`                                          |
| Bulk-Precedence        | `precedence_bulk`                                          | (kein Gegenstück, siehe unten)                          |
| Kategorie              | (keine)                                                    | `category`: `marketing` (Standard) oder `transactional` |
| Threading              | `in_reply_to`                                              | `headers`                                               |

Unsere Feldlimits und Standardwerte (Empfängeranzahl, Tag- und Metadaten-Limits) stehen unter [E-Mail senden](/docs/guides/email/sending-email).

Portierungshinweise:

- **Adressen sind dort Objekte und hier Strings.** `{"email": "a@x.com", "name": "A"}` wird zu `"A <a@x.com>"` oder einfach `"a@x.com"`, für `from`, `to`, `cc`, `bcc` und `reply_to` gleichermaßen.
- **`tags` sind einfache Strings mit einem Limit von fünf. Unsere Tags sind Paare.** Ein Tag wie `"welcome"` wird zu `{"name": "category", "value": "welcome"}`. Wählen Sie einen stabilen `name`, damit Ihre Dashboards so filtern wie Ihre bisherigen MailerSend-Tag-Statistiken.
- **`personalization` sind empfängerspezifische Template-Daten.** Es handelt sich um ein Array, das nach Empfänger-E-Mail geschlüsselt ist. Unser `template.parameters` gilt für den gesamten Send. Eine Nachricht, deren Inhalt sich tatsächlich pro Empfänger unterscheidet, wird daher zu einem Send pro Empfänger oder zu je einem [Batch](/docs/guides/email/sending-bulk)-Eintrag. Wenn Ihr `personalization`-Array für jeden Empfänger dieselben Werte enthält, lässt es sich zu einem einzigen `template.parameters`-Objekt zusammenfassen.
- **Round-Trip-Kontext hat kein MailerSend-Äquivalent zum Übernehmen.** Wenn Sie bisher Kontext aus `tags` rekonstruiert haben, verwenden Sie stattdessen [`metadata`](/docs/guides/email/sending-email): Wir senden es bei jedem Webhook-Event zusammen mit `email_id`/`recipient_id` zurück, und es ist nicht auf fünf Einträge begrenzt.
- **`precedence_bulk` hat kein Gegenstück, und `category` ist keins.** `precedence_bulk` setzt einen `Precedence: bulk`-Header, der Autoresponder und Abwesenheitsassistenten auffordert, nicht zu antworten. Unser `category` entscheidet, welche Suppressionseinträge und Abmeldepräferenzen eine Nachricht blockieren dürfen, und sonst nichts. `category` stattdessen zu setzen ändert das Suppressionsverhalten und bewirkt nichts gegen Autoresponder. Falls Sie den Header benötigen: `headers` lehnt Adress- und Plattformnamen ab, aber nicht diesen.
- **Eigene Header und `list_unsubscribe` sind bei MailerSend tarifabhängig.** Falls Ihr Tarif sie nicht enthielt, stehen sie hier zur Verfügung; siehe [E-Mail senden](/docs/guides/email/sending-email) und [Kategorien](/docs/guides/email/categories) für den Umgang mit List-Unsubscribe bei Marketing-Mail.

## Suppressionen exportieren

MailerSend führt fünf Listen unter `/v1/suppressions`, einen Endpoint pro Liste. Vier sind permanent und werden übernommen; die fünfte darf nicht übernommen werden.

Exportieren und durch die [Import-Schleife](/docs/guides/email/migrate#3-import-suppressions) laufen lassen:

- **Hard Bounces**, zum Beispiel `GET https://api.mailersend.com/v1/suppressions/hard-bounces`
- **Spam-Beschwerden**
- **Abmeldungen**
- **Blocklist**, die Adressen und Muster, die Sie manuell hinzugefügt haben

**Importieren Sie die On-Hold-Liste nicht.** MailerSend beschreibt sie selbst so, dass sie Adressen enthält, die "have soft bounced 5 times within 30 days", die "these emails will be blocked for 72 hours", und die dann "automatically removed from the list". Es handelt sich um eine Abkühlungsphase, die der Anbieter selbst aufhebt. Der Import wandelt eine temporäre Sperre in eine permanente Suppression um und verhindert stillschweigend den Versand an Adressen, die kurz vor der Freigabe standen. Unser Äquivalent dafür ist [Deferral](/docs/guides/email/events), das wir anhand von Live-Zustellergebnissen handhaben statt über eine importierte Liste.

Die Listentypen von MailerSend werden unseren Gründen `hard_bounce`, `complaint` und `manual` zugeordnet; [Suppressionen](/docs/guides/email/suppressions) enthält die vollständige Taxonomie.

## Webhook-Events übersetzen

| Ergebnis                | MailerSend                                     | Bird                                             |
| ----------------------- | ---------------------------------------------- | ------------------------------------------------ |
| Angenommen/verarbeitet  | `activity.sent`                                | `email.accepted` → `email.processed`             |
| Zugestellt              | `activity.delivered`                           | `email.delivered`                                |
| Temporärer Fehler       | `activity.soft_bounced` / `activity.deferred`  | `email.deferred`                                 |
| Permanenter Bounce      | `activity.hard_bounced`                        | `email.bounced` / `email.out_of_band_bounce`     |
| Spam-Beschwerde         | `activity.spam_complaint`                      | `email.complained`                               |
| Öffnung                 | `activity.opened` / `activity.opened_unique`   | `email.opened`                                   |
| Klick                   | `activity.clicked` / `activity.clicked_unique` | `email.clicked`                                  |
| Abmeldung               | `activity.unsubscribed`                        | `email.unsubscribed` / `email.list_unsubscribed` |
| Temporär zurückgehalten | `recipient.on_hold_added` / `..._removed`      | (kein Äquivalent; siehe oben)                    |

Zwei Unterschiede bestimmen, wie stark sich Ihr Handler ändert.

**Beide Seiten signieren mit HMAC-SHA256, es handelt sich also um eine Neuimplementierung, nicht um neuen Code.** MailerSend sendet einen einzelnen `Signature`-Header mit einem Hash des Payloads, berechnet mit dem Signing Secret des Webhooks. Wir folgen dem [Standard Webhooks](https://www.standardwebhooks.com)-Schema, das `webhook-id`, `webhook-timestamp` und `webhook-signature` verwendet und einen String aus der ID, dem Zeitstempel und dem Body signiert, sodass der Zeitstempel Ihnen auch Replay-Schutz bietet. Behalten Sie den Konstantzeit-Vergleich, den Sie bereits haben, und tauschen Sie die Konstruktion aus; die Anleitung steht unter [Webhooks und Events](/docs/guides/webhooks).

**MailerSend unterscheidet Öffnungen und Klicks von deren eindeutigen Varianten. Wir nicht.** `activity.opened` und `activity.opened_unique` kommen beide als `email.opened` an. Ein Handler, der nur die eindeutige Variante gezählt hat, muss daher selbst anhand von `recipient_id` deduplizieren. Unsere Zustellereignisse sind empfängerbezogen: Ein Send an drei Empfänger erzeugt drei Zustellergebnisse statt eines.

## Umstellung

Arbeiten Sie [Domains und DNS](/docs/guides/email/migrate#2-re-point-domains-and-dns) und den [Sandbox-Smoke-Test](/docs/guides/email/migrate#5-verify-in-the-sandbox-before-cutover) im Hauptleitfaden durch. Beides ist anbieterunabhängig.

## Nächste Schritte

- [Sende-Domains](/docs/guides/email/sending-domains): Registrierung, Verifizierungs-Lebenszyklus und die DNS-Einträge, die Sie veröffentlichen
- [Webhooks und Events](/docs/guides/webhooks): Endpoint-Einrichtung und Standard-Webhooks-Verifizierung
- [Test-Sandbox](/docs/guides/email/testing-sandbox): Smoke-Test der neuen Integration vor der Umstellung
- [Suppressionen](/docs/guides/email/suppressions): Überprüfen Sie Ihre importierte Liste und wie wir sie ab jetzt pflegen

## Related resources

- [Getting started with email](/learn/email/getting-started-with-email) (video)
- [Email](/products/email) (product)
- [Build your first integration](/learn/paths/integration) (course)
- [Send your first email](/docs/get-started/send-your-first-email) (docs)

[Get an implementation brief](/learn/workspace?topic=email)
