> ## Documentation Index
> Fetch the complete documentation index at: /docs/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:

```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);
```

***

### Python

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

# Install Mailofly
pip install mailofly
```

```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)
```

***

### Raw HTTP / cURL

```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>"
  }'
```

***

## 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.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.