Skip to content

Delivery events

sent means Amazon SES accepted the message. That is the last thing SESKit can observe on its own — whether it arrived, bounced, or was reported as spam is knowledge that lives at AWS, and SES does not report it anywhere unless asked.

Setting it up

Press Set up event reporting on the AWS page. SESKit creates, in the region the project is connected to:

Resource Purpose
SQS queue seskit-events the worker polls this
SNS topic seskit-events SES publishes here; it fans out to the queue
SES configuration set seskit sends name it, or SES publishes nothing

Messages sent from that point on show a delivery history: delivered, bounced with the reason SES gave, marked as spam.

This is the one action in SESKit that creates resources in your own AWS account, which is why the page names them before you press the button and why disconnecting removes them again. It needs the second IAM policy.

Messages sent before setup gain nothing

SES only reports on mail sent through a configuration set, so existing messages have no history and never will. The message page distinguishes that from "no events yet" rather than showing an ambiguous blank.

Two ways events get back

Set by EVENT_INGESTION:

Mode How When to use
sqs (default) The worker polls the queue Anywhere. No inbound port, no public hostname, no certificate — AWS cannot POST to a laptop
https SNS posts to POST /v1/events/ses A public address with TLS. Lower latency, no polling. Needs PUBLIC_BASE_URL
both Both at once Migrating between the two

SQS is the default because it works from anywhere, including a laptop behind NAT with no certificate. HTTPS is lower latency but requires SESKit to be reachable from the internet.

How the HTTPS endpoint is protected

It is unauthenticated by necessity: SNS has no credential to present.

Every request is verified against the RSA signature SNS signed it with, using a certificate fetched only from sns.<region>.amazonaws.com, and only after that host is validated. An unsigned or altered notification is refused with 403 and nothing is recorded. The endpoint is not mounted at all unless EVENT_INGESTION asks for it.

Checking only the topic ARN — which is a field in the request body, and not a secret — would let anyone who learns one fabricate bounce and complaint events. See the security model.

Open and click tracking

Off unless you turn it on, per project, and worth understanding before you do.

This changes the mail your recipients receive

Enabling it asks Amazon SES to rewrite every link in the mail this project sends so clicks route through an Amazon-operated domain, and to add an invisible tracking pixel to HTML messages.

Your recipients see the rewritten links. That is a visible change to your own product with privacy consequences, which is why it is a deliberate choice rather than a default.

With tracking off, open and click rates read "Not tracked" rather than 0% — see reading your metrics.

Duplicate events

SNS and SQS are both explicitly at-least-once, so the same notification will arrive twice sooner or later.

SESKit deduplicates on the SNS message id with a unique constraint, so a redelivered bounce is recorded once. This matters more than it sounds: a double-counted bounce inflates the rate AWS judges your account by.

Removing it

Removing event reporting, or disconnecting the account, deletes what was created. Nothing else in your account is touched, and if a second project on the same instance shares the region, the infrastructure stays until the last one stops using it.

Getting events into your own application

Delivery events tell SESKit what happened. To tell your application, set up webhooks.