How to switch from Resend in 2 minutes (and keep your code)
Short answer: Point Resend's SDK at SendFox. Set RESEND_BASE_URL to https://api.sendfox.com/transactional/resend and RESEND_API_KEY to your SendFox key, verify your domain, and deploy. Your resend.emails.send() calls don't change.
Why switch? Mostly price: SendFox is $15 a month for 50,000 emails, Resend Pro is $20 for 50,000, and SendFox's free plan covers 3,000 a month. (Full breakdown in Resend pricing explained.) Some teams also want a second provider they can fail over to without maintaining two integrations. Since your code doesn't change, you can try it on staging in an afternoon.
Before you start: what carries over
| Resend feature | On SendFox |
|---|---|
resend.emails.send() | Works as is |
resend.batch.send() | Works as is, up to 100 emails a call |
resend.emails.get() | Works as is |
to, cc, bcc as string or array | Both accepted: up to 50 in to, plus 50 more across cc and bcc |
tags | The first tag's value becomes the SendFox tag |
Webhooks and webhooks.verify() | Works with the Resend format and your SendFox secret |
| Idempotency keys | Supported for 24 hours |
attachments, scheduled_at | Not yet. Refused with a 422, never sent without them |
Step 1: Get a SendFox API key
Sign up free and open Transactional. Your first API key is created when the page loads, and the code snippets on that page are already filled in with it. Copy it into your secrets manager: the full key stays visible on that page for an hour, then only its name is shown.
Step 2: Verify your sending domain
Add the domain you send from (for example mail.yourapp.com) and paste the DNS records SendFox shows into your DNS provider. They're the same kind of DKIM and SPF records Resend asked you for. Most DNS providers pick them up in a few minutes.
Until the domain is verified you can still test: the sandbox sender can email your own address and SendFox's test addresses.
Step 3: Change two environment variables
RESEND_BASE_URL=https://api.sendfox.com/transactional/resend
RESEND_API_KEY=<your SendFox transactional key>
Resend's Node SDK reads RESEND_BASE_URL on its own. If your SDK doesn't, pass the same URL as the base URL option when you create the client. Your send code stays exactly as it was:
import { Resend } from 'resend';
const resend = new Resend(process.env.RESEND_API_KEY);
await resend.emails.send({
from: 'Acme <[email protected]>',
to: '[email protected]',
subject: 'Your login code',
html: '<p>Your code is 123456</p>',
tags: [{ name: 'category', value: 'login_code' }],
});
Message ids now start with tm_. If you store ids, make sure the column takes that shape.
Step 4: Switch your webhook
Under Transactional > Webhooks, add the same URL your Resend webhook posts to and choose the Resend format. Events arrive as email.sent, email.delivered, email.delivery_delayed, email.bounced, email.complained and email.failed, signed with the same svix-* headers. Replace the signing secret in your environment with the SendFox one and webhooks.verify() keeps passing.
Failed deliveries are retried after 1 minute, 15 minutes, 2 hours and 18 hours, with the same event id, so dedupe on it.
Step 5: Send a test and watch the feed
Send to [email protected], [email protected] or [email protected] to see each outcome, including the webhook, without touching a real inbox. Test addresses never count against your quota. The live feed on the Transactional page shows every message and its event timeline, and rejected requests get their own log with the reason.
Things to know after you switch
- Quota counts recipients, same as Resend: every
to,ccandbccaddress is one email. - Rate limit: 5 requests a second. A 429 carries a
Retry-Afterheader to back off by. - Overage is off by default. On the $15 plan you can turn it on at $0.50 per 1,000 with a cap, so nothing bills past 50,000 unless you choose to.
- Open and click tracking is per tag, and it's always off for login codes, magic links and password resets, because mailbox scanners click those links and burn the token.
- Errors tell you the fix. Every error response has a
fixfield that says what to change.
Full reference: Transactional API docs, also as one Markdown page for AI coding agents. Product overview: the SendFox email API. Still deciding? Compare the best Resend alternatives.
FAQ
Do I need to change my code to switch from Resend?
No. SendFox accepts Resend's request shape at /transactional/resend. resend.emails.send, resend.batch.send and resend.emails.get keep working once RESEND_BASE_URL and RESEND_API_KEY point at SendFox.
Will my Resend webhook handler still work?
Yes. Pick the Resend format for your SendFox webhook and the events arrive with the same types (email.delivered, email.bounced and so on) and the same svix signature headers. Swap in the SendFox signing secret.
What does not carry over?
Attachments and scheduled sends are not supported yet. Requests that use them get a 422 validation error instead of being sent without them, so you will see it in testing.
Can I move back to Resend?
Yes. Your code never changed, so moving back is the same two variables in reverse.
Send your first email in two minutes.
Free for 3,000 emails a month. $15 a month for 50,000. Already on Resend? Change two environment variables.
Get your free API key