Migrate from Resend
Moving from Resend to CamelMailer keeps the shape you already know: a single API key per server, an SDK send call with the same fields, and DKIM-signed domains. The main differences are that the HTML field is html_body, plain text has its own text_body, and marketing lists become broadcast streams with per-stream subscribers.
What maps to what
Resend and CamelMailer line up cleanly on the transactional path. The marketing side maps to broadcast streams, and webhooks cover the outgoing delivery lifecycle.
| Resend | CamelMailer |
|---|---|
API key (re_..., Authorization: Bearer) | Server API credential in the X-Server-API-Key header (SDKs set it for you). See Credentials. |
| Verified domain with DKIM and SPF | Sending domain with a per-domain DKIM key, an SPF include, and a verification TXT record. |
resend.emails.send(...) | camelmailer.emails.send(...) or POST /api/v2/server/messages. |
html and text fields | html_body and text_body. |
| Audiences, contacts, and broadcasts | Broadcast streams with per-stream subscribers and one-click unsubscribe. |
| Unsubscribe and bounce handling | Suppressions per server, honored before every send. |
Webhooks (email.sent, email.delivery_delayed, email.bounced) | RSA-signed webhooks: MessageSent, MessageDelayed, MessageDeliveryFailed, MessageHeld. |
Set up your domain and DNS
As on Resend, you verify a domain and publish DKIM and SPF before you can send from it. Add each domain to the CamelMailer server and publish the three TXT records it generates: a verification record, an SPF include, and the per-domain DKIM record. CamelMailer mints its own DKIM key, so publish its record alongside the Resend one and keep both live until the cutover is complete. Full steps are in Sending domains.
The send call
The Node SDK swap is close to line for line. Rename the client, point at the CamelMailer API key, and change html to html_body (add text_body for the plain part). Both SDKs return a { data, error } result, so nothing throws for a rejected request.
import { Resend } from 'resend';
const resend = new Resend(process.env.RESEND_API_KEY);
const { data, error } = await resend.emails.send({
from: 'billing@acme.com',
to: 'ada@example.com',
subject: 'Your receipt',
html: '<p>Thanks for your purchase.</p>',
});import { CamelMailer } from 'camelmailer';
const camelmailer = new CamelMailer(process.env.CAMELMAILER_API_KEY);
const { data, error } = await camelmailer.emails.send({
from: 'billing@acme.com',
to: 'ada@example.com',
subject: 'Your receipt',
html_body: '<p>Thanks for your purchase.</p>',
text_body: 'Thanks for your purchase.',
});If you call Resend over HTTP rather than the SDK, the equivalent CamelMailer request is a POST to the messages endpoint with the X-Server-API-Key header:
POST https://app.camelmailer.com/api/v2/server/messages
X-Server-API-Key: <your CamelMailer server key>
Content-Type: application/json
{
"from": "billing@acme.com",
"to": ["ada@example.com"],
"subject": "Your receipt",
"html_body": "<p>Thanks for your purchase.</p>",
"text_body": "Thanks for your purchase."
}A successful send returns 201 Created with one entry per recipient. See Sending email for batch sends, attachments, and custom headers, and the Node.js SDK reference for the full client.
Audiences and broadcasts
Resend audiences and broadcasts map to broadcast streams. A broadcast stream carries marketing mail and enforces the rules that go with it: every recipient must be an opted-in subscriber of that stream, each message gets a per-recipient one-click unsubscribe (RFC 8058) plus an unsubscribe footer, and the stream can run on its own IP pool for reputation. Import your contacts as subscribers of the target stream, then send to the stream the same way you send transactional mail, setting the stream field to the broadcast stream permalink.
SMTP drop-in
For any service that already speaks SMTP, CamelMailer is a straight relay. Create an SMTP-type credential on the server and use its key as the password:
Host: the SMTP hostname of your CamelMailer installation Port: 587 (STARTTLS) or 25 (plain with STARTTLS); 465 for implicit TLS Auth: AUTH PLAIN or AUTH LOGIN User: any value (accepted but unused for these mechanisms) Pass: an SMTP-type credential key from the server
SMTP submission reaches the same pipeline as the HTTP API. See SMTP for the session details.
Cutover checklist
- Create a CamelMailer server and a server API credential.
- Add each sending domain and publish its verification, SPF, and DKIM records; keep the Resend DKIM record live too.
- Verify each domain and confirm the health check is green.
- Swap the client to
camelmailer, set the new API key, and renamehtmltohtml_body(addtext_body). - Point webhook subscriptions at CamelMailer and map the event names.
- Import contacts as subscribers of the matching broadcast stream for any marketing mail.
- Send a test message and confirm it is accepted and delivered.
- Flip traffic, then keep the Resend account warm briefly before you close it.
