# Migrate from Mailjet

The provider-specific half of the [migration guide](/docs/guides/email/migrate): how Mailjet's Send API v3.1 payload, blocklist, and Event API map onto Bird. Do the steps in the main guide in order — this page is the lookup table for steps 1, 3, and 4.

The biggest structural change is the envelope. Mailjet wraps every send in a `Messages` array of PascalCase objects (`POST /v3.1/send`); Bird takes one flat, lowercase JSON object per [`POST /v1/email/messages`](/docs/api/reference/create-email-message), and many independent messages go to the [batch endpoint](/docs/guides/email/sending-bulk) instead of the `Messages` array.

## Map the send call

| What it does       | Mailjet (Send API v3.1)                                          | Bird                                                        |
| ------------------ | ---------------------------------------------------------------- | ----------------------------------------------------------- |
| Sender             | `From` — `{ "Email", "Name" }`                                   | `from` — string or `{ "email", "name" }`                    |
| Recipients         | `To` / `Cc` / `Bcc` — `[{ "Email", "Name" }]`                    | `to` / `cc` / `bcc` — arrays, max 50 each                   |
| Subject            | `Subject`                                                        | `subject`                                                   |
| Body               | `TextPart` / `HTMLPart`                                          | `text` / `html` (at least one)                              |
| Reply-to           | `ReplyTo` — `{ "Email", "Name" }`                                | `reply_to` — array, 1–25                                    |
| Custom headers     | `Headers`                                                        | `headers` — string → string object                          |
| Round-trip context | `EventPayload` (string), echoed on events                        | `metadata` — arbitrary JSON, max 2 KB                       |
| Your own send ID   | `CustomID`                                                       | `Idempotency-Key` header + `tags`/`metadata`                |
| Attachments        | `Attachments` — `{ "ContentType", "Filename", "Base64Content" }` | `attachments` — `{ "content_type", "filename", "content" }` |
| Inline images      | `InlinedAttachments` — with `ContentID`                          | `attachments` with `content_id`                             |
| Tracking           | account/template setting                                         | `track_opens` / `track_clicks` (default `true`)             |
| Category           | —                                                                | `category`: `marketing` (default) or `transactional`        |

Porting notes:

- **Unwrap the `Messages` array.** A single Mailjet send is one entry in `Messages`; on Bird that's the whole request body. If you batch several entries in one `Messages` array, that maps to Bird's [batch endpoint](/docs/guides/email/sending-bulk) (up to 100 messages), not to repeated fields in one request.
- **Case changes from PascalCase to lowercase.** Every field renames: `HTMLPart` → `html`, `TextPart` → `text`, `From.Email` → `from.email`. This is mechanical but touches every send.
- **`EventPayload` becomes `metadata`.** Mailjet echoes a single `EventPayload` string back on every event; Bird echoes structured `metadata` (JSON) and `tags` on every webhook, so you can split correlation data into typed fields. See [tags vs metadata](/docs/guides/email/sending-email#tags-vs-metadata).
- **`CustomID` splits in two.** Mailjet's `CustomID` does double duty as a dedup key and a correlation handle. On Bird, use the [`Idempotency-Key`](/docs/guides/idempotency) header for safe retries and put your own correlation ID in `metadata`.
- **Templates render in your app.** Mailjet's `TemplateID` + `Variables` (server-hosted templates with `TemplateLanguage`) have no Bird equivalent yet — `template_id` is [reserved](/docs/guides/email/sending-email#reserved-fields). Render your template to HTML before sending and pass it as `html`.
- **Attachments port directly** — Mailjet's `Base64Content` is Bird's base64 `content`, and `InlinedAttachments` + `ContentID` become `attachments` entries with `content_id`. See [attachments](/docs/guides/email/attachments).

## Export suppressions

Mailjet keeps unreachable and unwanted addresses on its **blocklist** (hard/soft bounces and blocked sends) and tracks spam and unsubscribe signals separately. Export the blocked and bounced addresses from **Statistics → Contacts**, or pull them through the [contact management API](https://dev.mailjet.com/email/reference/contacts/), and run the list through the [import loop](/docs/guides/email/migrate#3-import-suppressions). If you send marketing mail, also carry over contacts marked unsubscribed so those preferences survive the move.

## Translate webhook events

Mailjet's [Event API](https://dev.mailjet.com/email/guides/webhooks/) posts one trigger per event type. The mapping to Bird's [event vocabulary](/docs/guides/email/events):

| Outcome          | Mailjet   | Bird                                             |
| ---------------- | --------- | ------------------------------------------------ |
| Sent / accepted  | `sent`    | `email.accepted` → `email.processed`             |
| Delivered        | —         | `email.delivered`                                |
| Permanent bounce | `bounce`  | `email.bounced` / `email.out_of_band_bounce`     |
| Blocked          | `blocked` | `email.rejected`                                 |
| Spam complaint   | `spam`    | `email.complained`                               |
| Open             | `open`    | `email.opened`                                   |
| Click            | `click`   | `email.clicked`                                  |
| Unsubscribe      | `unsub`   | `email.unsubscribed` / `email.list_unsubscribed` |

Two differences worth coding for:

- **Bird reports delivery explicitly.** Mailjet's `sent` event means the message left Mailjet; Bird splits acceptance (`email.accepted`/`email.processed`) from the recipient mail server actually taking the message (`email.delivered`), so you get a distinct delivered signal.
- **Events are recipient-scoped.** Mailjet keys events by `MessageID`; Bird's delivery events carry `recipient_id` alongside `email_id`, so a multi-recipient send produces one event stream per recipient. Bird signs deliveries per the [Standard Webhooks](https://www.standardwebhooks.com) spec — see [Webhooks & events](/docs/guides/webhooks) for verification.

## Cut over

Work through [domains & DNS](/docs/guides/email/migrate#2-re-point-domains-and-dns) and the [sandbox smoke test](/docs/guides/email/migrate#5-verify-in-the-sandbox-before-cutover) in the main guide — both are provider-independent.

## Next steps

- [Sending domains](/docs/guides/email/sending-domains) — registration, verification lifecycle, and the DNS records you're re-pointing
- [Webhooks & events](/docs/guides/webhooks) — endpoint setup and Standard Webhooks verification
- [Testing sandbox](/docs/guides/email/testing-sandbox) — smoke-test the new integration before cutover
- [Suppressions](/docs/guides/email/suppressions) — confirm your imported list and how Bird maintains it from here