# Migrate from Mandrill

The provider-specific half of the [migration guide](/docs/guides/email/migrate): how Mandrill's (Mailchimp Transactional) `messages/send` payload, rejection blacklist, and webhooks map onto Bird. Do the steps in the main guide in order; this page is the lookup table for steps 1, 3, and 4.

Two shape changes dominate the port. Mandrill nests everything under a `message` object and authenticates with a `key` in the request body; Bird takes a flat top-level payload and a standard `Authorization: Bearer` header. And Mandrill's recipient `type` (`to`/`cc`/`bcc` as a field on each address) becomes Bird's separate `to`/`cc`/`bcc` arrays.

## Map the send call

| What it does        | Mandrill (`messages/send`)                       | Bird                                                 |
| ------------------- | ------------------------------------------------ | ---------------------------------------------------- |
| Auth                | `key` in request body                            | `Authorization: Bearer bk_...` header                |
| Sender              | `message.from_email` / `from_name`               | `from`: string or `{ "email", "name" }`              |
| Recipients          | `message.to`: `[{ email, name, type }]`          | `to` / `cc` / `bcc`: split by the `type` field       |
| Subject             | `message.subject`                                | `subject`                                            |
| Body                | `message.html` / `message.text`                  | `html` / `text` (at least one)                       |
| Reply-to            | `message.headers["Reply-To"]`                    | `reply_to`: array                                    |
| Custom headers      | `message.headers`                                | `headers`: string → string object                    |
| Filterable labels   | `message.tags`: bare strings                     | `tags`: `{ name, value }` pairs                      |
| Round-trip context  | `message.metadata`                               | `metadata`: arbitrary JSON                           |
| Stored template     | `messages/send-template` + `merge_vars`          | `template` + `template.parameters`                   |
| Scheduling          | `send_at`                                        | `scheduled_at`                                       |
| Open/click tracking | `message.track_opens` / `track_clicks`           | `track_opens` / `track_clicks` (default `true`)      |
| Attachments         | `message.attachments`: `{ type, name, content }` | `attachments`: `{ content_type, filename, content }` |
| Inline images       | `message.images`: `{ type, name, content }`      | `attachments` with `content_id`                      |
| Category            | subaccount / tags convention                     | `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:

- **Flatten and re-auth.** Drop the `message` wrapper (its fields move to the top level) and move the API key out of the body into the `Authorization` header. The `key` field has no Bird equivalent.
- **Split recipients by `type`.** Mandrill marks each recipient `to`, `cc`, or `bcc` on the address object; Bird uses three separate arrays. Bucket the `to` list by its `type` field as you port.
- **Tags become name/value pairs.** Mandrill tags are bare strings (`"welcome"`); Bird tags are `{ name, value }` pairs. Pick a stable `name`, for example `{ "name": "category", "value": "welcome" }`, so your filters and analytics group the way your Mandrill stats did. `metadata` ports across directly as JSON.
- **Stored templates port, with two caveats.** Mandrill's `messages/send-template` becomes 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). Bird's template variables are per message rather than per recipient, so per-recipient `merge_vars` become one [batch](/docs/guides/email/sending-bulk) entry per recipient, each with its own `parameters`. And template authoring on Bird is in preview and not yet open to every workspace, so until yours has it, render the final HTML in your application and send it as `html`.
- **Attachments port directly.** Mandrill's base64 `content` is Bird's `content`, and inline `images` (referenced as `cid:` in the HTML) become `attachments` entries with `content_id`. See [attachments](/docs/guides/email/attachments).

## Export suppressions

Mandrill keeps unwanted addresses on its **rejection blacklist**; pull it with the `rejects/list` API (or export from the Rejection Blacklist view). Each entry carries a reason (`hard-bounce`, `soft-bounce`, `spam`, `unsub`, `custom`); skip the `soft-bounce` rows (transient, not a true suppression) and run the rest through the [import loop](/docs/guides/email/migrate#3-import-suppressions).

## Translate webhook events

Mandrill posts batched event arrays; map the `event` value to Bird's [event vocabulary](/docs/guides/email/events):

| Outcome           | Mandrill      | Bird                                                   |
| ----------------- | ------------- | ------------------------------------------------------ |
| Sent / accepted   | `send`        | `email.accepted` → `email.processed`                   |
| Delivered         | (none)        | `email.delivered`                                      |
| Temporary failure | `deferral`    | `email.deferred`                                       |
| Permanent bounce  | `hard_bounce` | `email.bounced` / `email.out_of_band_bounce`           |
| Soft bounce       | `soft_bounce` | `email.deferred` (then `email.bounced` if it gives up) |
| Spam complaint    | `spam`        | `email.complained`                                     |
| Unsubscribe       | `unsub`       | `email.unsubscribed` / `email.list_unsubscribed`       |
| Rejected/blocked  | `reject`      | `email.rejected`                                       |
| Open              | `open`        | `email.opened`                                         |
| Click             | `click`       | `email.clicked`                                        |

Two differences to code for:

- **Bird reports delivery explicitly.** Mandrill's `send` event means the message was injected; Bird splits acceptance (`email.accepted`/`email.processed`) from the recipient mail server taking it (`email.delivered`).
- **Events are recipient-scoped and signed differently.** Bird's delivery events carry `recipient_id` alongside `email_id` (one stream per recipient), and Bird delivers one event per request, signed per the [Standard Webhooks](https://www.standardwebhooks.com) spec rather than Mandrill's `X-Mandrill-Signature` HMAC over batched arrays. 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