Marketing & Migration
Replace your existing ESP in an afternoon. Migrate templates, contacts, and suppressions — then connect your marketing tools.
Every migration script is a self-contained Node.js ESM module. Install the one you need, set two environment variables, and run it. Nothing is deleted from your old provider — the scripts are read-only against the source and write-only against Mailgrid.
Migrate from SendGrid
The SendGrid migration script pulls your transactional templates, marketing contacts, global suppressions, and verified sending domains and recreates them in Mailgrid.
Install
npx mailgrid-migrate@latest integrations/migrate-sendgrid/
Run
SENDGRID_API_KEY=SG.xxxxxxxxxxxxxxxxxxxxxxxx \ MAILGRID_API_KEY=mb_live_xxxxxxxxxxxxxxxxxxxx \ node migrate.mjs
What migrates
- Transactional templates — all versions; active version is set as default
- Marketing contacts — email, first/last name, custom fields, list memberships
- Global suppressions — unsubscribes, bounces, spam reports, blocks
- Verified sending domains — domain records are re-verified through Mailgrid/SES DKIM flow
Estimated time
Under 5 minutes for < 100k contacts. Large lists (> 500k) may take 15–30 minutes due to SendGrid's paginated contacts API.
After migration
Re-add DKIM CNAMEs for any migrated domains — SES issues new DKIM tokens. Update your application's SENDGRID_API_KEY references to MAILGRID_API_KEY and swap the base URL to https://api.mailgrid.space/api.
SendGrid uses {{"{{"}}variable{{"}}"}} (Handlebars-like) but with their own substitution tag format. The script auto-converts {{"{{"}}variable{{"}}"}} tags to Mailgrid Handlebars. Review complex conditional blocks manually.
Migrate from Mailchimp
Exports all Mailchimp audiences, their members, merge fields, and tags into Mailgrid contacts and lists.
Install & run
npx mailgrid-migrate@latest integrations/migrate-mailchimp/ MAILCHIMP_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-us21 \ MAILGRID_API_KEY=mb_live_xxxxxxxxxxxxxxxxxxxx \ node migrate.mjs
What migrates
- Audiences → Lists — each Mailchimp audience becomes a Mailgrid list; audience name is preserved
- Members → Contacts — email, merge fields (FNAME, LNAME, custom), subscription status
- Tags — member tags are stored as Mailgrid contact tags
- Unsubscribes / cleaned addresses — added to Mailgrid suppressions automatically
Estimated time
~3 minutes per 50k members. The Mailchimp export API is rate-limited to 10 requests/second.
Mailchimp Transactional (formerly Mandrill) templates are not included in the standard Mailchimp API. Run the SendGrid migration script against your Mandrill account instead (Mandrill exposes a compatible API).
Migrate from Brevo (Sendinblue)
Migrates contacts, contact lists, email templates, and transactional suppressions from Brevo.
Install & run
npx mailgrid-migrate@latest integrations/migrate-brevo/ # Dry run first — prints a summary without writing anything BREVO_API_KEY=xkeysib-xxxxxxxxxxxxxxxxxxxx \ MAILGRID_API_KEY=mb_live_xxxxxxxxxxxxxxxxxxxx \ node migrate.mjs --dry-run # Full migration BREVO_API_KEY=xkeysib-xxxxxxxxxxxxxxxxxxxx \ MAILGRID_API_KEY=mb_live_xxxxxxxxxxxxxxxxxxxx \ node migrate.mjs
What migrates
- Contacts — all attributes, list memberships, opt-in status
- Lists — contact lists with their names and folder groupings
- Email templates — HTML body, subject, sender name; template IDs are remapped and printed to stdout
- Transactional suppressions — hard bounces, spam complaints, unsubscribes
Estimated time
~10 minutes for a typical Brevo account. Use --dry-run first to verify counts before committing.
Brevo contacts with only a phone number (no email) are skipped. The script prints a count of skipped records at the end.
Migrate from Mailgun
Migrates Mailgun sending domains, mailing lists, and mailing list members to Mailgrid.
Install & run
npx mailgrid-migrate@latest integrations/migrate-mailgun/ MAILGUN_API_KEY=key-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \ MAILGUN_DOMAIN=mg.yourdomain.com \ MAILGRID_API_KEY=mb_live_xxxxxxxxxxxxxxxxxxxx \ node migrate.mjs
What migrates
- Domains — all verified sending domains; new SES DKIM records are printed for re-verification
- Mailing lists — list addresses, descriptions, access levels
- Mailing list members — email, name, subscription status, custom vars
Estimated time
2–5 minutes. Mailgun's API supports bulk exports, so member migration is fast regardless of list size.
If your Mailgun account is on the EU region, set MAILGUN_API_URL=https://api.eu.mailgun.net in addition to your API key.
Migrate from Postmark
Migrates Postmark email templates and suppression lists into Mailgrid.
Install & run
npx mailgrid-migrate@latest integrations/migrate-postmark/ POSTMARK_SERVER_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \ MAILGRID_API_KEY=mb_live_xxxxxxxxxxxxxxxxxxxx \ node migrate.mjs
What migrates
- Email templates — all templates including layouts; Postmark's
{{"{{"}}variable{{"}}"}}syntax is preserved (it's already Handlebars-compatible) - Suppressions — bounces, spam complaints, and manual suppressions across all streams
Estimated time
Under 3 minutes for most accounts. Postmark templates are small and the suppressions endpoint paginates efficiently.
Postmark message streams map to Mailgrid's transactional/broadcast split. Suppressions from broadcast streams are imported to Mailgrid's marketing suppression list; transactional stream suppressions go to the transactional list.
Migrate from Resend
Migrates Resend domains, audiences, and audience contacts to Mailgrid.
Install & run
npx mailgrid-migrate@latest integrations/migrate-resend/ RESEND_API_KEY=re_xxxxxxxxxxxxxxxxxxxxxxxxxxxx \ MAILGRID_API_KEY=mb_live_xxxxxxxxxxxxxxxxxxxx \ node migrate.mjs
What migrates
- Domains — all verified domains; new DKIM CNAMEs are output for re-verification via SES
- Audiences → Lists — each Resend audience becomes a Mailgrid list
- Contacts — email, first/last name, subscription status per audience
Estimated time
Under 5 minutes. Resend's audience API is fully paginated and the script batches contact imports at 500/request.
Migrate from MailerLite
Migrates MailerLite subscriber groups to Mailgrid lists and subscribers to Mailgrid contacts.
Install & run
npx mailgrid-migrate@latest integrations/migrate-mailerlite/ MAILERLITE_API_KEY=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9... \ MAILGRID_API_KEY=mb_live_xxxxxxxxxxxxxxxxxxxx \ node migrate.mjs
What migrates
- Groups → Lists — every MailerLite group becomes a named Mailgrid list
- Subscribers → Contacts — email, name, custom fields, group memberships, subscription status
- Unsubscribed / bounced / junk — added to Mailgrid suppression list
Estimated time
~5 minutes per 100k subscribers. MailerLite's API rate limit is 120 requests/minute; the script respects this with automatic back-off.
The script targets the new MailerLite API (api.mailerlite.com). If you're on MailerLite Classic, set MAILERLITE_CLASSIC=true to use the legacy endpoint instead.
Klaviyo
A Cloudflare Worker receives Klaviyo Flow webhook events and forwards them to Mailgrid as transactional sends. Use this to trigger order confirmation, shipment, and cart-recovery emails from Klaviyo Flows without changing your ESP.
Install the worker
npx mailgrid-migrate@latest integrations/klaviyo/ # Configure secrets npx wrangler secret put MAILGRID_API_KEY npx wrangler secret put KLAVIYO_SIGNING_SECRET # Deploy npx wrangler deploy
Supported Klaviyo Flow events
- Placed Order — triggers your
order-confirmationMailgrid template - Fulfilled Order — triggers
shipment-notificationwith tracking data - Started Checkout — triggers
cart-recoverywith a 1-hour delay (configurable)
Configure the Klaviyo Flow action
In your Klaviyo Flow, add a Webhook action after the trigger:
{
"event": "{{ event.MetricName }}",
"email": "{{ person.EmailAddress }}",
"name": "{{ person.FirstName }}",
"data": {{ event|json }}
}
Set the webhook URL to your deployed Worker URL (e.g. https://klaviyo-mailgrid.youraccount.workers.dev). The Worker validates the X-Klaviyo-Signature header before forwarding.
Edit template-map.js in the worker directory to customize which Mailgrid template ID is triggered for each Klaviyo event type. The default map covers the three events above.
Customer.io
A Cloudflare Worker handles Customer.io webhook delivery events and a sync script keeps suppressions in both platforms consistent.
Deploy the worker
npx mailgrid-migrate@latest integrations/customer-io/ npx wrangler secret put MAILGRID_API_KEY npx wrangler secret put CUSTOMERIO_WEBHOOK_SECRET npx wrangler deploy
In Customer.io, go to Settings → Reporting Webhooks and add your Worker URL. Enable the email.bounced, email.unsubscribed, and email.spam_complaint event types.
Suppression sync
The included sync script exports contacts from Customer.io and imports unsubscribes/bounces into Mailgrid — and vice versa — keeping suppression lists aligned across both platforms.
CUSTOMERIO_APP_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \ MAILGRID_API_KEY=mb_live_xxxxxxxxxxxxxxxxxxxx \ node sync-suppressions.mjs # Run direction: customerio→mailgrid (default), mailgrid→customerio, or both DIRECTION=both node sync-suppressions.mjs
Contact export / import
# Export Customer.io segment to Mailgrid list CUSTOMERIO_SEGMENT_ID=12345 \ MAILGRID_LIST_ID=lst_xxxxxxxxxxxxxxxxxxxx \ node export-segment.mjs
The Worker also accepts inbound Mailgrid webhook events (email.bounced, email.unsubscribed) and calls the Customer.io /unsubscribe endpoint to keep both platforms in sync without the manual sync script.
During migration, you can run Customer.io and Mailgrid in parallel. The Worker deduplicates sends using a 24-hour idempotency key so the same message is not delivered twice.