Skip to main content

Email Provider Migration: Resend → SES → Postmark → Mailgun

Status: COMPLETE. Mailgun is live as the sole delivery provider; Resend is fully retired. Remaining cleanup: stale Resend DNS records on e.kinetic.email should be removed.

Timeline

  • Pre-April 2026: Resend as primary email provider (no raw MIME / AMP support)
  • April 2-8: Attempted AWS SES migration for AMP4Email support via raw MIME
  • April 8: SES production access denied twice despite detailed application
  • April 9: Attempted Postmark migration — domain verified, but REST API does not support raw MIME or AMP4Email
  • April 9: Migrated to Mailgun — raw MIME via REST API confirmed working, AMP4Email delivered successfully
  • Post-April 2026: Resend fully retired — all sends (AMP and non-AMP) now go through Mailgun; api/send-email.ts and RESEND_API_KEY removed

Why SES Failed

AWS SES requires manual approval to exit sandbox mode. We submitted two detailed applications including full bounce/complaint handling, unsubscribe infrastructure, and CAN-SPAM compliance. Both were rejected with generic responses and no actionable feedback.

Why Postmark Failed

Postmark's REST API does not support raw MIME (RawSource is undocumented and rejected From headers). Their documentation has no mention of AMP4Email support. The Invalid 'From' value error persisted despite correct Sender Signature configuration. Postmark is not suitable for AMP4Email.

Why Mailgun

  • Raw MIME via REST APIPOST /v3/{domain}/messages.mime accepts full MIME messages as multipart/form-data
  • AMP4Email support — Explicitly documented. text/x-amp-html MIME part works out of the box
  • No sandbox gatekeeping — Domain verification grants immediate sending to any address
  • Free tier — 100 emails/day (~3,000/month), no credit card, no time limit
  • Webhook support — Delivered, failed, complained, opened, clicked events
  • HMAC-SHA256 webhook verification — Signing key for secure webhook authentication

Current Architecture

ProviderPurposeEndpoints
MailgunAll sends — AMP4Email (raw MIME) and standard HTMLapi/send-email-mailgun.ts

How It Works

  • Every send goes through /api/send-email-mailgun (Playground, Sandbox, workspace, etc.)
  • Sends require a signed-in user and are attributed to the verified account email
  • The sending domain and from address default to kinetic.email / Kinetic Email <ai@kinetic.email> and can be overridden via MAILGUN_DOMAIN / MAILGUN_FROM without a deploy

Webhook Flow

Mailgun webhooks → api/mailgun-webhook.ts → logs to email_delivery_events table + feeds bounces/complaints into email_suppressions table → viewable at /station/delivery

Environment Variables

VariableWherePurpose
MAILGUN_APIVercel + .env.localMailgun API key
MAILGUN_WEBHOOK_SIGNING_KEYVercelWebhook signature verification
MAILGUN_DOMAINVercel (optional)Sending domain override (defaults to kinetic.email)
MAILGUN_FROMVercel (optional)From address override (defaults to Kinetic Email <ai@kinetic.email>)

Removed

VariableReason
RESEND_API_KEYResend fully retired — all sends via Mailgun
EMAIL_FROMWas Resend's sender address; Mailgun uses MAILGUN_FROM
POSTMARK_SERVER_TOKENPostmark does not support AMP4Email
AWS_ACCESS_KEY_IDSES sandbox access denied
AWS_SECRET_ACCESS_KEYSES sandbox access denied
AWS_REGIONSES sandbox access denied
AWS_SNS_TOPIC_ARNSES sandbox access denied

File Inventory

FileStatusPurpose
api/send-email-mailgun.tsActiveMailgun send endpoint — all sends, with AMP raw MIME support
api/mailgun-webhook.tsActiveMailgun delivery/bounce/complaint webhook (HMAC-verified)
api/unsubscribe.tsActiveGlobal unsubscribe endpoint (verified session or signed HMAC token)
database/68-email-suppressions.sqlActiveSuppression tables
database/69-email-delivery-events.sqlActiveDelivery event log for Station dashboard

Removed Files

FileReason
api/send-email.tsResend retired — Mailgun handles non-AMP sends too
api/send-email-postmark.tsPostmark does not support AMP
api/postmark-webhook.tsPostmark removed
api/send-email-ses.tsSES access denied
api/ses-webhook.tsSES removed

AMP4Email Setup

Sender Requirements

  • Domain kinetic.email verified in Mailgun with DKIM + SPF
  • DMARC set to p=reject with rua=mailto:dmarc@kinetic.email

Recipient Requirements

Gmail users must enable dynamic email:

  1. Open Gmail → gear icon → See all settings
  2. General tab → find Dynamic email
  3. Check Enable dynamic email
  4. Save Changes

MIME Structure

AMP emails are sent as multipart/alternative with three parts:

  1. text/plain — plain text fallback
  2. text/x-amp-html — AMP version (rendered in Gmail, Yahoo)
  3. text/html — HTML fallback (rendered in all other clients)