Migrate from MailerLite to Unitpost

Contacts, suppressions, templates, sending domains and more come over in one import.
What comes with you
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.
| 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. |
| 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, pluscontacts:writeandsegments:writeif your signup form adds contacts, created in API keys. - A second Unitpost key for the migration steps, with
templates:writeandwebhooks:manage, saved asUNITPOST_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
MailerLite keeps sending until the last step, so there is no gap in delivery.
Run the Migration Assistant
Paste the token in 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.
Verify your domain
Open 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_dmarcrecord.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 withPATCH /api/v1/email/templates/{id}.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 answers409, andPATCH /api/v1/contacts/{id or email}updates it.signup.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" });Re-key and enable webhooks
MailerLite signs each delivery with a
Signatureheader, an HMAC-SHA256 of the body. Unitpost signs with awhsec_secret insvix-id,svix-timestampandsvix-signature. Rotate the secret in Webhooks to see it, update your handler, then setstatustoenabled.Test, move traffic, then delete the token
Send each template with
POST /api/v1/email/templates/{id}/test-sendand firePOST /api/v1/webhooks/{id}/testat each endpoint. Send your next campaign from Unitpost to a small segment first, then to everyone, and delete the MailerLite token.
Name changes
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
_dmarcand Unitpost's records. - Delete the MailerLite API token you used for the import.
Facts about MailerLite checked 2026-11-05. Providers change their APIs and plans; check their docs before you rely on a detail.
Questions about leaving MailerLite
Why are my MailerLite emails plain text?
My account is on MailerLite Classic. Can I connect it?
MailerLite rejected a valid token. Why?
Does Unitpost replace MailerSend too?
Leaving MailerLite?
Preview the migration on the free tier
Verify a domain, paste an API key, and see what would come across before anything is written.
