Migration Guides
Migrate from Resend
Step-by-step guide to migrate from Resend to send0.
Overview
send0's API is designed to be familiar to Resend users. Most concepts map 1:1 — the migration is straightforward.
1. Install the SDK
Replace resend with send0:
# Before
npm install resend
# After
npm install send0Python:
# Before
pip install resend
# After
pip install send02. Update the client
TypeScript:
// Before (Resend)
import { Resend } from 'resend';
const resend = new Resend('re_...');
// After (send0)
import { Send0 } from 'send0';
const send0 = new Send0('sk_live_...');Python:
# Before (Resend)
import resend
resend.api_key = "re_..."
# After (send0)
from send0 import Send0
client = Send0("sk_live_...")3. Update send calls
The send API is nearly identical. Key differences:
| Resend | send0 | Notes |
|---|---|---|
resend.emails.send() | send0.emails.send() | Same interface |
react parameter | template parameter | Use template IDs or JSX components |
scheduledAt (ISO string) | scheduledAt (Date object in TS) | send0 accepts Date objects |
tags (array of {name, value}) | tags (object {key: value}) | Simpler key-value format |
| No batch endpoint | send0.emails.batch() | send0 supports batch sends natively |
TypeScript:
// Before (Resend)
const email = await resend.emails.send({
from: 'hello@acme.com',
to: 'user@example.com',
subject: 'Welcome!',
html: '<p>Hello</p>',
tags: [{ name: 'category', value: 'onboarding' }],
});
// After (send0)
const email = await send0.emails.send({
from: 'hello@acme.com',
to: 'user@example.com',
subject: 'Welcome!',
html: '<p>Hello</p>',
tags: { category: 'onboarding' },
});Python:
# Before (Resend)
email = resend.Emails.send({
"from": "hello@acme.com",
"to": "user@example.com",
"subject": "Welcome!",
"html": "<p>Hello</p>",
})
# After (send0)
email = client.emails.send(
from_address="hello@acme.com",
to="user@example.com",
subject="Welcome!",
html="<p>Hello</p>",
)4. Update webhook verification
TypeScript:
// Before (Resend) — uses Svix
import { Webhook } from 'svix';
const wh = new Webhook(secret);
const event = wh.verify(body, headers);
// After (send0) — built-in
import { Send0 } from 'send0';
const event = Send0.webhooks.verify(body, headers, secret);Python:
# After (send0)
from send0 import Webhooks
event = Webhooks.verify(body, headers, secret)5. Update domain verification
The domain verification flow is similar. send0 requires DKIM, SPF, and optionally DMARC records.
// Add domain
const domain = await send0.domains.create({ domain: 'mail.acme.com' });
// Configure DNS records from domain.dns_records
// Then verify
const result = await send0.domains.verify(domain.id);6. Concept mapping
| Resend concept | send0 equivalent |
|---|---|
API key (re_...) | API key (sk_live_..., sk_test_..., sk_restr_...) |
| Audiences | Contacts with tags |
| Domains | Domains |
| Emails | Emails |
| Webhooks (Svix) | Webhooks (native HMAC-SHA256) |
| React Email | send0 JSX components (send0/components) |
7. Feature comparison
| Feature | Resend | send0 |
|---|---|---|
| Transactional email | Yes | Yes |
| Marketing email | No | Yes (with daily cap + one-click unsubscribe) |
| Batch send | Yes (100 max) | Yes (100 max) |
| Contacts/audiences | Yes | Yes |
| Templates | No (React only) | Yes (server-side + JSX) |
| Webhook verification | Svix | Native HMAC-SHA256 |
| Test-mode API keys | No | Yes (sk_test_… never delivers) |
| CLI | No | Yes (send0 emails send, events tail, …) |
| IP allowlists | No | Yes |
| Restricted API keys | No | Yes (scoped permissions) |
| Audit log | No | Yes |
| Free tier | 3,000/month | 3,000/month |