[SES-PHASE-1-3] - PLU-744: add ses event parser#1629
Open
m0nggh wants to merge 2 commits into
Open
Conversation
Contributor
Author
This was referenced May 19, 2026
66e7e1a to
7fa6e51
Compare
3075d8d to
f6d6920
Compare
7fa6e51 to
901af9b
Compare
ogp-weeloong
reviewed
Jun 2, 2026
ogp-weeloong
reviewed
Jun 2, 2026
ogp-weeloong
reviewed
Jun 2, 2026
ogp-weeloong
reviewed
Jun 2, 2026
ogp-weeloong
approved these changes
Jun 2, 2026
Contributor
ogp-weeloong
left a comment
There was a problem hiding this comment.
lmk what you think about the zod stuff. Otherwise i dont think there's any big blockers tbh (no trapdoor decisions)
pregnantboy
approved these changes
Jun 2, 2026
Comment on lines
+85
to
+86
| const emails = complainedRecipients.map((r) => r.emailAddress) | ||
| const whitelisted = await EmailSuppressionEntry.whitelistEmails(emails) |
Contributor
There was a problem hiding this comment.
this is interesting. i guess a user who can emit a not-spam complain has a valid email
b0fd3f3 to
3fddfc4
Compare
f6d6920 to
61afd7d
Compare
This comment has been minimized.
This comment has been minimized.
3fddfc4 to
59cbb20
Compare
61afd7d to
8af238d
Compare
59cbb20 to
8c50986
Compare
47578d4 to
c635cfa
Compare
8c50986 to
95b7b1c
Compare
Contributor
There was a problem hiding this comment.
Pull request overview
Adds SES bounce/complaint event handling support to the backend, including parsing of SNS-wrapped SES events delivered via SQS and a processor that updates the email suppression/whitelist state based on event semantics.
Changes:
- Introduces
parseSqsMessage+ typed SES event shapes for Bounce/Complaint events. - Adds
processSesEventto suppress on permanent bounces/complaints and auto-whitelist onnot-spamcomplaints. - Adds unit/integration tests and fixture JSON payloads for representative SES events.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/backend/src/helpers/ses-event-parser.ts | New helper to parse SQS → SNS envelope → SES event JSON into a typed shape. |
| packages/backend/src/helpers/process-ses-event.ts | New processor to apply suppression/whitelist logic based on parsed SES events. |
| packages/backend/src/helpers/tests/ses-event-parser.test.ts | Unit tests for parser success/error paths. |
| packages/backend/src/helpers/tests/process-ses-event.itest.ts | Integration tests validating suppression/whitelisting behavior and idempotency. |
| packages/backend/ses-test-events/ses-bounce-permanent.json | Fixture for a permanent bounce event. |
| packages/backend/ses-test-events/ses-bounce-transient.json | Fixture for a transient bounce event. |
| packages/backend/ses-test-events/ses-complaint-abuse.json | Fixture for an abuse complaint event. |
| packages/backend/ses-test-events/ses-complaint-not-spam.json | Fixture for a not-spam complaint event (auto-whitelist). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+73
to
+77
| logger.error('Complaint event missing complaint payload', { | ||
| event: 'ses-malformed-event', | ||
| sqsMessageId, | ||
| messageId: mail?.messageId, | ||
| }) |
Comment on lines
+58
to
+60
| // Transient / Undetermined — log only, do not suppress | ||
| logger.info('Transient bounce received — no suppression', { | ||
| event: 'ses-transient-bounce', |
Comment on lines
+25
to
+31
| interface SesComplaint { | ||
| complainedRecipients: ComplainedRecipient[] | ||
| timestamp: string | ||
| feedbackId: string | ||
| complaintFeedbackType?: string | ||
| complaintSubType?: string | ||
| } |
95b7b1c to
cdaa0e1
Compare
Base automatically changed from
feat/ses/add-email-suppression-migration-and-model
to
feat/ses/trunk
June 8, 2026 15:02
cdaa0e1 to
79a7684
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

TL;DR
Adds a SES event processor that suppresses or whitelists email addresses based on bounce and complaint notifications received via SNS/SQS.
TODOs:
What changed?
ses-event-parser.tshelper that parses SQS messages containing SNS-wrapped SES events, exposing typed interfaces for bounce and complaint events.process-ses-event.tswith aprocessSesEventfunction that:not-spamcomplaint is received.parseSqsMessagecovering valid events, invalid JSON, missingMessagefield, and missingeventType.processSesEventcovering suppression on permanent bounce, no suppression on transient bounce, suppression on abuse complaint, auto-whitelisting on not-spam complaint, graceful handling of not-spam for non-suppressed emails, and idempotency.How to test?
Run the unit and integration tests:
The fixture files under
ses-test-events/can also be used to manually invoke the processor against a local SQS queue to verify end-to-end behaviour.Why make this change?
SES delivers bounce and complaint notifications via SNS → SQS. Without handling these events, suppressed or complaining recipients would continue to receive emails, risking SES account reputation and deliverability. This processor ensures that permanently bounced and complained-about addresses are suppressed from future sends, while also providing a recovery path when recipients mark emails as not-spam.