Documentation
Sign inGet started

Migrate from Resend

This page maps Resend's POST /emails payload, suppression handling, and Svix-signed webhooks to Bird. Follow the main migration guide in order, and use these mappings for steps 1, 3, and 4. The send payloads have similar fields, but tracking, metadata, and webhook verification require changes.

Map the send call

What it doesResendBird
Senderfromfrom
Recipientsto / cc / bccto / cc / bcc (arrays)
Subjectsubjectsubject
Bodyhtml / texthtml / text (at least one)
Reply-toreply_toreply_to (array)
Custom headersheadersheaders (string → string object)
Filterable labelstags: {name, value} pairstags: {name, value} pairs
Round-trip context(none; tags double as context)metadata: arbitrary JSON
Schedulingscheduled_atscheduled_at
Open/click trackingper-domain dashboard settingtrack_opens / track_clicks (default true)
Category(none)category: marketing (default) or transactional
Our field caps and defaults (recipient counts, tag and metadata limits) live in Sending email.
Porting notes:
  • Tags keep their shape, and metadata is an upgrade. Resend tags are the same {name, value} pairs we use, but their value constraints pushed correlation data into tag values. Here, move correlation context into metadata (arbitrary JSON, echoed back on every webhook event and returned on API reads) and keep tags for filtering. See tags vs metadata.
  • Tracking moves into the payload. Resend toggles open/click tracking per domain in the dashboard. We set track_opens/track_clicks per message (both default true).
  • scheduled_at maps directly, name and all. See scheduled sending. For react, render your React Email templates to HTML in your application (the render function from @react-email/render works unchanged) and send the result as html.
  • Attachments port directly. Resend's attachments (base64 content) map to our attachments array. Set content_id for inline images.
  • Batch sending ports directly. Resend's POST /emails/batch becomes our batch endpoint, with per-entry results in both cases.

Export suppressions

Resend doesn't expose a dedicated suppression-list export. Pull addresses whose last event is bounced or complained. Use the Emails view in the dashboard or your stored webhook events, then run the list through the import loop. If you use Audiences for marketing mail, also carry over contacts marked unsubscribed.

Translate webhook events

OutcomeResendBird
Accepted/processedemail.sentemail.acceptedemail.processed
Deliveredemail.deliveredemail.delivered
Temporary failureemail.delivery_delayedemail.deferred
Permanent bounceemail.bouncedemail.bounced / email.out_of_band_bounce
Spam complaintemail.complainedemail.complained
Blocked/suppressedemail.failedemail.rejected
Openemail.openedemail.opened
Clickemail.clickedemail.clicked
Unsubscribe(none)email.unsubscribed / email.list_unsubscribed
Webhook verification uses a related HMAC construction but different headers. Resend uses svix-id, svix-timestamp, and svix-signature. Bird follows the Standard Webhooks specification with webhook-* headers. Update your verifier to use Bird's signing secret and the Webhooks and events procedure.
One behavioral difference: Resend's events are message-scoped. Our delivery events are recipient-scoped (recipient_id alongside email_id), so a three-recipient send produces three delivery outcomes, one per recipient.

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 we maintain it from here