Evidence feeds
Docs / Webhooks

Evidence feeds

Delivered is the provider's word, not ours. A message reads Delivered only when a provider tells us so, and the record names the feed it came from. This page is exactly which transports can do that today, and how to point one at us.

Which transports report

mailgunreports — once its webhook signing key is saved
postmarkreports — once its webhook secret is saved
smtpnever — stops at Handed to your server, Amazon SES over SMTP included

A native SES type with an SNS feed is not offered: it needs signed AWS requests (SigV4), which are not built.

Where the webhook goes

POST https://spoolway.com/api/v1/webhooks/{transport id}

One URL per transport. The id is the transport's own id — GET /v1/transports lists it, with a key holding transports:read. An unknown id and a refused signature both answer 401, so the URL does not reveal which ids exist. An accepted event answers 202 and is processed in the background; a verified request that is not about delivery answers 200 and is ignored.

Mailgun

In Mailgun, point a webhook for the events you want at the URL above, and save the domain's HTTP webhook signing key on the transport. Each request is checked with HMAC-SHA256 over its timestamp and token. A timestamp more than 15 minutes off is refused, and each token is accepted once, so a captured request cannot be replayed. A refusal names itself: mailgun_signature_invalid.

Postmark

Postmark does not sign its webhooks, so the transport carries a secret you choose. In Postmark's webhook settings, send it as the custom header X-Postmark-Webhook-Token, or as the HTTP basic-auth password on the URL. A request without it is refused as postmark_secret_invalid.

What each event becomes

mailgun · deliveredDelivered
mailgun · failed, rejected, bouncedBounced — hard when Mailgun marks it permanent or it is a bounce, soft otherwise
mailgun · complainedComplaint
mailgun · unsubscribedUnsubscribed
postmark · DeliveryDelivered
postmark · BounceBounced — HardBounce, BadEmailAddress and ManuallyDeactivated are hard; Blocked is about the sender, never the recipient; the rest are soft
postmark · SpamComplaintComplaint
postmark · SubscriptionChangeUnsubscribed

Anything else a provider sends is verified and ignored. A bounce's class is then refined from its diagnostic text, and only ever away from blaming the recipient.

When a feed goes quiet

A feed that has carried mail and then reported nothing for 15 minutes reads stale. Counts built from it are complete only up to its last event, so Overview shows an em dash for proven delivered rather than a number quietly missing the latest confirmations. A feed that has carried nothing reads idle, which is not an outage.