# 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                                |
| Subject            | `Subject`                                                       | `subject`                                                  |
| Body               | `TextPart` / `HTMLPart`                                         | `text` / `html` (at least one)                             |
| Reply-to           | `ReplyTo`: `{ "Email", "Name" }`                                | `reply_to`: array                                          |
| Custom headers     | `Headers`                                                       | `headers`: string → string object                          |
| Round-trip context | `EventPayload` (string), echoed on events                       | `metadata`: arbitrary JSON                                 |
| Your own send ID   | `CustomID`                                                      | `Idempotency-Key` header + `tags`/`metadata`               |
| Stored template    | `TemplateID` + `Variables`                                      | `template` + `template.parameters`                         |
| 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           | (none)                                                          | `category`: `marketing` (default) or `transactional`       |

Bird-side field caps and defaults (recipient counts, tag and metadata limits) live in [Sending email](/docs/guides/email/sending-email).

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), 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 event, 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`.
- **Stored templates port, with one caveat.** Mailjet's `TemplateID` + `Variables` map to Bird's `template` field (referenced by ID or name) with values in `template.parameters`; see [sending with a template](/docs/guides/email/sending-email#sending-with-a-template). Template authoring on Bird is in preview and not yet open to every workspace, so until yours has it, render your template to HTML in your application and pass it as `html`. Templating logic beyond variable substitution (Mailjet's `TemplateLanguage` conditionals and loops) needs to render in your application either way.
- **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 Mailjet's contact statistics pages, 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                                             |
| ------------------ | --------- | ------------------------------------------------ |
| Accepted/processed | (none)    | `email.accepted` → `email.processed`             |
| Delivered          | `sent`    | `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 the pre-delivery stages explicitly.** Mailjet's `sent` fires once the recipient's mail server takes the message, which corresponds to Bird's `email.delivered`. Bird also emits `email.accepted` and `email.processed` before it, so you see a send progressing before the delivery confirmation; don't treat those earlier events as delivery.
- **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