# `SquatchMail.Adapters.Watchtower`
[🔗](https://github.com/Axio-Intelligence/Squatch-Mail/blob/v0.1.0/lib/squatch_mail/adapters/watchtower.ex#L1)

An opt-in Swoosh adapter that enforces `SquatchMail.Guard`'s guardrails
ahead of a wrapped real adapter.

This is the LaraSend-parity "proxy mode" from RESEARCH.md, applied to
guardrails specifically: instead of only *observing* sends via telemetry
(see `SquatchMail.Capture`), Watchtower sits directly in the send path so
a suppressed recipient or an auto-paused account can actually **block**
the send rather than just be recorded after the fact.

This is entirely optional — most hosts should prefer `SquatchMail.Capture`
(pure observation, zero risk of ever blocking a legitimate send by
mistake) and only reach for Watchtower if they want suppressions and the
complaint-rate auto-pause enforced *before* SES ever sees the request,
rather than after the fact via `SquatchMail.Guard.check/1` called
manually.

## Usage

Configure a mailer to use Watchtower with the real ("watched") adapter and
its own config flattened alongside it, under `:watched_adapter`:

    config :my_app, MyApp.Mailer,
      adapter: SquatchMail.Adapters.Watchtower,
      watched_adapter: Swoosh.Adapters.AmazonSES,
      region: "us-east-1",
      access_key: System.fetch_env!("AWS_ACCESS_KEY_ID"),
      secret: System.fetch_env!("AWS_SECRET_ACCESS_KEY")

Watchtower itself declares no `required_config` of its own beyond
`:watched_adapter` — everything else in `config` is passed straight
through to the watched adapter untouched, including its own required
keys, which are validated in `validate_config/1` by delegating to the
watched adapter (with `:watched_adapter` stripped out first).

## All-or-nothing batches

`deliver_many/2` checks every recipient across the *entire* batch before
sending any of it. If any recipient anywhere in the batch is suppressed
(or the account is paused), the whole call returns
`{:error, {:suppressed, addresses}}` (or `{:error, :complaint_rate_paused}`)
and **none** of the emails are sent — not even the ones with clean
recipients. This is a deliberate simplicity/safety trade-off: partial
sends would mean silently reordering or splitting a batch the caller
asked to send atomically, and would require inventing a per-email result
shape for a mixed outcome. A caller that wants partial delivery on
suppression should call `deliver/2` per email instead.

## Capture interplay

A blocked send still returns `{:error, reason}` from `deliver/2`, which
means `Swoosh.Mailer` still emits its `[:swoosh, :deliver, :stop]`
telemetry (with that error in metadata) exactly as it would for any other
adapter failure — so `SquatchMail.Capture` still records the attempt. See
`SquatchMail.Capture` for how `{:suppressed, _}` is recorded with status
`"suppressed"` rather than `"failed"`.

# `validate_config`

Validates the watched adapter's own config.

Requires `:watched_adapter` to be present, then delegates to that
adapter's `validate_config/1` with `:watched_adapter` stripped from the
config (so the watched adapter only ever sees keys it understands).
Adapters that don't export `validate_config/1` (not part of the
`Swoosh.Adapter` behaviour's required callbacks in every version) are
treated as passing validation.

---

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