Envello
Resend alternative

Switching from Resend? Move your transactional email to Envello

A step-by-step guide: DNS setup alongside your existing records, the sending-code swap, a dual-send cutover window, and verification with 90 days of searchable logs on Pro.

Envello's API and Node SDK use the same request shape as Resend's: the same method names (emails.send, emails.batch) and the same field names. For most codebases the change is the import, the client constructor and the API key. A codemod does the first two for you.

Before: Resend Node SDK
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: "Welcome",
  html: renderedHtml,
});
After: Envello Node SDK
import { Envello } from "envello";

const envello = new Envello(process.env.ENVELLO_API_KEY);

await envello.emails.send({
  from: "Acme <[email protected]>",
  to: "[email protected]",
  subject: "Welcome",
  html: renderedHtml,
});
Before: Resend REST
curl -X POST https://api.resend.com/emails \
  -H "Authorization: Bearer $RESEND_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "Acme <[email protected]>",
    "to": "[email protected]",
    "subject": "Welcome",
    "html": "<p>Welcome aboard</p>"
  }'
After: Envello REST
curl -X POST https://api.envello.dev/emails \
  -H "Authorization: Bearer $ENVELLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "Acme <[email protected]>",
    "to": "[email protected]",
    "subject": "Welcome",
    "html": "<p>Welcome aboard</p>"
  }'
Field mapping

Resend fields and their Envello equivalents

ResendEnvello
from, to, subject, html, text, cc, bccSame names, same types
reply_to (REST) / replyTo (newer Node SDKs)reply_to
react (Node SDK)Render with @react-email/render first, pass the string as html
scheduled_at / scheduledAtsend_at (ISO 8601)
headers, attachmentsheaders, attachments (filename, content as base64, contentType)
Idempotency-Key headerIdempotency-Key header (idempotencyKey option in the Node SDK)
POST /emails/batchPOST /emails/batch, up to 100 emails, per-item results
tagsNo equivalent yet; drop them or record them in your own logs

Run the codemod

npx @envello/migrate "src/**/*.{ts,tsx,js,jsx}" rewrites import { Resend } from "resend" to import { Envello } from "envello" and every new Resend(...) to new Envello(...). Add --dry-run to preview. It doesn't touch method calls, which don't need to change, or field names like replyTo, which do.

What still needs a manual look

Webhook consumers (Envello sends delivered, bounced, complained, opened and clicked events, HMAC-signed), any code that reads Resend-specific response fields, and dashboard-side integrations such as Slack alerts.

Four steps

The migration, end to end

1. Add Envello DNS records alongside your existing Resend records

Verify your sending domain in Envello and add the SPF include, DKIM CNAMEs, and the return-path CNAME Envello generates. Keep your existing records in place: both providers can authenticate the same domain at once, which is what makes a safe cutover possible. Only remove the old records after Envello has been the sole sender for a few days.

2. Swap the sending call

Point your outbound path at Envello's SDK. The request shape (from, to, subject, html, text, cc, bcc, reply_to, headers, attachments) mirrors the common transactional-API pattern, so the diff in most codebases is the import line, the client instantiation, and the API key environment variable. Templates rendered client-side (React Email, MJML, plain string) plug straight into the html field.

3. Dual-send during the cutover window

Route a small percentage of traffic to Envello first, or fork production sends so each message goes through both providers to non-critical recipients while you verify. Envello's log search shows every send, bounce, complaint, open, and click for 90 days on Pro (7 days on Free, up to 365 days on Scale) so you can confirm parity before flipping the rest of the traffic.

4. Cut over and retire Resend

Once Envello has handled a full week of production traffic without regressions on your key deliverability metrics (bounce rate, complaint rate, delivered rate per domain), route 100% of sends through Envello. Export your Resend suppression list and add each address with Envello's POST /suppressions so previously-suppressed recipients stay suppressed. Remove the old DNS records last.

Sending HTML from React components? See the React Email guide for how render() plugs straight into the html field.

FAQ

Migration questions

Can I keep sending through Resend while I test Envello?+

Yes. Both providers authenticate the same domain via separate DKIM selectors and their own SPF include, so parallel sending is safe as long as each provider's records are in place. Keep the old records until Envello has been the sole production sender for a few days, then remove them.

What happens to my suppression list?+

Export it from Resend and add each address with POST /suppressions (a full-access API key works, one address per request), or one by one in the dashboard. If you skip this step, addresses that Resend had marked as bounced or complained can send successfully through Envello on day one and generate the same bounce or complaint again, which harms deliverability. Import first, cut over second.

Do I need to change my webhook consumer?+

Yes, at least the payload shape. Envello's webhooks send delivered, bounced, complained, opened, and clicked events with HMAC-signed payloads; the field names and signature header are documented at envello.dev/docs. If your current consumer branches on your existing provider's specific bounce-subtype taxonomy, decide upfront how each subtype maps to Envello's simpler event set before writing the new handler.

How long does the whole migration take?+

For a codebase with a single central sending path, most teams complete the code change in under an hour. Add DNS propagation (up to 48 hours, usually much less), a dual-send verification window (a few days), and one week of production monitoring before retiring the old provider. Plan for two to three weeks end-to-end, not one afternoon.

Free tool

Check your own GDPR/DPA gaps before you switch

8 questions covering data residency, retention, and subprocessor documentation, the same things a security questionnaire asks.

Run the free checklist →
Ready to migrate?

Start free and migrate at your own pace.