Resend vs AWS SES
Amazon SES is the cheapest way to send email at scale — fractions of a cent per message — and it sits inside the AWS ecosystem you may already run on, with IAM auth, CloudWatch metrics, and regional endpoints. The trade-off is that SES is infrastructure, not a product: you manage your own sending reputation, configuration sets, and bounce handling, and the console is unmistakably AWS. Resend is a managed product with opinionated defaults, a clean dashboard, and React Email support, priced per-message at a premium over raw SES. In the unified message model the gap is scheduling and structured data: Resend supports sendAt natively while SES has no scheduled-send API, and neither exposes per-message metadata, so both lean on tags for categorization.
Message field support
Field support as encoded in Email SDK's own adapter capability matrix — the same data the SDK uses to reject sends that would silently drop fields.
| Message field | Resend | AWS SES |
|---|---|---|
| CC recipients | ✓ | ✓ |
| BCC recipients | ✓ | ✓ |
| Reply-To address | ✓ | ✓ |
| Custom headers | ✓ | ✓ |
| Attachments | ✓ | ✓ |
| Tags | ✓ | ✓ |
| Metadata | — | — |
| Scheduled sending (sendAt) | ✓ | — |
Fallback compatibility
Failing over from Resend to AWS SES loses: scheduled sending (sendat). Email SDK rejects the fallback send for messages that use these fields instead of dropping them silently.
Same code, either provider
With Email SDK the send call is identical for both providers — only the adapter import changes:
import { createEmailClient } from "@opencoredev/email-sdk";
import { resend } from "@opencoredev/email-sdk/resend";
const client = createEmailClient({
adapters: [resend({ apiKey: process.env.RESEND_API_KEY! })],
});
await client.send({
from: "hello@yourdomain.com",
to: "user@example.com",
subject: "Welcome!",
html: "<p>It works.</p>",
});Or run both, with automatic fallback:
import { createEmailClient } from "@opencoredev/email-sdk";
import { resend } from "@opencoredev/email-sdk/resend";
import { ses } from "@opencoredev/email-sdk/ses";
const client = createEmailClient({
adapters: [
resend({ apiKey: process.env.RESEND_API_KEY! }),
ses({
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
region: "us-east-1",
}),
],
defaultAdapter: "resend",
fallback: ["ses"],
});FAQ
- Can I switch from Resend to AWS SES without rewriting my email code?
- Yes. With Email SDK both providers share one typed send() call and one message shape, so switching from Resend to AWS SES is a one-line adapter change plus an API key. The SDK fails fast if a message uses a field AWS SES does not support, so nothing is silently dropped.
- Which message fields does Resend support that AWS SES doesn't?
- Resend supports scheduled sending (sendat) in the unified message shape, which AWS SES does not.
- Can I use AWS SES as a fallback for Resend?
- Partially. Email SDK checks field support before every send: a fallback from Resend to AWS SES is rejected for messages using scheduled sending (sendat). Messages that avoid those fields fail over cleanly.
Adapter docs
Setup guides: Resend adapter and AWS SES adapter. Sending from your own domain? Verify SPF, DKIM, and DMARC with the free email DNS checker.