By Tilak Sasmal — Sat Apr 18 2026
4 min read

While building a proxy for Ghost CMS’s default mail provider (Mailgun), I hit a major roadblock. Ghost uses Mailgun to send newsletter batches—containing post data and member emails—and relies on Mailgun to track if those emails were sent, delivered, or bounced. Ghost then queries this data to update member delivery statuses.
Creating a proxy to handle the email sending part was straightforward but capturing SES status events and storing them in a format Ghost expects was the real challenge. This post documents how to route those events from SES → SQS → Mailgun Proxy.
Before setting up your SES identities, you need an identity that your code will use to interact with AWS.
mailgun-proxy-worker.In the "Set permissions" step, choose Attach policies directly. You need to grant this user permission to use SES and SQS. Search for and check
AmazonSESFullAccess AmazonSQSFullAccess Once the user is created, you won't have your keys yet. You must generate them manually:
mailgun-proxy-worker) from the list.Ghost-Mailgun-Proxy-Keys.Peer Tip: Never commit these keys to GitHub. If you're running your proxy on an AWS EC2 instance or Lambda, it is much safer to use IAM Roles instead of static Access Keys, as roles provide temporary, self-rotating credentials.
Navigate to the AWS Console and open the Amazon SES page. You must first verify your Identities (the email addresses or domains used to send mail).

A Configuration Set allows you to apply specific rules to the emails you send. This is the "brain" of our operation because it tells SES where to send event data.
ghost-mailgun-proxy-set).Send, Delivery, Bounce, and Complaint.


Navigate to the SQS page. To keep our proxy organized and scalable, we will create three distinct queues:
newsletter-buffer-queue: To store incoming newsletter batches from Ghost.newsletter-events-queue: To store the raw SES events (bounces, deliveries) for processing.system-events-queue: To store events for transactional emails (e.g., signup links) sent via the proxy.Note: Use Standard Queues unless your specific logic strictly requires FIFO, as Standard queues offer higher throughput for large newsletter batches.

Once you have repeated the steps for creating all the queues:

Now, we need to ensure the events landing in SNS are pushed into our SQS queues.
newsletter-events-queue.sqs:SendMessage.

While it may seem like a lot of "plumbing" to get a simple status update, this architecture is built for scale and reliability. By moving your email events into SQS, you’ve ensured that even if your proxy goes down for maintenance or experiences a spike in traffic, your delivery data remains safe and sound in the queue.
You’ve successfully turned a rigid CMS requirement into a flexible, cloud-native notification system. Now, all that’s left is to start the worker, send that first newsletter, and watch the events roll in.
Happy sending!
Github: https://github.com/typetale-app