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.

ResendCamelMailer
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 SPFSending 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 fieldshtml_body and text_body.
Audiences, contacts, and broadcastsBroadcast streams with per-stream subscribers and one-click unsubscribe.
Unsubscribe and bounce handlingSuppressions 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.

Before: Resend (Node)
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>',
});
After: CamelMailer (Node)
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:

After: CamelMailer (HTTP)
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:

SMTP settings
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 rename html to html_body (add text_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.
Next steps: Sending email for the full send path, Credentials & routes for API and SMTP keys, and Sending domains for DNS and DKIM.