Envello
Tutorial

Migrating from Resend to Envello

Envello Team·2026-07-16·6 min read

Envello's SDK is deliberately shaped like Resend's: same method names, same request fields, same idea of what a "send" call looks like. That's not an accident, it's the whole point of the migration path. Most of the work here is mechanical, and the parts that aren't are the same parts that matter for any provider switch: DNS and cutover.

1. Run the codemod

npx @envello/migrate rewrites your import statements and client instantiation across the codebase. import { Resend } from 'resend' becomes import { Envello } from 'envello', and every new Resend(...) call updates with it.

Method calls like .emails.send() and .emails.batch() don't change, since Envello's SDK mirrors Resend's shapes on purpose. Review the diff like you would any other automated refactor before merging it.

2. Re-verify your sending domain

Add the SPF, DKIM, and DMARC records Envello generates for you. Most teams keep the same from domain, so this is usually one extra TXT record alongside the ones you already have, not a replacement of them, while both providers are live during the transition.

Don't remove your old provider's DNS records until you've confirmed the cutover worked. A dangling SPF include for a provider you've stopped using is harmless; deleting one too early, mid-migration, isn't.

3. Swap the API key

Replace your Resend API key environment variable with ENVELLO_API_KEY. Request shapes are compatible for the common fields (from, to, subject, html, text, cc, bcc), so the rest of your integration keeps working without further changes.

One real gap: Envello's API doesn't accept a react prop directly the way some marketing examples suggest. Render your React Email component to an HTML string first (with @react-email/render's render() function) and pass that string as html. If you were already doing this with Resend, nothing changes here.

4. Watch the logs during cutover

Send a small percentage of traffic first if you're risk-averse, then widen it. Envello's log search shows delivery status in real time, and logs stick around for 90 days by default on every plan, not just the top tier, so you can go back and check a delivery from weeks ago without having to have thought ahead about it.

  • Idempotency keys work the same way: pass idempotencyKey and a retried call with the same key and body replays the original response instead of sending twice.
  • Batch sending is a single request against POST /emails/batch, up to 100 emails, with per-item success/failure reporting, not a client-side loop.
  • If you use send-later scheduling, the field is send_at, an ISO 8601 timestamp.

What doesn't carry over automatically

The codemod handles imports and instantiation, not application logic. Webhook endpoint URLs, any code that inspects a Resend-specific response shape, and dashboard-side integrations (Slack alerts, admin tooling) still need a manual look. Budget for that even though the SDK swap itself is close to instant.

Envello

EU-hosted transactional email, done right by default.