Skip to content

Add SES newsletter delivery (experimental)#792

Draft
lylo wants to merge 1 commit into
mainfrom
ses-newsletter-delivery
Draft

Add SES newsletter delivery (experimental)#792
lylo wants to merge 1 commit into
mainfrom
ses-newsletter-delivery

Conversation

@lylo

@lylo lylo commented Feb 26, 2026

Copy link
Copy Markdown
Owner

Experimental — do not merge until warm-up is complete.

Summary

  • Migrates outbound newsletter delivery from Postmark to Amazon SES (~10x cost reduction)
  • Feature-flagged per blog (ses_newsletter_delivery) — Postmark remains the default path
  • SES sends from send.pagecord.com (separate domain from Postmark's newsletters.pagecord.com)
  • Bounce/complaint handling via SQS polling creates Email::Suppression records that block future sends
  • EmailSubscriber records stay intact — only the suppression list prevents delivery
  • Admin UI at /admin/suppressed_emails for viewing and unsuppressing emails
  • Region failover: eu-west-2eu-west-1
  • Provisioning rake task (ses:provision) automates full AWS setup

What's new

Area Files
Models Email::Suppression, Email::Event
Delivery PostDigest::SesDelivery (mirrors PostmarkDelivery)
Bounce processing Email::ProcessBouncesJob (SQS polling, every 5 min)
Admin UI /admin/suppressed_emails — list, filter, unsuppress
Rake tasks ses:provision, ses:status
Feature flag ses_newsletter_delivery in config/features.rb
Docs docs/ses-newsletter-delivery.md

What's unchanged

  • Postmark stays for Action Mailbox inbound (post-by-email, digest replies)
  • MailPace stays for transactional email
  • Mailer rendering pipeline (PostDigestMailer + Premailer) is reused as-is
  • PostDigest::PostmarkDelivery is untouched and remains the default

Rollout plan

Deploys inactive — no blogs have the feature flag. Gradual enablement:

  1. Own blog only (days 1-3, verify delivery + bounce simulator)
  2. ~10% of blogs (days 4-7, monitor SES dashboard)
  3. ~50% of blogs (days 8-10)
  4. All blogs (day 11+, then remove Postmark path)

Test plan

  • All 1185 existing tests pass (0 failures, 0 errors)
  • 32 new tests across models, jobs, and controllers
  • Run ses:provision and add DNS records
  • Send to success@simulator.amazonses.com — verify delivery + event records
  • Send to bounce@simulator.amazonses.com — verify suppression created
  • Send to complaint@simulator.amazonses.com — verify complaint suppression
  • Verify suppressed addresses are skipped on next digest
  • Admin UI: filter tabs, unsuppress flow
  • Check headers via mail-tester.com (DKIM, SPF, DMARC on send.pagecord.com)

Feature-flagged per blog (ses_newsletter_delivery) to run in parallel
with Postmark during warm-up. Includes Email::Suppression list for
bounce/complaint handling, SQS polling job, region failover, admin
suppressed emails management, and AWS provisioning rake tasks.
@lylo lylo force-pushed the main branch 2 times, most recently from c853070 to 18e4461 Compare March 11, 2026 11:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant