Migration guides
From ResendYour own Amazon SES5 min read

Keep your Resend code. Send through your own Amazon account.

Change two settings, and the app you have sends through mails.ai and out through Amazon SES in your own AWS account, at Amazon’s price. It goes on your AWS bill, where AWS credits can pay for it.

mails.ai answers the calls Resend’s SDKs make to send an email, send a batch and read an email back. Point your SDK at it and connect the Amazon SES account in your own AWS account, and your mail goes out through that account. Amazon bills you for it at its own price, and your mails.ai plan covers the API, the logs, and the bounces, complaints and suppression list.

Two settings, no code changes

Your Resend key becomes a mails.ai key, and the SDK’s base URL points at mails.ai. Set both where your app reads its environment, before it starts:

# .env: the two settings that change
# your mails.ai API key
RESEND_API_KEY=mk_live_…
# where the SDK sends its calls
RESEND_BASE_URL=https://api.mails.ai/resend

The code you have stays as it is:

import { Resend } from "resend";

const resend = new Resend(process.env.RESEND_API_KEY);

const { data, error } = await resend.emails.send({
  from: "Acme <hello@acme.com>",
  to: ["customer@example.com"],
  subject: "Your receipt",
  html: "<p>Thanks for your order.</p>",
});

Go, Ruby and PHP read a base URL the same way. Go and Ruby add the path to it without a slash of their own, so their value ends in one:

SDKSettingValue
Node.jsRESEND_BASE_URLhttps://api.mails.ai/resend
PythonRESEND_API_URLhttps://api.mails.ai/resend
GoRESEND_BASE_URLhttps://api.mails.ai/resend/
RubyRESEND_BASE_URLhttps://api.mails.ai/resend/
PHPRESEND_BASE_URLhttps://api.mails.ai/resend

The key is a mails.ai API key (mk_live_…) from your dashboard; a Resend key does not work here. For a send to go out through your Amazon SES, its from domain must be verified there; How it works covers connecting the account.

What it costs

Resend charges by plan. Amazon charges $0.16 per 1,000 emails on its Essentials plan, the one a new SES account starts on. Sending through your own account comes with mails.ai’s paid plans at no extra charge: Pro ($20 a month) sends up to 200,000 emails a month through it, and Scale ($99) up to 2,500,000.

500,000
Resend Scale$350/ mo
Your Amazon SES + mails.aiAmazon $80 + mails.ai Scale $99$179/ mo
You save $171 a month, 49% less than Resend Scale.

Up to 100,000 emails a month, Resend’s Free and Pro plans cost less than Amazon plus a mails.ai plan, so staying is the cheaper choice. From 200,000 a month this costs less, and the gap grows with your volume.

Resend’s prices are the ones its pricing page showed on October 21, 2026, at the least each volume costs there. At 200,000 that is Pro with pay-as-you-go extra emails, $0.90 per 1,000 past its 100,000, which costs less than Scale. Amazon’s is its Essentials price per email, before what it charges for attachment data and any other SES feature you turn on.

Because Amazon bills the sending to your own AWS account, AWS promotional credits can pay for it. Each grant names the services it covers, so check that yours includes SES. Your mails.ai plan is billed by mails.ai, and credits do not pay for it.

What carries over

  • emails.send with from, to, cc, bcc, one reply_to, subject, html, text, attachments, tags and scheduled_at, and an idempotency key.
  • batch.send: up to 100 emails a call, with Resend’s strict and permissive validation, and no attachments, as on Resend.
  • emails.get: the email in Resend’s shape, with its last event.
  • Errors in Resend’s shape and with Resend’s names for them, and mails.ai’s own error beside each one.

What does not:

  • Stored templates and topics.
  • Custom headers other than In-Reply-To and References. X-Entity-Ref-ID is dropped.
  • Listing, updating and cancelling emails, and Resend’s domains, contacts and broadcasts APIs: those calls answer Resend’s 404.

Two things work differently. Each from address is an agent in your mails.ai workspace, made by the first email it sends with a full-access key. And unless you set reply_to, mails.ai points the Reply-To at the agent, so replies reach you as reply.received events. The compatibility page has every field, answer and error.

How it works

  1. Create one IAM role in your AWS account. POST /v1/ses-connection/setup answers with its trust policy and its permissions policy, filled in for your workspace.
  2. Connect it with POST /v1/ses-connection, naming the role and the SES region you send from. mails.ai checks the role, then makes a configuration set and an SNS topic in your account for the bounce, complaint and delivery reports.
  3. Send. Mail from a domain verified in that region goes out through your account. mails.ai’s rules still refuse prohibited content, phishing links and plainly cold or bulk mail, and each agent’s limits apply. Amazon reports each bounce and complaint back, and the address goes on your suppression list.

Mail from your mails.ai addresses goes out as before. Connecting is done with the API for now: there is no screen for it in the dashboard yet. The setup guide takes you through it.

FAQ

Questions before you connect an account

Why a role, and not access keys?
A role leaves no secret of yours with us: there is nothing for mails.ai to store, leak or rotate. mails.ai assumes it with AWS STS, and only with your workspace’s external ID. Connecting refuses a role that would let mails.ai in without that ID, since any mails.ai workspace that learned the role’s ARN could then send through your account. The role’s permissions are the least that sending and the bounce reports need.
How do I take that access away?
Call DELETE /v1/ses-connection: mails.ai stops sending through your account at once, and removes the configuration set and SNS topic it made there while the role still lets it. Or end it from AWS, by deleting the role or taking mails.ai out of its trust policy. mails.ai keeps the role’s temporary credentials for up to an hour, so a trust policy change holds from the next time it asks for new ones.
What happens to bounces and complaints?
Every send through your account uses the configuration set mails.ai made there, so Amazon reports its bounces, complaints and deliveries back over SNS. A permanent bounce or a complaint puts the address on your workspace’s suppression list, and you get message.bounced or message.complained as you would for any send. Nothing goes out through your account until SNS has confirmed that subscription.
What about the SES sandbox?
A new SES account starts in Amazon’s sandbox, where it sends only to addresses verified in the account. POST /v1/ses-connection/test shows whether yours is still there (account.sandbox). While it is, Amazon refuses mail to anyone else, and the send answers 422 ses_message_rejected with Amazon’s reason. Production access is something you ask Amazon for, in the SES console.
Can AWS credits pay for the sending?
They can. Amazon bills the sending to your own AWS account, and AWS’s terms for promotional credits do not list SES among the services credits never cover. Each grant names the services it does cover, so check yours. Credits do not pay for your mails.ai plan, which mails.ai bills.
Which mail goes out through my account?
Mail from any domain that is a verified identity in the SES region you connected, and from its subdomains, even when you verified the same domain at mails.ai too. Mail from your mails.ai addresses, and from domains verified only at mails.ai, goes out as it always has.
Is there a screen for this in the dashboard?
Not yet. Connecting is done with the API: three calls, set out step by step in the setup guide.

Related

What to read next

Keep your code, change where it sends

Choose Pro or Scale, connect your Amazon SES account, and set two settings.

Get your API key