# `Letterbox.Plug`
[🔗](https://github.com/hattoriai/letterbox/blob/v0.1.0-rc.0/lib/letterbox/plug.ex#L1)

The webhooks of the ingresses (`Letterbox.Ingress`), a route of the
app's own router. `mix letterbox.install` writes one for every
ingress, the ingress named by the path:

    scope "/inbound" do
      pipe_through :webhooks
      post "/webhooks/:ingress", Letterbox.Plug, []
    end

The path, the scope and the pipeline are the app's to change: nothing
in Letterbox depends on them. A route can also name its ingress, one
route for each, at any path:

    post "/mail/resend", Letterbox.Plug, ingress: :resend
    post "/hooks/postfix", Letterbox.Plug, ingress: :relay

The ingress is the route's `:ingress` option, else the `:ingress`
parameter of its path. In an app without Phoenix's router, it is a Plug
like any other (`forward "/inbound/resend", Letterbox.Plug, ingress:
:resend`).

It answers:

  * `204` - the request was the ingress's, and what it brought is kept
    (or, for an email to fetch, noted): the provider stops sending it.
    Again for a message already kept.
  * `401` - it was not the ingress's (`verify/3` refused it).
  * `404` - no ingress of that name.
  * `413` - the body is larger than `:max_bytes` (`Letterbox.Config`).
  * `422` - the ingress could not read it.
  * `500` - it could not be kept (the store, the database): the
    provider sends it again later.

The route takes no session and no CSRF token: a provider has neither.
Its pipeline must not have `:protect_from_forgery`.

A signed webhook needs its body as it was sent: the plug declares it
(`use PhoenixMountable.RawBody`), and the endpoint's `Plug.Parsers`
keeps it with `body_reader: {PhoenixMountable.RawBody, :read_body,
[MyAppWeb.Router]}`, which `mix letterbox.install` adds. A relay's raw
email (`message/rfc822`) is passed by the parsers unread, and needs no
copy.

---

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