SES → SNS → MailAnvil: Complete Event Tracking Setup Guide
SES → SNS → MailAnvil Setup Guide
MailAnvil's SNS Worker (mailanvil-sns-worker.pakomting.workers.dev) handles bounce, complaint, and delivery notifications from SES. But it only works if SES is configured to send those notifications to the Worker's URL.
This guide connects everything.
Why this matters
| Without SNS | With SNS |
|---|---|
| ❌ Bounces unnoticed | ✅ Auto-suppressed (INV-2) |
| ❌ Complaints invisible | ✅ Kill switch triggers (INV-5) |
| ❌ Delivery status unknown | ✅ Per-recipient status tracked |
| ❌ Reputation degrades silently | ✅ Automated protection |
Prerequisites
Make sure the SNS Worker is deployed:
curl https://mailanvil-sns-worker.pakomting.workers.dev/health
# Should return {"status":"ok","worker":"sns"}
Step 1: Create SNS Topic for SES notifications
- Open https://ap-southeast-1.console.aws.amazon.com/sns/v3/home?region=ap-southeast-1#/topics
- Click Create topic
- Type: Standard
- Name:
mailanvil-ses-events - Display name: (leave empty)
- Click Create topic
- Copy the ARN (looks like
arn:aws:sns:ap-southeast-1:785823254435:mailanvil-ses-events)
Step 2: Create HTTPS subscription
- On the topic page, click Create subscription
- Protocol: HTTPS
- Endpoint:
https://mailanvil-sns-worker.pakomting.workers.dev/ses-event - Enable raw message delivery: No (leave unchecked)
- Click Create subscription
- Go to the subscription, click Request confirmation
- The Worker auto-confirms subscriptions when it receives the confirmation request from SNS
- Wait 30 seconds, refresh — status should be Confirmed
If status stays Pending confirmation, the Worker didn't receive the confirmation. Check:
curl https://mailanvil-sns-worker.pakomting.workers.dev/health
Step 3: Configure SES to send events to SNS
- Open https://ap-southeast-1.console.aws.amazon.com/ses/home?region=ap-southeast-1#/configuration-sets
- Click Create configuration set
- Name:
mailanvil-config - Click Create
Wait for the configuration set to be created...
- Click the config set name → Event destinations tab → Add destination
- Name:
sns-events - Event types: check ALL:
- ✅ Send
- ✅ Delivery
- ✅ Bounce
- ✅ Complaint
- ✅ Reject
- ✅ Open (optional)
- Destination: SNS topic
- Topic ARN: paste the ARN from Step 1
- Click Add destination
Step 4: Link configuration set to sending
Update the SES credentials to include the configuration set name.
cd /home/richa/mailanvil/packages/consumer
echo "mailanvil-config" | npx wrangler secret put SES_CONFIGURATION_SET
Then:
cd /home/richa/mailanvil/packages/consumer && npx wrangler deploy
Or ask me to do it.
Step 5: Test the pipeline
Send a test email and check:
curl -X POST https://api.mailanvil.com/v1/send \
-H "Authorization: Bearer ***" \
-H "Content-Type: application/json" \
-d '{"from":"hello@mailanvil.com","to":["aakricha@gmail.com"],"subject":"SNS test","text":"Testing SNS notifications"}'
Then check the email status after 30 seconds:
curl https://api.mailanvil.com/v1/emails/*** \
-H "Authorization: Bearer ***" | python3 -m json.tool
The ses_message_id should be set (meaning it left SES). After a few more seconds, the per-recipient status should update to delivered once SNS delivers the notification.
Verification
Check the SNS topic for published messages:
1. https://ap-southeast-1.console.aws.amazon.com/sns/v3/home?region=ap-southeast-1#/topics
2. Click mailanvil-ses-events → Monitoring tab
3. You should see Published messages increasing after test sends
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Subscription stuck Pending confirmation | Worker didn't auto-confirm | Hit Request confirmation again, then check Worker health |
| SNS published but no status update | Configuration set not linked to sends | Set SES_CONFIGURATION_SET secret on consumer Worker |
| SNS Worker 404 on confirmation | Endpoint URL wrong | Check /ses-event path matches subscription endpoint |
| SES events not publishing | No configuration set on sends | The sendEmail function uses ConfigurationSetName in SES API body |
What gets tracked
| Event | SNS Worker action | Result |
|---|---|---|
| Bounce | Insert into suppressions, update recipient status to bounced |
INV-2: future sends blocked |
| Complaint | Insert into suppressions, update to complained |
INV-5: kill switch check |
| Delivery | Update recipient status to delivered |
Per-recipient tracking |
| Send | Update email status from sending to sent |
Status update |
| Reject | Update email status to failed with error |
Error tracking |
You don't need to do anything else after Step 4. The SNS Worker handles all events automatically.