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.tsandRESEND_API_KEYremoved
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 API —
POST /v3/{domain}/messages.mimeaccepts full MIME messages asmultipart/form-data - AMP4Email support — Explicitly documented.
text/x-amp-htmlMIME 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
| Provider | Purpose | Endpoints |
|---|---|---|
| Mailgun | All sends — AMP4Email (raw MIME) and standard HTML | api/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 viaMAILGUN_DOMAIN/MAILGUN_FROMwithout 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
| Variable | Where | Purpose |
|---|---|---|
MAILGUN_API | Vercel + .env.local | Mailgun API key |
MAILGUN_WEBHOOK_SIGNING_KEY | Vercel | Webhook signature verification |
MAILGUN_DOMAIN | Vercel (optional) | Sending domain override (defaults to kinetic.email) |
MAILGUN_FROM | Vercel (optional) | From address override (defaults to Kinetic Email <ai@kinetic.email>) |
Removed
| Variable | Reason |
|---|---|
RESEND_API_KEY | Resend fully retired — all sends via Mailgun |
EMAIL_FROM | Was Resend's sender address; Mailgun uses MAILGUN_FROM |
POSTMARK_SERVER_TOKEN | Postmark does not support AMP4Email |
AWS_ACCESS_KEY_ID | SES sandbox access denied |
AWS_SECRET_ACCESS_KEY | SES sandbox access denied |
AWS_REGION | SES sandbox access denied |
AWS_SNS_TOPIC_ARN | SES sandbox access denied |
File Inventory
| File | Status | Purpose |
|---|---|---|
api/send-email-mailgun.ts | Active | Mailgun send endpoint — all sends, with AMP raw MIME support |
api/mailgun-webhook.ts | Active | Mailgun delivery/bounce/complaint webhook (HMAC-verified) |
api/unsubscribe.ts | Active | Global unsubscribe endpoint (verified session or signed HMAC token) |
database/68-email-suppressions.sql | Active | Suppression tables |
database/69-email-delivery-events.sql | Active | Delivery event log for Station dashboard |
Removed Files
| File | Reason |
|---|---|
api/send-email.ts | Resend retired — Mailgun handles non-AMP sends too |
api/send-email-postmark.ts | Postmark does not support AMP |
api/postmark-webhook.ts | Postmark removed |
api/send-email-ses.ts | SES access denied |
api/ses-webhook.ts | SES removed |
AMP4Email Setup
Sender Requirements
- Domain
kinetic.emailverified in Mailgun with DKIM + SPF - DMARC set to
p=rejectwithrua=mailto:dmarc@kinetic.email
Recipient Requirements
Gmail users must enable dynamic email:
- Open Gmail → gear icon → See all settings
- General tab → find Dynamic email
- Check Enable dynamic email
- Save Changes
MIME Structure
AMP emails are sent as multipart/alternative with three parts:
text/plain— plain text fallbacktext/x-amp-html— AMP version (rendered in Gmail, Yahoo)text/html— HTML fallback (rendered in all other clients)