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
Custom headersmessage.headersheaders: string → string object
Filterable labelsmessage.tags: bare stringstags: { name, value } pairs
Round-trip contextmessage.metadatametadata: arbitrary JSON
Stored templatemessages/send-template + merge_varstemplate + template.parameters
Schedulingsend_atscheduled_at
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: marketing (default) or transactional
Bird-side field caps and defaults (recipient counts, tag and metadata limits) live in 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. Bird's template variables are per message rather than per recipient, so per-recipient merge_vars become one batch 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.

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.

Translate webhook events

Mandrill posts batched event arrays; map the event value to Bird's event vocabulary:
OutcomeMandrillBird
Sent / acceptedsendemail.acceptedemail.processed
Delivered(none)email.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 delivers one event per request, signed per the Standard Webhooks spec rather than Mandrill's X-Mandrill-Signature HMAC over batched arrays. See Webhooks & events for verification.

Cut over

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

Next steps

  • Sending domains: registration, verification lifecycle, and the DNS records you're re-pointing
  • Webhooks & events: endpoint setup and Standard Webhooks verification
  • Testing sandbox: smoke-test the new integration before cutover
  • Suppressions: confirm your imported list and how Bird maintains it from here