Mailglass.Webhook.Providers.SES (Mailglass v1.4.3)

Copy Markdown View Source

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

Summary

Functions

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

Functions

verify_envelope!(raw_body, config)

(since 1.2.0)
@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.