-
-
The live run of 22 Oct 2026: fothering-bulk closed at 16:35 UTC after 20 of 100 bounced. Transactional and alerts stayed open.
-
The live run's email: 20 of 100 recipient-sends bounced for good on the bulk lane, all 20 from batch stale-import.
-
The SES console after the pause: the fothering-bulk configuration set's sending status reads Disabled.
-
The transactional set stays open. A test send on the paused set was refused with SendingPausedException.
-
The email carries the reopen command. Fothering never reopens a lane itself.
-
The replay on the site: one incident in four steps, a generated fixture labelled as one.
-
The deploy page lists every permission each role holds, and why, generated from the synthesized templates.
-
The architecture: SES events to EventBridge, Lambda and DynamoDB, an agent on AgentCore, one pause read back.
Fothering is an agentic AI guard for mail sent through Amazon SES, the email service in AWS Communication Developer Services. When one stream starts bouncing, it works out why, pauses that one configuration set, proves the pause took, and emails the operator the evidence. An agent on Amazon Bedrock AgentCore Runtime has the last word before anything is paused.
Try it in this order: the replay (nothing to install), the demo video, then the code.
If you have three minutes:
- The first 70 seconds of the video: the live run, the pause and the SES console reading Disabled.
- The replay: one incident in four steps, from the first bounce to the reopen.
- "How it decides" below: what code does, and where the agent can say no.
- The email in the gallery: the evidence line an operator actually gets.
- The table under "Limits": what ran live, what is a fixture, what isn't built.
docs/architecture.mdin the repository, if you want the parts.
The problem
A small shop sends everything through one Amazon SES account: receipts, password resets, the newsletter. SES counts bounces across the whole account. AWS's bounce FAQ puts it plainly: at a 5% bounce rate the account goes under review, and at 10% SES might pause its sending, receipts included. So one stale list imported into the newsletter can take the password resets down with it. An AWS partner who runs SES for clients has the same risk in every client account, and can deploy Fothering into each of them.
What Fothering does
When one configuration set starts bouncing, Fothering pauses that set and leaves the others alone. It never closes a transactional lane. It doesn't trust its own pause until SES says so: it reads the setting back, and about ten minutes later checks that nothing got through. Then the operator gets one plain email with what happened, the evidence, what stays open and the command to reopen. It never reopens a lane on its own, and when the evidence doesn't settle the cause it closes nothing.
What AWS already documents, and what Fothering adds
AWS has a guide to pausing one configuration set automatically. A CloudWatch alarm crosses its threshold and notifies an SNS topic, and a Lambda function turns that set's sending off. If you already run it, you have a per-set brake. It pauses whatever crosses the line and can't tell you why. Fothering names the cause with counts (an import batch, a template, a campaign, a mailbox provider or a From domain), closes nothing when the cause isn't settled, leaves transactional lanes open, reads the pause back, checks that it held, and emails the evidence with the reopen command.
How it decides
Code proposes the one lane it may close, the agent confirms it or answers unknown, and code checks again before it pauses anything. An unknown closes nothing.
SES publishes each lane's events to EventBridge, and an ingest function stores a minimized record: the recipient's domain and a keyed hash, never the address, kept 30 days. Every five minutes a detection function reads each lane's window from DynamoDB. A lane opens an incident at 5% hard bounces or 0.1% complaints, counted over at least 100 recipient-sends and at least 3 events. Those match the levels where SES puts an account under review, but they're Fothering's own lane ratios and not SES's figure (SES leaves out mailbox simulator mail, for one). While the other lanes stay under that line, the account's combined rate stays below the bad lane's, so the lane trips before the account does. On a spike the detection function also reads the SES settings and the domain's SPF, DMARC and MX records, then writes one evidence record.
The agent runs on Amazon Bedrock AgentCore Runtime in eu-central-1 and calls Claude Sonnet 4.6 through Bedrock's EU inference profile (eu.anthropic.claude-sonnet-4-6). It gets the evidence record and the lanes code says may be closed, and it holds no tool that changes anything. It writes one paragraph for the email, which the email labels as the agent's. A separate action function refuses anything but the agent's close, checks the decision again, pauses one set with PutConfigurationSetSendingOptions, reads it back with GetConfigurationSet and later confirms that the pause held. No Fothering role can stop the whole account's sending.
The live run
On 22 October 2026 I deployed the four stacks into a real AWS account and sent the scenario to the SES mailbox simulator. After 100 sends on the bulk lane, 20 had bounced for good, every one from the batch stale-import. Fothering paused fothering-bulk, read back "sending enabled: false", and the SES console showed Disabled. A test send on the paused set was refused with SendingPausedException, while the transactional set kept accepting mail. The operator email went out through fothering-alerts, a set Fothering never pauses.
The first attempt that day closed the lane as well, but a missing SES permission stopped its email. I fixed the permission and ran it again. Afterwards I reopened the lane with the command from the email and removed every stack.
Limits, and what is real today
It has only run against the SES mailbox simulator, never real recipients. One scenario ran live, so neither the site nor the video carries a performance number: I'll publish numbers only after more than three live runs. The replay on the site is a generated fixture and says so. Reopening is a command the operator runs. And if AWS pauses the whole account, Fothering's own email can't be sent either.
| Claim | State | Where to see it | Date |
|---|---|---|---|
| Pauses only the configuration set that went wrong | LIVE RUN | the SES console in the gallery: fothering-bulk reads Disabled |
2026-10-22 |
| Reads the pause back from SES | LIVE RUN | the operator email: "sending enabled: false" | 2026-10-22 |
| Names the cause with counts | LIVE RUN | the email's evidence line: 20 of 100, all from batch stale-import |
2026-10-22 |
| The other lanes keep sending | LIVE RUN | a send on the paused set refused with SendingPausedException, the transactional set accepting |
2026-10-22 |
| Emails the operator through a set it never pauses | LIVE RUN | the email, sent through fothering-alerts |
2026-10-22 |
| An agent's unknown closes nothing | FIXTURE | the test "ends an agent unknown as refused no-close with no put" in packages/functions/src/action/action.test.ts |
every CI run |
| One incident, first bounce to reopen | FIXTURE | the replay, labelled as generated | on the site now |
| Replying to the email to keep or reverse a pause | NOT RUN | designed, not built | |
| Real recipients | NOT RUN | only the SES mailbox simulator so far |
The site targets WCAG 2.2 AA and publishes an accessibility statement, and its ship gate checks the Device, Light and Dark theme switch, that Tab reaches every Stop control, and text at 320 px.
What's next
Replying to the email to keep or reverse a pause, which is designed but not built. More live runs, and the numbers they earn once there are more than three. The live run's own replay on the site, with the addresses scrubbed. A measured comparison with the per-set alarm AWS documents.
Built With
- 4.6
- agentcore
- agents
- amazon
- amazon-web-services
- astro
- bedrock
- cdk
- claude
- cloudflare
- cloudwatch
- dynamodb
- eventbridge
- iam
- lambda
- manager
- node.js
- secrets
- ses
- sonnet
- sqs
- strands
- typescript
- zod
Log in or sign up for Devpost to join the conversation.