Documentation
Sign inGet started

Migrate from Amazon SES

The provider-specific half of the migration guide: how the SES v2 SendEmail call, account-level suppression list, and SNS-based event notifications map onto Bird. Do the steps in the main guide in order — this page is the lookup table for steps 1, 3, and 4.

Map the send call

SES splits a send across Destination, Content, and configuration-set plumbing; Bird's POST /v1/email/messages is one flat payload:
What it doesSES (SendEmail v2)Bird
SenderFromEmailAddressfrom
RecipientsDestination.*Addressesto / cc / bcc (arrays, max 50 each)
SubjectContent.Simple.Subjectsubject
BodyContent.Simple.Body.Html/Texthtml / text (at least one)
Reply-toReplyToAddressesreply_to (array, 1–25)
Custom headersContent.Simple.Headersheaders (string → string object)
Filterable labelsEmailTagstags{name, value} pairs, max 20
Round-trip contextmetadata — arbitrary JSON, max 2 KB
Open/click trackingconfiguration settrack_opens / track_clicks (default true)
IP pooldedicated IP pool (config set)ip_pool (ipp_... or ipp_shared)
Categorycategory: transactional (default) or marketing
Porting notes:
  • Configuration sets dissolve into per-message fields. Tracking, IP pool, and event routing were configuration-set concerns on SES; on Bird the first two are payload fields and event routing is a webhook subscription.
  • Auth changes from SigV4 to a bearer token. No request signing — Authorization: Bearer bk_.... Drop the AWS SDK credential chain from this code path.
  • Content.Raw (MIME) has no equivalent — Bird builds the message from structured fields. If you assemble raw MIME for attachments, note attachments is reserved and returns 422 unsupported_feature today; the full reserved list is in Sending email.
  • SES sandbox ≠ Bird sandbox. SES's sandbox restricts who you can send to; Bird's mail sandbox is a simulator with magic addresses — no allowlisting, and nothing is delivered.

Export suppressions

Export the account-level suppression list and run it through the import loop:
  • GET /v2/email/suppressed-destinations (paginate with NextToken; each entry carries BOUNCE or COMPLAINT as the reason)

Translate webhook events

SES publishes events through SNS or EventBridge; Bird POSTs signed webhooks directly, so the SNS topic, subscription-confirmation handshake, and message-envelope unwrapping all go away. The event names map like this:
OutcomeSESBird
Accepted/processedSendemail.acceptedemail.processed
DeliveredDeliveryemail.delivered
Temporary failureDeliveryDelayemail.deferred
Permanent bounceBounceemail.bounced / email.out_of_band_bounce
Spam complaintComplaintemail.complained
Blocked/suppressedemail.rejected
OpenOpenemail.opened
ClickClickemail.clicked
UnsubscribeSubscriptionemail.list_unsubscribed
email.rejected is new relative to SES: Bird reports suppressed recipients visibly (status rejected, rejection_reason: recipient_suppressed) rather than counting them into the send-and-bounce cycle — add a handler for it.
In place of SNS message verification, Bird signs per the Standard Webhooks specification — HMAC headers on the delivery itself; the verification recipe is in Webhooks & events.

Cut over

Work through domains & DNS and the sandbox smoke test in the main guide — both are provider-independent. One SES-specific note for the DNS step: SES's "Easy DKIM" CNAMEs stay in place during the transition — Bird's DKIM TXT record uses its own selector, so the two coexist.