---
title: "Migrate from MailerLite to Unitpost"
description: "Leave MailerLite in order: import subscribers, groups, segments, bounces and spam reports, rebuild designs from plain-text drafts, re-verify DNS, move signups."
url: https://www.unitpost.com/migration/mailerlite
section: Migration
updated: 2026-11-07
---
# Migrate from MailerLite to Unitpost

To leave MailerLite, paste a MailerLite API token into Unitpost's Migration Assistant. It imports subscribers with their status and custom fields, groups and segments as segments, bounced and spam-complaint subscribers as suppressions, and webhooks. MailerLite's API returns no email HTML, so campaigns arrive as plain-text drafts you rebuild in the editor. Unconfirmed subscribers are left out. Only current MailerLite accounts connect: Classic accounts from before March 2022 use a different API.

Contacts, suppressions, templates, sending domains and more come over in one import.

## What comes with you

| Data | Result | What happens |
| --- | --- | --- |
| Contacts | Imports | Subscribers import with MailerLite's `name` field as the first name, `last_name` as the last name and every other field as a custom field, plus their opt-in date and signup source. |
| Unsubscribes and consent | Imports | Unsubscribed, bounced and junk subscribers import unsubscribed. Unconfirmed subscribers never confirmed double opt-in, so MailerLite can't email them either, and they are left out. |
| Suppressions (bounces and complaints) | Imports | MailerLite has no separate suppression list; a subscriber's status is the record. Bounced subscribers import as bounce suppressions and junk subscribers, who marked an email as spam, as complaint suppressions. |
| Groups and segments | Partly imports | Groups become static segments with their members. MailerLite segments come over as a snapshot of today's members, because MailerLite's API doesn't return their filter rules. |
| Templates | Partly imports | MailerLite's REST API has no templates endpoint and returns campaign emails as subject and plain text only. Draft campaigns and your 25 most recent sent campaigns arrive as plain-text drafts with `{$name}` style variables rewritten; rebuild each design in the editor. |
| Sending domains | Partly imports | MailerLite's API has no domains endpoint. Domains seen on your campaigns' sender addresses are recreated as verifying with new DKIM keys; add any others in [Domains](/dashboard/email/domains). |
| Webhooks | Partly imports | Webhooks import switched off with a new signing secret. Subscriber, bounce, spam, open and click events map to ours; `campaign.sent` and automation events don't. MailerLite limits webhooks on its Free plan, so they may not be readable there. |
| Topics | Rebuild | MailerLite has no topics. If readers picked groups in your preference center, create a topic for each here. |
| API keys | Rebuild | MailerLite tokens stay at MailerLite. Create Unitpost API keys instead, and delete the token you used for the import. |
| SMS consent | Rebuild | MailerLite's API has no SMS data. Its `phone` field comes over as a custom field, not as the contact's SMS number, and carries no consent. Add numbers and record consent before you text anyone. |
| Send history and analytics | Stays behind | Campaign reports, opens, clicks and subscriber activity stay at MailerLite. |
| Automations | Stays behind | MailerLite automations stay; the preview lists them with their email count. Rebuild them in Unitpost Automations, which are in early access, or send those emails from your code. |
| Forms, landing pages, websites and products | Stays behind | Not read. Unitpost has no hosted forms, landing pages or websites, and doesn't sell to readers. |

## Before you start

- A MailerLite API token: Integrations → MailerLite API → Generate new token. MailerLite shows it once.
- Leave IP restrictions off for this token. MailerLite lets you limit a token to certain IP addresses, and a restricted token refuses the importer.
- A current MailerLite account. Accounts created before March 2022 that still run on MailerLite Classic use a separate API and key, which the importer doesn't read.
- MailerLite tokens have no read-only setting and stop working if the user who made them leaves the account. The importer only reads; delete the token when the move is done.
- A Unitpost API key for your app with `emails:send`, plus `contacts:write` and `segments:write` if your signup form adds contacts, created in [API keys](/dashboard/api-keys).
- A second Unitpost key for the migration steps, with `templates:write` and `webhooks:manage`, saved as `UNITPOST_MIGRATION_KEY`. Keep it out of your app and revoke it once the move is done.
- Access to your DNS host.

## The cut-over plan

### 1. Run the Migration Assistant

Paste the token in [Settings → Migration](/dashboard/settings/migration). The preview counts subscribers by status, lists the unconfirmed ones it leaves out, and shows which campaigns arrive as plain text. Suppressions are written before contacts, so bounced and junk addresses land unsubscribed.

### 2. Verify your domain

Open [Domains](/dashboard/email/domains), add any domain the importer didn't find, and publish the records shown: MX and SPF on `unitpost.<your domain>` and a DKIM TXT under `_domainkey`. They don't replace MailerLite's records, so both stay authenticated while you move. Keep your single `_dmarc` record.

### 3. Rebuild designs from the plain-text drafts

Each campaign arrives as a plain-text draft with its subject. Rebuild the layout in the visual editor, or paste your own HTML in code mode. `{$name}` became `{{first_name}}`, `{$last_name}` `{{last_name}}`, `{$email}` `{{email}}` and `{$unsubscribe}` `{{unsubscribe_url}}`; `|default('…')` fallbacks are dropped, and `{$url}`, `{$forward}` and `{$preferences}` stay for you to replace. Publish with `PATCH /api/v1/email/templates/{id}`.

### 4. Point signups at Unitpost

MailerLite forms, landing pages and websites keep adding subscribers to MailerLite. Send signups from your own form with `POST /api/v1/contacts`, and add the contact to the segment that replaced each group. MailerLite's create call updates an existing subscriber; here an existing contact answers `409`, and `PATCH /api/v1/contacts/{id or email}` updates it.

```ts
// Before: MailerLite
await fetch("https://connect.mailerlite.com/api/subscribers", {
  method: "POST",
  headers: { Authorization: "Bearer " + process.env.MAILERLITE_API_KEY, "content-type": "application/json" },
  body: JSON.stringify({
    email: "user@example.com",
    fields: { name: "Ada", last_name: "Lovelace" },
    groups: [GROUP_ID],
  }),
});

// After: Unitpost
import { Unitpost } from "unitpost";
const unitpost = new Unitpost(process.env.UNITPOST_API_KEY);
const { error } = await unitpost.contacts.create({
  email: "user@example.com",
  first_name: "Ada",
  last_name: "Lovelace",
});
// 409 conflict: the contact already exists. MailerLite's call upserts; update with contacts.update.
if (error && error.code !== "conflict") throw new Error(error.message);
// A group became a static segment.
await unitpost.segments.addMember("seg_123", { contact: "user@example.com" });
```

### 5. Re-key and enable webhooks

MailerLite signs each delivery with a `Signature` header, an HMAC-SHA256 of the body. Unitpost signs with a `whsec_` secret in `svix-id`, `svix-timestamp` and `svix-signature`. Rotate the secret in [Webhooks](/dashboard/webhooks) to see it, update your handler, then set `status` to `enabled`.

### 6. Test, move traffic, then delete the token

Send each template with `POST /api/v1/email/templates/{id}/test-send` and fire `POST /api/v1/webhooks/{id}/test` at each endpoint. Send your next campaign from Unitpost to a small segment first, then to everyone, and delete the MailerLite token.

## Same ideas, new names

| MailerLite | Unitpost | Note |
| --- | --- | --- |
| Subscriber | Contact |  |
| Group | Segment (static) |  |
| Segment | Segment (dynamic) | Imported as a snapshot; rebuild the filter. |
| Field | Contact field |  |
| `name` field | First name |  |
| Junk subscriber | Suppression (complaint) |  |
| Unconfirmed subscriber | Not imported |  |
| Campaign | Campaign |  |
| Automation | Automations | In early access. |
| Preference center (`{$preferences}`) | Unsubscribe preference page |  |
| `{$name}` | `{{first_name}}` |  |

## API calls

| MailerLite API | Unitpost API | Note |
| --- | --- | --- |
| POST /api/subscribers | POST /api/v1/contacts | MailerLite's call upserts; here an existing contact answers 409 and you update it with PATCH. |
| PUT /api/subscribers/{id} | PATCH /api/v1/contacts/{id or email} | MailerLite's PUT removes groups you leave out; segment membership here changes only through the segment calls. |
| GET /api/subscribers | GET /api/v1/contacts |  |
| POST /api/subscribers/{subscriber_id}/groups/{group_id} | POST /api/v1/segments/{id}/contacts |  |
| GET /api/groups | GET /api/v1/segments |  |
| GET /api/segments | GET /api/v1/segments |  |
| GET /api/fields | GET /api/v1/contact-fields |  |
| POST /api/campaigns | POST /api/v1/email/campaigns |  |
| POST /api/webhooks | POST /api/v1/webhooks |  |
| `Authorization: Bearer` on connect.mailerlite.com | `Authorization: Bearer <api key>` |  |

## Webhook events

| MailerLite event | Unitpost event | Note |
| --- | --- | --- |
| subscriber.created | contact.created |  |
| subscriber.updated, subscriber.unsubscribed, subscriber.active | contact.updated |  |
| subscriber.added_to_group, subscriber.removed_from_group | segment.joined, segment.left | The importer maps them to `contact.updated`; the segment events are the closer match. |
| subscriber.deleted | contact.deleted |  |
| subscriber.bounced | email.bounced |  |
| subscriber.spam_reported | email.complained |  |
| campaign.open | email.opened |  |
| campaign.click | email.clicked |  |
| campaign.sent | email.sent | Ours fires per recipient. |
| subscriber.automation_triggered, subscriber.automation_completed | No equivalent |  |

## Before you cancel MailerLite

- Export subscribers as CSV, including unconfirmed ones, which the importer leaves out.
- Save the designs you still use; MailerLite's API can't hand them over.
- Write down each automation, with its trigger, steps and delays.
- Move your forms, landing pages and websites, or keep MailerLite for them.
- Delete MailerLite's DNS records once no mail goes through MailerLite. Keep `_dmarc` and Unitpost's records.
- Delete the MailerLite API token you used for the import.

Facts about MailerLite checked 2026-11-05.

## FAQ

### Why are my MailerLite emails plain text?

MailerLite's REST API returns a campaign's subject and plain-text version, never its HTML, and has no templates endpoint. The importer brings what the API gives. Rebuild each design in Unitpost's visual editor or paste your own HTML into code mode.

### My account is on MailerLite Classic. Can I connect it?

Not directly. Classic accounts, created before March 2022, use a separate API and key that the importer doesn't read. MailerLite lets a Classic account move to the current MailerLite; do that first, or export subscribers as CSV and import them in Contacts.

### MailerLite rejected a valid token. Why?

Most often the token is limited to certain IP addresses, which refuses the importer. Create a token without IP restrictions. A token also stops working when the user who made it leaves the account.

### Does Unitpost replace MailerSend too?

MailerLite sends transactional email through MailerSend, a separate product. Unitpost sends transactional and marketing email on one API and one bill, so one account covers both. The importer reads MailerLite only, not MailerSend.

## Related

- [Migrate from Kit to Unitpost](https://www.unitpost.com/migration/kit): Leave Kit in order: import subscribers, tags, bounces, broadcasts and sequence emails with a V4 key, rebuild segments and automations, then move signups.
- [Migrate from beehiiv to Unitpost](https://www.unitpost.com/migration/beehiiv): Leave beehiiv in order: copy the suppression list by hand, import subscribers, publications, segments and posts, rewrite merge tags, then move signups.
- [Migrate from Klaviyo to Unitpost](https://www.unitpost.com/migration/klaviyo): Leave Klaviyo in order: import profiles, consent, lists, segments and templates with a Read-Only key, rebuild flows, then move your signups and sends.
