> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mailofly.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrating from Resend

> Step-by-step guide to migrate your applications, React Email templates, webhooks, and audiences from Resend to Mailofly.

# Migrating from Resend to Mailofly

If you love modern, developer-centric email APIs but need **multi-account sending identities**, **integrated broadcast campaign management**, **unified subscriber CRM with topics**, or **AI Model Context Protocol (MCP)** integration, migrating from Resend to Mailofly takes only a few minutes.

Because Mailofly shares a modern, developer-first philosophy, our SDK interfaces and payload models are nearly 1:1 compatible.

***

## Key Benefits of Mailofly

* **Multi-Identity Sending**: Send from multiple brands, client sub-accounts, or environments using a single unified API key and lightweight `account_key` routing.
* **Unified Audiences & Broadcasts**: Manage transactional emails and rich visual marketing broadcasts under one roof—no need for separate third-party newsletter tools.
* **Native AI MCP Server**: Connect Mailofly directly to AI assistants (Cursor, Claude Desktop, Antigravity) via `@mailofly/mcp`.
* **Zero Template Lock-in**: Full support for React Email, standard HTML/CSS, and server-side mustache templates.

***

## 1. Domain Setup & DNS

Your existing Resend DKIM records will **not** conflict with Mailofly. Both can operate side-by-side during your transition:

1. In the Mailofly dashboard, go to **[Domains](https://www.mailofly.com/user/domains)** → **Add Domain**.
2. Add the unique DNS records provided by Mailofly:
   * **DKIM**: Unique selector `mailofly._domainkey.yourdomain.com` (coexists with `resend._domainkey`).
   * **SPF**: Add `include:mailofly.com` to your domain's SPF record. If you already have `include:resend.com`, you can temporarily keep both:
     ```dns theme={null}
     v=spf1 include:resend.com include:mailofly.com ~all
     ```
3. Verify the domain in your dashboard.

***

## 2. API & SDK Parameter Mapping

The parameters used to dispatch emails map directly between Resend and Mailofly:

| Resend Field   | Mailofly Field | Description                                                   |
| :------------- | :------------- | :------------------------------------------------------------ |
| `from`         | `from`         | Sender address (e.g. `"Acme <onboarding@example.com>"`)       |
| `to`           | `to`           | Recipient string or array of strings (`["user@example.com"]`) |
| `subject`      | `subject`      | Subject line                                                  |
| `html`         | `html`         | HTML body string                                              |
| `text`         | `text`         | Plaintext fallback string                                     |
| `cc`           | `cc`           | String or array of CC email addresses                         |
| `bcc`          | `bcc`          | String or array of BCC email addresses                        |
| `reply_to`     | `reply_to`     | Reply-To address string or array                              |
| `attachments`  | `attachments`  | Array of attachment objects (`{ filename, content, path }`)   |
| `headers`      | `headers`      | Key-value dictionary of custom email headers                  |
| `tags`         | `tags`         | Key-value pairs or tags for classification and search         |
| `scheduled_at` | `scheduled_at` | ISO 8601 timestamp for scheduled delivery                     |
| *(N/A)*        | `account_key`  | Optional multi-identity / sending account routing key         |

***

## 3. Code Migration Examples

### Node.js / TypeScript

First, replace the package:

```bash theme={null}
# Remove Resend
npm uninstall resend

# Install Mailofly
npm install @mailofly/node
```

Update your sending code:

<CodeGroup>
  ```ts Before: Resend theme={null}
  import { Resend } from "resend";

  const resend = new Resend(process.env.RESEND_API_KEY);

  const data = await resend.emails.send({
    from: "Acme <hello@acme.com>",
    to: ["customer@example.com"],
    subject: "Welcome to Acme",
    html: "<p>Welcome aboard!</p>",
    tags: [
      { name: "category", value: "welcome" }
    ],
  });

  console.log("Resend Email ID:", data.id);
  ```

  ```ts After: Mailofly theme={null}
  import { Mailofly } from "@mailofly/node";

  const mailofly = new Mailofly({
    apiKey: process.env.MAILOFLY_API_KEY!,
  });

  const { id } = await mailofly.emails.send({
    from: "Acme <hello@acme.com>",
    to: ["customer@example.com"],
    subject: "Welcome to Acme",
    html: "<p>Welcome aboard!</p>",
    tags: [
      { name: "category", value: "welcome" }
    ],
    // Optional: specify a sending identity account key
    // account_key: process.env.MAILOFLY_ACCOUNT_KEY,
  });

  console.log("Mailofly Email ID:", id);
  ```
</CodeGroup>

***

### Python

```bash theme={null}
# Remove Resend
pip uninstall resend

# Install Mailofly
pip install mailofly
```

<CodeGroup>
  ```python Before: Resend theme={null}
  import resend
  import os

  resend.api_key = os.environ["RESEND_API_KEY"]

  params = {
      "from": "Acme <hello@acme.com>",
      "to": ["customer@example.com"],
      "subject": "Welcome to Acme",
      "html": "<strong>Welcome!</strong>",
  }

  response = resend.Emails.send(params)
  print("Resend ID:", response["id"])
  ```

  ```python After: Mailofly theme={null}
  from mailofly import Mailofly
  import os

  client = Mailofly(api_key=os.environ["MAILOFLY_API_KEY"])

  response = client.emails.send(
      sender="Acme <hello@acme.com>",
      to=["customer@example.com"],
      subject="Welcome to Acme",
      html="<strong>Welcome!</strong>",
  )

  print("Mailofly ID:", response.id)
  ```
</CodeGroup>

***

### Raw HTTP / cURL

<CodeGroup>
  ```bash Before: Resend theme={null}
  curl -X POST https://api.resend.com/emails \
    -H "Authorization: Bearer re_123456789" \
    -H "Content-Type: application/json" \
    -d '{
      "from": "Acme <hello@acme.com>",
      "to": ["customer@example.com"],
      "subject": "Welcome",
      "html": "<p>Hello!</p>"
    }'
  ```

  ```bash After: Mailofly theme={null}
  curl -X POST https://api.mailofly.com/emails \
    -H "Authorization: Bearer mf_live_xxxxxxxxxxxxxxxx" \
    -H "Content-Type: application/json" \
    -d '{
      "from": "Acme <hello@acme.com>",
      "to": ["customer@example.com"],
      "subject": "Welcome",
      "html": "<p>Hello!</p>"
    }'
  ```
</CodeGroup>

***

## 4. React Email Support

If you authored your email components using `@react-email/components`, **no refactoring is required**. You can render your React templates to HTML using `@react-email/render` and pass the markup directly to Mailofly:

```tsx theme={null}
import { Mailofly } from "@mailofly/node";
import { render } from "@react-email/render";
import { WelcomeEmail } from "./emails/WelcomeEmail";

const mailofly = new Mailofly({
  apiKey: process.env.MAILOFLY_API_KEY!,
});

// Render React Email to HTML
const emailHtml = await render(<WelcomeEmail name="Jane Doe" />);

const { id } = await mailofly.emails.send({
  from: "Acme <hello@acme.com>",
  to: ["jane@example.com"],
  subject: "Welcome to Acme!",
  html: emailHtml,
});
```

***

## 5. Webhooks Migration

Both Resend and Mailofly adhere to modern security standards for webhook signatures.

### Event Names Mapping

| Event Description      | Resend Event             | Mailofly Event           |
| :--------------------- | :----------------------- | :----------------------- |
| Email Sent             | `email.sent`             | `email.sent`             |
| Successfully Delivered | `email.delivered`        | `email.delivered`        |
| Delivery Delayed       | `email.delivery_delayed` | `email.delivery_delayed` |
| Email Bounced          | `email.bounced`          | `email.bounced`          |
| Marked as Spam         | `email.complained`       | `email.complained`       |
| Email Opened           | `email.opened`           | `email.opened`           |
| Link Clicked           | `email.clicked`          | `email.clicked`          |

### Verifying Webhook Signatures in Next.js / Express

```ts theme={null}
import { Webhook } from "svix";

export async function POST(req: Request) {
  const payload = await req.text();
  const svix_id = req.headers.get("svix-id");
  const svix_timestamp = req.headers.get("svix-timestamp");
  const svix_signature = req.headers.get("svix-signature");

  const wh = new Webhook(process.env.MAILOFLY_WEBHOOK_SECRET!);
  
  let evt;
  try {
    evt = wh.verify(payload, {
      "svix-id": svix_id!,
      "svix-timestamp": svix_timestamp!,
      "svix-signature": svix_signature!,
    }) as any;
  } catch (err) {
    return new Response("Invalid signature", { status: 400 });
  }

  const { type, data } = evt;

  switch (type) {
    case "email.delivered":
      console.log("Email delivered:", data.email_id);
      break;
    case "email.bounced":
      console.warn("Email bounced for:", data.to, "Reason:", data.bounce_reason);
      break;
  }

  return new Response("OK", { status: 200 });
}
```

***

## 6. Audiences & Contacts Migration

If you use Resend Audiences to store subscriber lists:

1. **Export from Resend**:
   * Go to **Resend Dashboard → Audiences**.
   * Export your contact list to a `.csv` file.
2. **Import into Mailofly**:
   * Navigate to **[Audiences > Contacts](https://www.mailofly.com/user/audience)**.
   * Click **Import CSV**.
   * Map standard columns (`email`, `first_name`, `last_name`, `unsubscribed`) and any custom metadata properties.
   * Assign imported contacts to relevant **Topics** (e.g., Product Updates, Weekly Newsletter).

***

## Migration Checklist

* [ ] Add domain to Mailofly and configure DNS records (`mailofly._domainkey`).
* [ ] Verify SPF includes `include:mailofly.com`.
* [ ] Swap `@mailofly/node` (or `mailofly` Python package) in your codebase.
* [ ] Update environment variables with `MAILOFLY_API_KEY`.
* [ ] Point webhook endpoints to Mailofly Webhooks in the dashboard.
* [ ] Export and import contacts & suppressions into Mailofly.
* [ ] Remove legacy Resend SPF entries once 100% of traffic is switched.


## Related topics

- [Migrating from Postmark](/guides/migrations/postmark.md)
- [Migrating from Mailgun](/guides/migrations/mailgun.md)
- [Migrating from Amazon SES](/guides/migrations/aws-ses.md)
- [Migrating from Mailchimp & Mandrill](/guides/migrations/mailchimp.md)
- [Migrating from Twilio SendGrid](/guides/migrations/sendgrid.md)
