# `SquatchMail.SNS.RawBodyPlug`
[🔗](https://github.com/Axio-Intelligence/Squatch-Mail/blob/v0.1.1/lib/squatch_mail/sns/raw_body_plug.ex#L1)

Captures the exact raw request body into `conn.assigns[:raw_body]` for the
SNS webhook route, independent of the host endpoint's `Plug.Parsers`.

`SquatchMail.Web.Router` mounts this plug ahead of
`SquatchMail.Web.WebhookController` for `POST .../webhooks/sns/:token` only.
It exists because relying on `Plug.Parsers`'s `:body_reader` to capture the
raw bytes is not sufficient for SNS:

SNS delivers to HTTP/S endpoints with `Content-Type: text/plain;
charset=UTF-8`. `Plug.Parsers` only invokes its `:body_reader` for a
content-type one of its configured parsers *matches* — and the usual parser
list (`[:urlencoded, :multipart, :json]`) matches none of `text/plain`. With
`pass: ["*/*"]`, `Plug.Parsers` therefore returns the request with an **empty
params map and the body still unread**, so a `:body_reader` never sees SNS's
bytes and `conn.assigns[:raw_body]` is never set. `SquatchMail.SNS.Processor`
then decodes the controller's `Jason.encode!(conn.params)` fallback — just the
path params — finds no `"Type"` key, and every SNS message 500s.

Because the host endpoint's `Plug.Parsers` runs *earlier* and leaves the
`text/plain` body unread, this plug (running later, in SquatchMail's own
router pipeline) can still read it. It reads the full body — following
`{:more, ...}` chunking — and assigns it. `SquatchMail.SNS.MessageVerifier`
needs those exact bytes to rebuild the signed string, and
`SquatchMail.SNS.Processor.process/2` does its own JSON decode of them.

If `conn.assigns[:raw_body]` is already a binary — e.g. a host wired
`SquatchMail.SNS.RawBodyReader` into its endpoint's `Plug.Parsers`
`:body_reader` (still supported) — this plug leaves it untouched. It is the
reliable default; the body_reader is an optional belt-and-suspenders for hosts
who prefer to capture at the endpoint.

---

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