Skip to content

Switching Transactional Email Providers With Zero Downtime

Moving your app's email to a new provider doesn't need a risky big-bang cut-over. Dual DKIM, a thin sending interface, gradual rollout and suppression export.

Koltrix Team4 min read
Stone arch bridge spanning a rocky river gorge
Photo by Adrien CÉSARD on Unsplash
On this page(10 sections)
  1. Why teams switch
  2. Step 1: Put a thin interface in front of sending
  3. Step 2: Authenticate the new provider alongside the old one
  4. Step 3: Move your suppression list
  5. Step 4: Roll out gradually
  6. Step 5: Handle webhooks from both providers
  7. Step 6: Watch the right numbers
  8. Step 7: Finish the switch
  9. A note on SMTP
  10. Key takeaways

Switching the service your app uses to send password resets and receipts sounds like a weekend job: change an API key, swap a client library, deploy. Then the first customer can't log in because their reset email went to spam, and you discover that nobody exported the suppression list.

A provider switch can be boring and safe if you treat it as a gradual rollout rather than a single cut-over. Here's the sequence.

Why teams switch

The reasons vary: cost at a new volume, a feature you need (inbound handling, better logs, replies landing in a team inbox), support quality, consolidating vendors, or deliverability problems you've traced to the provider. The reason affects what you test, but the mechanics are the same.

Step 1: Put a thin interface in front of sending

If provider-specific code is scattered across your app, start here. Create one internal function or module that every part of the app calls to send email, and make it the only place that knows which provider exists.

// email/send.ts
export interface OutboundEmail {
  from: string;
  to: string;
  subject: string;
  html: string;
  text?: string;
  tag?: string; // e.g. "password-reset"
}

export async function sendEmail(msg: OutboundEmail) {
  const provider = pickProvider(msg); // old or new, see step 4
  return provider.send(msg);
}

This is worth doing even if you never switch again. It makes testing easier, gives you one place to add logging, and keeps future changes small.

Step 2: Authenticate the new provider alongside the old one

Your domain's DNS can authorize both providers at once. Do this days before any mail moves.

  • DKIM: each provider signs with its own key under its own selector, so both can be published at the same time. Add the new provider's DKIM record without touching the old one.
  • SPF: add the new provider's include to your existing SPF record. Watch the limit of ten DNS lookups; if you're close, remove includes for services you no longer use.
  • Return-path or bounce domain: some providers ask for a CNAME on a subdomain to handle bounces and align SPF. Set it up now.
  • DMARC: no change needed if both providers pass DKIM with your domain aligned. Your DMARC aggregate reports will show the new provider's traffic once it starts.

Verify with the new provider's dashboard and a DMARC check before sending anything real.

Step 3: Move your suppression list

This is the step teams skip and regret. Your old provider has a list of addresses that hard-bounced, complained or unsubscribed. If you don't carry it over, the new provider will happily send to all of them, your bounce and complaint rates will spike, and your new sender reputation starts off damaged.

  • Export hard bounces, spam complaints and any unsubscribes from the old provider.
  • Import them into the new provider's suppression list, or into your own database if you keep suppression in-app.
  • Decide how you'll keep both in sync during the overlap. The simplest option is to handle bounce and complaint webhooks from both providers and write to one shared table in your app.

Step 4: Roll out gradually

Route a small share of mail to the new provider first, then increase it. Two common approaches:

By message type. Start with low-risk, low-volume email, such as internal notifications or weekly digests, then move onboarding email, and move password resets and receipts last.

By percentage. Send a fixed percentage of all mail through the new provider using a feature flag, and raise it as metrics hold.

function pickProvider(msg: OutboundEmail) {
  const rollout = Number(process.env.NEW_PROVIDER_PERCENT ?? 0);
  // Stable per-recipient bucketing so one person doesn't flip between providers
  const bucket = hash(msg.to) % 100;
  return bucket < rollout ? newProvider : oldProvider;
}

A sensible ramp is a few days at each step, such as 5%, 25%, 50% and 100%, watching delivery at each stage. If you're also sending from a newly authenticated domain, ramp more slowly; new sending identities build reputation over time.

Step 5: Handle webhooks from both providers

During the overlap, delivery, bounce and complaint events arrive from two places with two formats. Normalize them into one internal event shape before your app acts on them.

  • Give each provider its own webhook endpoint.
  • Verify each provider's webhook signature.
  • Map their event names to yours: delivered, bounced, complained, opened, clicked.
  • Make handlers idempotent; webhooks can be delivered more than once.

Step 6: Watch the right numbers

Metric Where to look What a problem looks like
Bounce rate Both providers' dashboards New provider noticeably higher than old for the same mail
Complaint rate Webhooks, feedback loops Any increase after moving a message type
Inbox placement Seed accounts at major mailbox providers Password resets landing in spam
Delivery latency Timestamp of send vs receipt Resets taking minutes instead of seconds
Support tickets Your support inbox "I never got the email" rising

Keep a small set of test accounts at Gmail, Outlook, Yahoo and a couple of business domains, and send each critical template to them at each rollout step.

Step 7: Finish the switch

Once 100% of mail has gone through the new provider for a week or two without problems:

  • Remove the old provider's SPF include.
  • Leave its DKIM record for a few more weeks so delayed or retried mail still verifies, then remove it.
  • Remove old webhook endpoints and rotate or delete old API keys and SMTP credentials.
  • Update your runbooks and the email inventory.
  • Close the old account only after you've saved any logs you might need.

A note on SMTP

If parts of your stack send over SMTP rather than an API, such as a legacy app, a CMS or a billing tool, those need moving too. Most providers offer an SMTP relay; switching is usually a matter of changing host, port and credentials. Include each SMTP sender in your rollout plan and test it separately.

If Koltrix is your destination, the REST endpoint is POST https://api.koltrix.com/api/v2/emails with an API key, and anything that already speaks SMTP can point at the relay instead. The sending docs cover both, and the webhooks reference covers delivery events.

Key takeaways

  • Wrap sending behind one internal interface before you switch.
  • Publish the new provider's DKIM and SPF alongside the old ones days in advance.
  • Export and import your suppression list; never start fresh.
  • Roll out by message type or percentage, with password resets last.
  • Normalize webhooks from both providers, watch bounces and placement, and clean up DNS and credentials at the end.

Start with Koltrix

Your domain, one inbox, and an API that sends.

A team inbox where AI sorts and drafts (nothing is sent without your click), plus the transactional API and SMTP relay your product sends with. 7 days free, no card.

SharePost on XLinkedIn
More in Guides →