JustEmails
PricingSign inStart free trialStart free
Tutorials··11 min read

Migrate from SparkPost to JustEmails Without Losing Deliverability

SparkPost to JustEmails migration—zero dropped emails, reputation intact.

By JustEmails Platform Team
Contents
  1. What You'll Have at the End
  2. Prerequisites
  3. Step 1: Map Your SparkPost Configuration
  4. Step 2: Add JustEmails DNS Records
  5. Step 3: Export and Convert Templates
  6. Step 4: Build the Migration Wrapper
  7. Step 5: Configure Webhooks
  8. Step 6: The 72-Hour Watch Period
  9. Step 7: Cut Over to JustEmails
  10. Common Errors and Fixes
  11. What You Save
  12. Next Steps
  13. Frequently Asked Questions
  14. Why migrate from SparkPost to JustEmails?
  15. Will I lose my domain's sender reputation during migration?
  16. How do SparkPost subaccounts map to JustEmails?
  17. Can I keep using SparkPost templates with JustEmails?
  18. Try JustEmails

The renewal email from Bird (the company that absorbed SparkPost through the MessageSystems acquisition chain) landed in my inbox last month. The new pricing structure required a $500/month minimum commitment — for a service sending maybe 8,000 transactional emails monthly.

I get it. SparkPost built serious infrastructure. Their deliverability team knew their stuff. But somewhere between MessageSystems buying SparkPost and Bird buying MessageSystems, the pricing model shifted hard toward enterprise. Small senders like me got squeezed out. Classic acquisition math — buy the product, squeeze the margins, watch the little guys scramble.

Here's the thing: I was already paying $49/year for JustEmails to host mailboxes across five product domains. The plan includes 1,000 transactional emails per month and an API that looks suspiciously similar to what I'd been using on SparkPost. Add $25/year for another 10K/month tier? That's $74/year total versus $6,000/year.

The math wasn't subtle. My CFO (me, in a different Slack channel) approved instantly.

This guide covers the migration I ran over a week. The goal was zero dropped emails and — critically — preserving the sender reputation I'd built over three years of consistent transactional sending.

What You'll Have at the End

A working transactional email setup on the JustEmails API with your existing domain fully authenticated, webhooks receiving delivery events, and SparkPost decommissioned. Your domain reputation stays intact because you're migrating the provider, not the sending identity.

Real hands-on time: maybe three hours spread across five days. Most of that is waiting for DNS propagation and watching logs like a nervous parent.

Prerequisites

Before starting:

  • A JustEmails account with your sending domain added (if you're using JustEmails for mailboxes, the domain is already there)
  • DNS access for your sending domain — Cloudflare, Route53, Namecheap, wherever
  • Admin access to your SparkPost account (grab API keys, export templates, note current DNS records)
  • Your application codebase where transactional emails originate
  • Basic familiarity with REST APIs and your stack's HTTP client

Check your current SparkPost volume first. Log into SparkPost, note your monthly sends. JustEmails' base $49/year plan includes 1,000/month. Each additional $25/year tier adds 10K/month. Size your tier before you start.

Note your daily peak too, because the daily ceiling binds before the monthly allowance does: sends are capped per account per day at 20/day for the first week, 200/day in the second, and 500/day from day 15 on, with mailbox sends and API sends counted against the same number. A tier raises the monthly allowance rather than that daily cap, which puts the practical maximum at about 15,000 a month. Warm-up is measured from domain verification rather than signup, so every domain you add here — including the ones replacing SparkPost subaccounts — starts at the bottom of that ramp even on a long-standing account.

API access requires a paid plan. This migration runs on the transactional API, and API access is not included in the 7-day trial — a trial account cannot issue the key the dual-send wrapper in Step 4 needs, so there is no way to complete the cutover without subscribing first.

Step 1: Map Your SparkPost Configuration

SparkPost has a few concepts that translate differently to JustEmails. Get these mapped before touching code.

Subaccounts → Domains

SparkPost uses subaccounts to isolate sending for different clients or products. Each subaccount gets its own API key and reputation isolation. JustEmails achieves this with domains. One domain = one isolated sending entity. If you're using subaccounts for client separation, add each client's sending domain to JustEmails separately.

In my case, three SparkPost subaccounts became three domains in JustEmails. Simple translation. If you're tracking sending streams for analytics, JustAnalytics can help segment email event data alongside web traffic.

Sending Domains → Same concept

SparkPost verifies sending domains through DNS. JustEmails does too. The DKIM selectors differ (SparkPost uses sparkpostmail by convention; JustEmails uses je1 and je2), but the concept is identical.

Templates → Local rendering

This is the big difference. SparkPost stores templates server-side. You call their API with a template ID and substitution data; they render and send. JustEmails expects you to render templates yourself and send final HTML.

More work upfront? Yeah. But you get version control and no template lock-in. I actually prefer this now — debugging a template in my editor beats squinting at SparkPost's web UI every time.

Webhooks → Different payload format

SparkPost's webhook payloads use their event schema. JustEmails uses a different structure. You'll update your webhook handlers to parse both during the transition, then drop SparkPost's format after cutover.

Step 2: Add JustEmails DNS Records

Your domain already sends through SparkPost, so DKIM and SPF records exist. You'll add JustEmails' records alongside SparkPost's — don't remove the old ones yet.

In JustEmails dashboard, go to Domains → [your domain] → DNS Records. You'll see the required CNAME entries.

Add these DKIM records:

je1._domainkey.yourdomain.com CNAME je1.dkim.justemails.app
je2._domainkey.yourdomain.com CNAME je2.dkim.justemails.app

Update your SPF record to authorise both providers:

v=spf1 include:sparkpostmail.com a:mail1.justemails.app ~all

SparkPost publishes an include; JustEmails doesn't, so ours is an a: mechanism naming the sending host directly. Keep SparkPost's include during transition. You're running parallel infrastructure.

Wait for DNS propagation — usually 15 minutes for Cloudflare, up to 48 hours for slower registrars. Verify in JustEmails dashboard under Domains → [your domain] → DNS Status. All checks should show green before proceeding.

Don't skip verification. I once spent two hours debugging API errors that turned out to be unpropagated DKIM records. The JustEmails API accepts the send request but downstream verification fails, causing silent bounces. Two hours I'll never get back. Learn from my mistakes.

Step 3: Export and Convert Templates

SparkPost templates use substitution variables like {{name}} or {{order_id}}. The syntax looks like Handlebars but has SparkPost-specific extensions for loops and conditionals.

Export all templates first:

curl -X GET "https://api.sparkpost.com/api/v1/templates" \
  -H "Authorization: YOUR_SPARKPOST_API_KEY" \
  -H "Content-Type: application/json" > sparkpost-templates.json

For each template, extract the HTML content and convert SparkPost-specific syntax to your templating engine. If you're already using Handlebars, most templates transfer directly. Watch for SparkPost's {{each}} loops — they map to Handlebars' {{#each}}.

Example — SparkPost template:

<p>Hi {{name}},</p>
<p>Your order #{{order_id}} has shipped.</p>
{{each items}}
  <p>{{name}} - ${{price}}</p>
{{/each}}

Converted for Handlebars:

<p>Hi {{name}},</p>
<p>Your order #{{order_id}} has shipped.</p>
{{#each items}}
  <p>{{name}} - ${{price}}</p>
{{/each}}

Store converted templates in your codebase. I use a /templates/email/ directory with one file per template. Version control catches changes, and you can preview locally.

(Yes, this means you're now responsible for template rendering. It's not glamorous work. But after dealing with SparkPost's template versioning — or lack thereof — local control feels like a relief.)

For a deeper look at managing transactional templates in your codebase, we covered the SMTP vs API decision (and template implications) in our SMTP vs API comparison.

Step 4: Build the Migration Wrapper

The key to safe migration: send through JustEmails first, fall back to SparkPost if it fails. Run this for at least 72 hours.

async function sendTransactional({ to, subject, html }) {
  const idempotencyKey = `${to}-${subject}-${Date.now()}`;

  // Try JustEmails first
  try {
    const response = await fetch('https://justemails.app/api/v1/send', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${process.env.JUSTEMAILS_API_KEY}`,
        'Content-Type': 'application/json',
        'Idempotency-Key': idempotencyKey
      },
      body: JSON.stringify({
        from: { email: 'notifications@yourdomain.com', name: 'Your App' },
        to: [{ email: to }],
        subject,
        html
      })
    });

    if (response.ok) return { provider: 'justemails', success: true };
    throw new Error(`JustEmails: ${response.status}`);
  } catch (err) {
    console.warn(`JustEmails failed, trying SparkPost: ${err.message}`);
  }

  // Fallback to SparkPost
  const response = await fetch('https://api.sparkpost.com/api/v1/transmissions', {
    method: 'POST',
    headers: {
      'Authorization': process.env.SPARKPOST_API_KEY,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      recipients: [{ address: to }],
      content: { from: 'notifications@yourdomain.com', subject, html }
    })
  });

  if (response.ok) return { provider: 'sparkpost', success: true };
  throw new Error('Both providers failed');
}

The idempotency key prevents duplicates if the first request times out but actually succeeds. Deploy and monitor logs. If JustEmails handles 100% of sends for three days, you're ready to cut SparkPost.

Will you check the logs obsessively for the first 24 hours? Probably. I did. No shame in that.

Step 5: Configure Webhooks

SparkPost sends delivery events to your webhook endpoint. JustEmails does the same but with different payload structures.

Register your webhook URL in JustEmails: Dashboard → API Settings → Webhooks → Add Endpoint.

Your webhook handler needs to detect the payload source during transition. SparkPost sends arrays at the root level; JustEmails sends individual event objects with an event_type field. Handle both until cutover, then simplify to JustEmails-only.

Step 6: The 72-Hour Watch Period

Deploy to production. Then watch.

Daily checklist:

  • JustEmails dashboard: delivery rate, bounce rate, complaint rate
  • Application logs: how many sends fell back to SparkPost?
  • DNS health: DKIM and SPF still passing?

If you see fallbacks, investigate. Common causes: a send cap (the monthly allowance, base 1,000/month, or the daily ceiling a tier does not lift), DNS verification issues, or API key scope.

After 72 hours of clean JustEmails sending with zero fallbacks? You're ready. Take a breath. The hard part is over.

If you're protecting ad spend on domains associated with these emails, ClickzProtect monitors for click fraud on the same domains.

Step 7: Cut Over to JustEmails

Once confident:

  1. Remove SparkPost fallback from code. JustEmails is now your only path.

  2. Update DNS. Remove SparkPost's DKIM and SPF records. Your SPF becomes: v=spf1 a:mail1.justemails.app ~all. Wait 24-48 hours before removal — emails in queue may still carry SparkPost signatures.

  3. Disable SparkPost webhooks. Stop events from reaching your endpoint.

  4. Keep SparkPost account for 30 days. Cancel after clean operation.

Common Errors and Fixes

401 Unauthorized — API key format issue. JustEmails expects Authorization: Bearer je_xxxx. Check for trailing whitespace.

422 Unprocessable Entity — DKIM records haven't propagated. Check Domains → DNS Status in dashboard. All checks should be green.

Emails delivered but marked as spam — Domain reputation issue, not JustEmails. Check Google Postmaster Tools.

SparkPost syntax breaking — If you see literal {{variable}} in emails, your template conversion missed something. Check loop syntax ({{each}} vs {{#each}}).

What You Save

For a service sending 8,000 transactional emails per month:

  • SparkPost (current Bird pricing): starts at $500/month minimum = $6,000/year
  • JustEmails: $49/year base + $25/year for one 10K tier = $74/year

That's $5,926/year back in your pocket. Real money. If you're handling payment notifications, VeloCards pairs well for card transaction alerts through JustEmails.

And you consolidate mailbox hosting and transactional sending under one provider. One DNS configuration per domain. One dashboard. One invoice. I can't overstate how nice it is to not juggle three different email vendors anymore. For teams that also need voice notifications, VeloCalls handles transactional voice alerts with similar simplicity.

Next Steps

After migration:

  • Monitor with Google Postmaster Tools for the first month. Watch domain reputation.
  • Set up DMARC reporting to catch authentication issues early — see our DMARC guide.
  • Review bounce handling — ensure your webhook handler categorizes bounces correctly for list hygiene. The server-enforced suppression list means a hard bounce stops future sends to that address whether or not your handler catches it.

The JustEmails API docs cover batch sending and attachments if you need them. And if you're still on the fence, our SMTP vs API comparison covers when HTTP APIs make sense versus sticking with SMTP.

Frequently Asked Questions

Why migrate from SparkPost to JustEmails?

SparkPost (now under Bird/Sinch) has shifted pricing toward enterprise contracts, pushing smaller senders toward minimum commitments that don't fit their volume. If you're already using JustEmails for mailbox hosting at $49/year, you get 1,000 transactional emails/month included. Adding tiers costs $25/year per 10K emails/month — no contracts, no minimums, no surprise overages.

Will I lose my domain's sender reputation during migration?

Not if you use the parallel-send approach. Your domain reputation lives in DNS (SPF, DKIM, DMARC) and at receiving mailboxes, not at SparkPost. By running both providers simultaneously for 72+ hours and gradually shifting volume, you maintain continuous sending from your domain. Receivers see the same authenticated domain throughout.

How do SparkPost subaccounts map to JustEmails?

SparkPost uses subaccounts to isolate sending streams. JustEmails uses domains instead. Each domain you add to JustEmails acts as an isolated sending entity with its own API key option, webhook configuration, and reputation. One domain per product or client. For multi-tenant setups, add each as a separate domain.

Can I keep using SparkPost templates with JustEmails?

Not directly. SparkPost stores templates server-side with their substitution syntax. JustEmails expects you to render HTML in your application before sending. Export your SparkPost templates, convert them to your local templating engine (Handlebars, Jinja, etc.), and pass the rendered output to the JustEmails API. More control, better version control, no vendor lock-in.


Try JustEmails

Unlimited custom domain email hosting for $49/year flat — unlimited domains, unlimited mailboxes, 10 GB storage, full IMAP/SMTP. Built for agencies, freelancers, and anyone managing email across more than one domain.

Start your 7-day free trial → · How it compares

sparkpost-migrationtransactional-email-apiemail-api-switchdkim-spf-migrationdeliverability-warmupbuildinpublicsaasstudioaiworkforcebuildwithclaude

Related posts

Tutorials
Migrate From Migadu to JustEmails: Multi-Domain IMAP Migration
13 min read
Tutorials
Migrate from GMX and Mail.com to JustEmails: Step-by-Step IMAP Guide
12 min read
Tutorials
Migrate From Purelymail to JustEmails: IMAP and DNS Cutover Guide
13 min read