# `Mailglass.Webhook.Providers.SES`
[🔗](https://github.com/szTheory/mailglass/blob/v2.7.0/lib/mailglass/webhook/providers/ses.ex#L1)

AWS SES webhook verifier via Amazon SNS.

Implements `Mailglass.Webhook.Provider` for SES events delivered through
SNS HTTP subscriptions. Handles all three SNS message types on the same
endpoint:

  * `Notification` — SES event payload; returns `:ok` for the ingest pipeline
  * `SubscriptionConfirmation` — auto-confirms after verification; returns
    `{:ok, :control_plane, :subscription_confirmed}`
  * `UnsubscribeConfirmation` — verifies and no-ops; returns
    `{:ok, :control_plane, :unsubscribe_confirmed}`

## Verification algorithm

1. Parse raw body as JSON (SNS delivers `text/plain` but body is valid JSON)
2. Validate `SigningCertURL` with `TrustPolicy.valid_cert_url?/1` before network I/O
3. Fetch X.509 public key from `CertCache` (ETS hit) or `:httpc` (cache miss)
4. Build canonical string from message fields (byte-sorted per AWS spec)
5. Verify RSA-SHA1 (SignatureVersion 1) or RSA-SHA256 (SignatureVersion 2) signature
6. Dispatch on `MessageType`:
   - `Notification` → return `:ok`
   - `SubscriptionConfirmation` → validate SubscribeURL, construct ConfirmSubscription
    URL from TopicArn + Token, :httpc GET with redirects disabled
   - `UnsubscribeConfirmation` → log telemetry, return control-plane no-op

## Inbound-reuse seam

`verify_envelope!/2` exposes steps 1-5 (the SNS X.509 verification) as a public
seam so `mailglass_inbound`'s SES ingress can reuse the byte-identical SNS
envelope verification without reinventing cryptography (-01). `verify!/3`
calls it, then dispatches on `MessageType`; its public return and behavior are
unchanged.

## Configuration (Application env)

    config :mailglass, :ses,
      cert_cache_ttl_seconds: 86_400   # default 24 hours

# `verify_envelope!`
*since 1.2.0* 

```elixir
@spec verify_envelope!(binary(), map()) :: {:ok, map()}
```

Verify the SNS envelope's X.509 signature and trust policy, returning the
decoded SNS payload.

This is the **inbound-reuse seam** (-01): the SNS JSON envelope is
byte-identical for outbound webhooks and `mailglass_inbound` SES ingress, so
the crypto primitive (decode → `TrustPolicy.valid_cert_url?` → `CertCache`
public-key fetch → canonical-string build → `:public_key.verify`) is factored
out for `mailglass_inbound.Ingress.Providers.SES` to call directly, then drive
its own MessageType dispatch (S3 fetch / inline content / control-plane).

Raises `Mailglass.SignatureError` on any verification failure — identical
behavior to the steps previously inlined in `verify!/3`. The outbound
`verify!/3` return and behavior are unchanged.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
