Sendy + SES Bounce Handling: The SNS Setup That Reports

Set up bounce handling in Sendy with Amazon SES: the SNS push-based bounce-feedback architecture, suppression lists, and the config that keeps your account alive.

The single most dangerous Sendy configuration isn't a misconfigured DKIM record or a wrong region setting. It's a Sendy install where bounce handling looks set up — and silently isn't. You find out the hard way: SES trips its bounce-rate wire, pauses your sending, and your "unsubscribed" and "bounced" lists in Sendy are empty. You had no signal. You never had a signal.

Sendy only learns about bounces if Amazon SES tells it about them. That feedback path — SES → SNS topic → HTTPS push straight into your Sendy install's bounce endpoint — is a chain of three links. Break any one and bounce handling dies quietly. (The SNS → SQS → cron-polling architecture you'll see in some guides is MailWizz's pattern, not Sendy's — a confusion that causes real setups to wire the wrong chain.) Here's how to build it right and, more importantly, how to verify every link.

Why this matters more than any other Sendy setting

SES enforces hard bounce-rate thresholds on your AWS account: warnings around 5%, account under review or suspended past 10%. Complaints must stay under 0.1%. Those thresholds apply no matter what software sends your mail — Sendy, MailWizz, anything.

Sendy's job in this is damage control. When a hard bounce comes back, Sendy is supposed to mark that subscriber as bounced and exclude them from all future campaigns. One dead address should bounce exactly once. Without working feedback, that same dead address bounces on every send — your bounce rate climbs campaign after campaign until SES acts.

The SES side of this failure mode is documented: a stale list, a sudden bounce spike, a suspended account, a rejected appeal. But the failure mode is identical for Sendy users. The mechanism that keeps you under the wire is bounce feedback, and it's opt-in — you have to wire it up yourself.

The three links of bounce feedback

Here's the architecture Sendy actually uses (per Sendy's own setup guide: Sendy configures "bounces and complaints handling with Amazon SNS"):

  1. SES generates bounce/complaint notifications. When SES bounces a message or a recipient reports spam, it can publish a notification.
  2. An Amazon SNS topic receives the notifications. You create an SNS topic per region and point SES's feedback notifications at it.
  3. The SNS topic pushes to your Sendy install. Sendy subscribes its bounce/complaint endpoints as HTTPS subscriptions on your topic — notifications arrive within seconds and Sendy marks the subscriber immediately. No queue, no polling.

Break link 3 and SES keeps reporting into the void: SNS has nowhere to deliver, and Sendy happily keeps mailing dead addresses.

Setting it up correctly

1. Create the SNS topic (SES console, per sending region)

  • Create an SNS topic in the same region as your SES sending identity (e.g. sendy-bounces).
  • In SES, set the bounce and complaint feedback notifications to publish to your SNS topic for each verified identity you send from (domain or email). (Delivery notifications are optional noise — skip them.)
  • In Sendy, go to Settings → bounce handling and enter the topic ARN. Sendy subscribes its bounce endpoint on your installation as an HTTPS subscription on the topic — this is the push link, and it requires your Sendy install to be reachable from the public internet.

Critical detail: do this for every region and every identity you send from. A second domain you verified later, or sending through a second region, needs its own topic and its own feedback-notification mapping. This is the #1 silent-breakage source — people set up bounce handling for their first domain in 2021, add a domain in 2024, and never wonder why the new domain's bounces never register.

2. Give Sendy the right IAM permissions

Sendy wires up the bounce handling itself — creating the SNS topic subscriptions and confirming them — so the IAM credentials in Sendy's settings need SNS rights (sns:Subscribe, sns:ConfirmSubscription, sns:ListSubscriptionsByTopic, plus the SES sending rights), not SQS polling rights. Handing Sendy keys scoped only to SES sending is the quiet way this step breaks: setup "succeeds" but the subscription never gets created.

Use a scoped IAM user — not your root keys. Least privilege isn't paranoia here; it's how you notice if something goes wrong, because a scoped policy breaking is a loud failure while overly-broad credentials mask mistakes.

3. Confirm the SNS subscription

Bounce marking in Sendy is push-driven — notifications arrive seconds after SES reports them, no polling involved. But SNS only delivers to confirmed subscriptions, and confirmation requires SNS to reach your Sendy endpoint:

  • In the SNS console, open your topic's subscriptions: the Sendy endpoint subscription must read Confirmed, not PendingConfirmation.
  • The endpoint must be publicly reachable over HTTPS. A firewall, a redirect chain, or an http→https mismatch can leave the subscription stuck unconfirmed — SNS keeps accepting SES notifications and dropping them in exactly this state.
  • Hit the bounce endpoint manually and confirm it responds successfully, not with a 500 or a login redirect.

(Sendy's cron job still matters — it drives scheduled campaign sending — but it is not in the bounce-feedback path. If your mental model says "the cron picks up bounces," you're debugging the wrong component.)

4. Test with the SES mailbox simulator

Don't wait for a real campaign to find out feedback is broken. SES provides mailbox simulator addresses (bounce@simulator.amazonses.com, complaint@simulator.amazonses.com, ooto@simulator.amazonses.com) that trigger the real notification path without hurting your reputation:

  1. Send a campaign from Sendy to bounce@simulator.amazonses.com.
  2. Wait a few minutes for SNS delivery.
  3. Check the subscriber record in Sendy: it should show as bounced.
  4. Check the SNS topic in the AWS console: the subscription should be Confirmed and showing delivered notifications.

If the subscriber never updates, walk the chain backwards: subscription unconfirmed (the SNS→Sendy push link), or the topic receiving nothing (the SES→SNS mapping is missing for that identity)?

The five ways this breaks silently

Ranked by how often I see them reported in Sendy forums:

  1. New identity, no feedback. You verified a second domain or moved regions and never recreated the topic/notification mapping.
  2. Subscription stuck unconfirmed. The SNS subscription to your Sendy endpoint never confirmed — endpoint unreachable, wrong scheme, redirect in the way. SNS keeps accepting SES notifications and dropping them; nothing tells you.
  3. Wrong IAM scope. The credentials in Sendy can send via SES but can't manage SNS subscriptions, so the push link was never created.
  4. Topic deleted or notifications switched off. Someone "cleaned up" the SNS topic, or feedback notifications got disabled on the identity — often after an AWS console redesign moves the setting.
  5. The endpoint moved. Server migration, HTTPS enforcement, or a path change broke the subscription endpoint. The old subscription shows confirmed against a URL that no longer answers.

The 60-second monthly check

Put this in your calendar. It takes a minute and it's the cheapest insurance in your entire stack:

  1. AWS console → SNS → your topic. Subscription Confirmed, deliveries flowing. A subscription flipped back to pending (or a topic with zero deliveries while campaigns run) is the push link breaking.
  2. In Sendy, open the bounced/complained subscriber view. It should not be empty. If you've sent campaigns recently and there are zero bounces on record, something is wrong — real lists always have some bounces.
  3. Send one simulator test per quarter to confirm the end-to-end path still works.

The MailWizz version of the same story

MailWizz is where the SNS → SQS → poll architecture actually lives: its SES bounce servers pull notifications from an SQS queue on a cron schedule. So if you ever followed a "Sendy + SQS" tutorial, you were probably reading MailWizz instructions with Sendy's name on them — and that queue-based setup was never going to talk to Sendy's HTTPS endpoint. The failure taxonomy rhymes across both tools: feedback wired per identity, a delivery path that must actually run, credentials that must still be valid. If you run MailWizz and your bounce rate crept up for no visible reason, check the same three links — in MailWizz's case the last link is the poll, not the push.

What working bounce handling buys you

It doesn't make you immune to SES enforcement — nothing does. What it buys you is the single-bounce rule: every dead address burns you exactly once, and then it's out of every future campaign. That's the difference between a list that naturally drifts at 1–3% bounce (safe) and a list where the same 4% of dead addresses bounce every send, pushing you past 5% and then 10% on pure mechanical repetition.

And it buys you evidence. If SES ever reviews your account, a Sendy install with clean bounce-marking history and a bounded bounce rate is a very different conversation than one whose lists show zero bounces on record — which reads, to a reviewer, as "this sender isn't even watching."


Free: the ListProof self-audit checklist. The 15-point deliverability checklist to run before any SES suspension risk — stale-list detection, bounce-feedback verification, warmup math, and the "pause safely" protocol. [Get it free] → own the rails, not the risk.

Keep Exploring

Use the Workflow Library to browse more guides, comparisons, and integration examples to continue your evaluation.

Keep reading

If this one helped, the next two are the natural follow-ups.