# `Accrue.Mailer.Default`
[🔗](https://github.com/szTheory/accrue/blob/accrue-v0.3.0/lib/accrue/mailer/default.ex#L1)

Default `Accrue.Mailer` adapter — enqueues an Oban job on the
`:accrue_mailers` queue that a worker later turns into a delivered email.

## Pay-style override ladder (D-23)

This adapter documents the Pay-inspired four-rung override ladder but
Phase 1 implements only rungs 1 and 3. The full catalog lands in Phase 6.

1. **Kill switch** (`:emails` config) — `Accrue.Mailer.deliver/2`
   short-circuits before this adapter is reached. Handled at the
   behaviour layer.
2. MFA conditional (`:emails` value is `{Mod, :fun, args}`) — Phase 6.
3. **Template module override** (`:email_overrides` config) — resolved
   in `Accrue.Workers.Mailer.resolve_template/1`.
4. Full pipeline replace (`:mailer` config pointing at a custom
   module) — already supported via `Accrue.Mailer.impl/0`.

## Oban args safety (D-27, Pitfall #5, T-MAIL-01)

Oban persists job `args` as JSONB. The `assigns` map MUST contain only
scalars (no structs, pids, functions, refs) so a worker crash mid-job
doesn't corrupt the queue and so sensitive structs don't leak into the
`oban_jobs` table. `only_scalars!/1` walks the map and raises
`ArgumentError` on any non-primitive value. The convention is:
**pass entity IDs, not entity structs**. The worker rehydrates at
delivery time.

# `only_scalars!`

```elixir
@spec only_scalars!(map()) :: map()
```

Walks `map` and raises `ArgumentError` if any value is not
Oban-JSON-safe. Returns the map unchanged on success.

Allowed leaf types: `nil`, atom, binary, number, boolean. Maps and
lists are recursed.

---

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