Documentation
Sign inGet started

Migrate from Mandrill

The provider-specific half of the migration guide: 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 doesMandrill (messages/send)Bird
Authkey in request bodyAuthorization: Bearer bk_... header
Sendermessage.from_email / from_namefrom — string or { "email", "name" }
Recipientsmessage.to[{ email, name, type }]to / cc / bcc — split by the type field
Subjectmessage.subjectsubject
Bodymessage.html / message.texthtml / text (at least one)
Reply-tomessage.headers["Reply-To"]reply_to — array, 1–25
Custom headersmessage.headersheaders — string → string object
Filterable labelsmessage.tags — bare stringstags{ name, value } pairs, max 20
Round-trip contextmessage.metadatametadata — arbitrary JSON, max 2 KB
Open/click trackingmessage.track_opens / track_clickstrack_opens / track_clicks (default true)
Attachmentsmessage.attachments{ type, name, content }attachments{ content_type, filename, content }
Inline imagesmessage.images{ type, name, content }attachments with content_id
Categorysubaccount / tags conventioncategory: transactional (default) or marketing
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{ "name": "category", "value": "welcome" } — so your filters and analytics group the way your Mandrill stats did. metadata ports across directly as JSON.
  • merge_vars / templates render in your app. Mandrill's handlebars-style merge tags and stored templates (messages/send-template) have no Bird equivalent yet — template_id is reserved. Render the final HTML in your application and send it as html.
  • send_at is reserved. Mandrill's scheduled-send send_at maps to Bird's scheduled_at, which is in preview and returns 422 unsupported_feature today — plan around the gap before cutover.
  • 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.

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. Bird sorts them into its own reasons as they're imported.

Translate webhook events

Mandrill posts batched event arrays; map the event value to Bird's event vocabulary:
OutcomeMandrillBird
Sent / acceptedsendemail.acceptedemail.processed
Deliveredemail.delivered
Temporary failuredeferralemail.deferred
Permanent bouncehard_bounceemail.bounced / email.out_of_band_bounce
Soft bouncesoft_bounceemail.deferred (then email.bounced if it gives up)
Spam complaintspamemail.complained
Unsubscribeunsubemail.unsubscribed / email.list_unsubscribed
Rejected/blockedrejectemail.rejected
Openopenemail.opened
Clickclickemail.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 signs per the Standard Webhooks spec rather than Mandrill's X-Mandrill-Signature HMAC. See Webhooks & events for verification.

Cut over

Work through domains & DNS and the sandbox smoke test in the main guide — both are provider-independent.