Skip to documentation

Get started

Migrate from Resend

Move domains, webhooks, templates, and contacts to your own Opensend installation.

What stays the same

Opensend follows Resend's HTTP API shape, including bearer authentication and JSON email requests. Read compatibility with Resend for differences and gaps before migrating.

In Node, replace the resend package with Opensend's SDK, @opensendcc/sdk. It keeps Resend's resource and method names and exports Resend as an alias, so most code only needs a new import and your installation's base URL:

bash
pnpm remove resend
pnpm add @opensendcc/sdk
typescript
import { Opensend } from "@opensendcc/sdk";

const opensend = new Opensend(process.env.OPENSEND_API_KEY!, {
  baseUrl: process.env.OPENSEND_BASE_URL!,
});

const { data, error } = await opensend.emails.send({
  from: "Acme <hello@example.com>",
  to: ["you@example.net"],
  subject: "Hello from Opensend",
  html: "<p>Your email is on its way.</p>",
});
if (error) throw new Error(error.message);
console.log(data?.id);

The SDK never reads RESEND_API_KEY or RESEND_BASE_URL, so a leftover Resend setting can't send mail to Resend. From other languages, call the HTTP API.

Set OPENSEND_BASE_URL to your installation’s API origin, such as https://api.mail.example.com, without an /api suffix. The installer prints it as the API base URL.

The same request over HTTP is:

bash
curl "$OPENSEND_BASE_URL/emails" \
  -H "Authorization: Bearer $OPENSEND_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"from":"Acme <hello@example.com>","to":["you@example.net"],"subject":"Hello from Opensend","html":"<p>Your email is on its way.</p>"}'

1. Stand up Opensend

Follow self-host in 10 minutes. Claim the first administrator account and finish AWS SES setup. Your own AWS account sends the mail; its quotas and sandbox restrictions apply.

2. Create an API key

Create an API key on the team receiving your data. Use full access for migration operations. For sending, you can create a separate key with sending access and a domain restriction. Keep keys on your application server.

3. Add and verify domains

Add your domains and publish the DNS records Opensend provides. Sending goes through your own AWS SES, so the DKIM, MAIL FROM, receiving, and tracking records differ from Resend's. Use the new records, not copies of the old provider's values. Follow AWS SES setup and confirm each sending domain is ready before testing mail.

4. Recreate webhooks

Create webhook endpoints for the events your application uses. Replace the Resend signing secret with the new Opensend secret in your receiver. Opensend uses Svix-compatible signature headers; follow verify webhook requests and test verification with the new secret before cutover.

5. Move templates

Recreate your template HTML, text, and variable definitions with create template or the template editor, then publish them before sending. Store the new template IDs in your application. Opensend resource IDs differ from Resend IDs; keep a mapping for any referenced resources.

6. Import contacts, audiences, and segments

Export your contacts as CSV. Recreate audience and segment groupings as Opensend segments; legacy audience API routes alias segment records. Import each group's contacts with the contact import feature.

In Audience → Contacts, choose Import CSV, map columns to email, names, unsubscribed, and existing custom properties, and choose Add to segment. Matching addresses are updated. Preserve unsubscribe choices during import. The contact import API also accepts column mappings, segments, and topic preferences; split files into batches of at most 500 rows and 500 KB of parsed data.

7. Move suppressions

Use batch-add suppressions with a full-access key to add 1–100 addresses per request:

bash
curl "$OPENSEND_BASE_URL/suppressions/batch/add" \
  -H "Authorization: Bearer $OPENSEND_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"emails":["blocked@example.net"]}'

Finish this before sending to imported contacts. Added suppressions are manual entries; the batch API does not import the old provider's bounce/complaint metadata.

8. Switch your application

Replace the API key, base URL, template IDs, segment IDs, and webhook secret. In Node, swap resend for @opensendcc/sdk. If your app calls new Resend() without arguments, set OPENSEND_API_KEY and OPENSEND_BASE_URL: the SDK reads those, not the RESEND_* variables. An explicit key or baseUrl in the constructor takes precedence.

Test the operations your app uses against Opensend. Check compatibility for resource-specific limitations. An accepted email ID means the message entered the queue; check delivery and failure events before switching production traffic.

9. Cut over DNS and warm up

Complete the DNS cutover for the sending and tracking records Opensend shows. If you use receiving, follow receiving setup before changing MX records. Keep the previous provider available while validating delivery and webhooks.

Start with a small volume and increase gradually within your SES quotas. Watch bounces, complaints, and delivery failures in Emails. Opensend has no automatic migration or warm-up command; plan the traffic switch in your application.