Migration guide

Move from Resend without rewriting your code

You keep the Resend SDK and your sending code. You publish new DNS records for your domain, change the key and base URL and give your webhook handler a new secret. We do this with you on the first day.

  1. Add your domain and publish its DNS records

    Add each sending domain in your dashboard or with POST /domains. We give you a DKIM TXT record, an MX and an SPF TXT record for the MAIL FROM subdomain and a suggested DMARC record. The domain can send as soon as DKIM verifies.

    Your Resend DKIM records can stay while you move. Resend probably uses send.yourapp.com for its MAIL FROM records, so pick another label with custom_return_path, such as mail, and both can run side by side.

    yourapp.comVerified

    TXTDKIM recordVerified
    MXmail.yourapp.comVerified
    TXTmail.yourapp.comVerified
    TXT_dmarc.yourapp.comSuggested
  2. Create an API key

    Create a key in your dashboard or with POST /api-keys. A sending key can only send, and you can limit it to one domain. We show the key once, so put it in your secrets manager straight away.

    New API keyShown once

    yourapp_live_4f2a8cQ1bZ7nLx0Vt3Rd

    Sending onlyyourapp.com only
  3. Change the key and the base URL

    These are the only two changes to your sending code. In Node you can also set RESEND_BASE_URL to https://manzo.dev and leave the code alone. Single sends, batches, schedules and templates work as they are.

    Moving from Resend
    import { Resend } from "resend";const resend = new Resend(resendKey);const resend = new Resend(manzoKey, {  baseUrl: "https://manzo.dev",});await resend.emails.send({  from: "Your app <hi@yourapp.com>",  to: "ada@example.com",  subject: "Your sign-in code",  html: "<p>Your code is 482913.</p>",});
  4. Move your webhooks

    Create each endpoint in your dashboard or with POST /webhooks. You get a new signing secret that starts with whsec_. Put it where your handler reads the old one.

    Event names, payloads and signatures match Resend's, so resend.webhooks.verify() keeps working. Send a test event from your dashboard to confirm it.

    Deliveriesyourapp.com/hooks/email

    Test event200
    email.delivered200
    email.bounced200
  5. Keep your React Email templates

    The Node SDK renders the react field on your server before it calls us, so your components work as they are. If you call the API without the SDK, render them yourself and send html and text.

    Without the SDK
    import { render } from "@react-email/render";
    
    const html = await render(<Welcome name="Ada" />);
    const text = await render(<Welcome name="Ada" />, {
      plainText: true,
    });
  6. Bring your suppression list

    Collect the addresses that bounced or complained at Resend and add them with POST /suppressions/batch/add, up to 1,000 at a time. If you skip this, we will send to addresses you already know are bad and your bounce rate starts high.

    Add addresses you should not email
    curl -X POST https://manzo.dev/suppressions/batch/add \
      -H "Authorization: Bearer $MANZO_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{"emails": ["old@example.com"]}'
  7. Send a test, then switch production

    Send from staging and find the email in your log. Then point production at us. We watch the first 48 hours with you.

    Keep your Resend plan until a full day of production mail looks right. To go back, change the key and base URL back.

    Email log

    ada@example.comDelivered
    tunde@example.comDelivered

What is different after you move

Most things carry over. These do not, and it is better to know before you switch.

What changes when you move from Resend
AreaWith us
Open and click trackingNot available yet. Creating a domain with open_tracking or click_tracking set to true returns an error.
SMTPNot available. Send through the API.
Receiving emailNot available.
Email bodiesWe delete them once the email is accepted for delivery, so GET /emails/:id returns null for html and text.
RegionsOne, in the United States. Leave region out when you add a domain.
AttachmentsUp to 25 MB in total on each email.
LogsKept for 90 days by default, and up to 365 days if you ask.
BillingOne naira invoice each month, paid by bank transfer.

Want us to do this with you?

Tell us which domains you send from and how many emails a month. We will set a date and move you.