# `Mailglass.Config`
[🔗](https://github.com/szTheory/mailglass/blob/v0.1.0/lib/mailglass/config.ex#L1)

Runtime configuration for mailglass, validated at boot via NimbleOptions.

**Only this module may call `Application.compile_env*`.** Every other module
reads configuration through `Application.get_env/2` (enforced by the
`LINT-08` Credo check in Phase 6).

The brand theme (D-19) is cached in `:persistent_term` after validation so
the render hot path reads it in O(1) without re-parsing the Application env
on every message.

## Options

* `:repo` - The adopter's Ecto.Repo module. Required from Phase 2+ onwards. The default value is `nil`.

* `:adapter` (`t:term/0`) - Adapter module or `{module, opts}` tuple. Default: the Fake adapter. The default value is `{Mailglass.Adapters.Fake, []}`.

* `:theme` (`t:keyword/0`) - Brand theme tokens. See `Mailglass.Components.Theme`. The default value is `[]`.

  * `:colors` (`t:map/0`) - Brand color map. Keys: `:ink`, `:glass`, `:ice`, `:mist`, `:paper`, `:slate`. The default value is `%{ink: "#0D1B2A", glass: "#277B96", ice: "#A6EAF2", mist: "#EAF6FB", paper: "#F8FBFD", slate: "#5C6B7A"}`.

  * `:fonts` (`t:map/0`) - Font-stack map. Keys: `:body`, `:display`, `:mono`. The default value is `%{display: "'Inter Tight', 'Inter', sans-serif", body: "'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif", mono: "'IBM Plex Mono', ui-monospace, monospace"}`.

* `:telemetry` (`t:keyword/0`) - Telemetry options. The default value is `[]`.

  * `:default_logger` (`t:boolean/0`) - Attach the default logger handler at boot. Default: `false`. The default value is `false`.

* `:renderer` (`t:keyword/0`) - Renderer options. The default value is `[]`.

  * `:css_inliner` - CSS inlining backend. Default: `:premailex`. The default value is `:premailex`.

  * `:plaintext` (`t:boolean/0`) - Auto-generate a plaintext body alongside the HTML body. Default: `true`. The default value is `true`.

* `:tenancy` - Module implementing `Mailglass.Tenancy`. Default: `nil` (single-tenant mode). The default value is `nil`.

* `:suppression_store` - Module implementing `Mailglass.SuppressionStore`. Default: `Mailglass.SuppressionStore.Ecto`. The default value is `Mailglass.SuppressionStore.Ecto`.

* `:async_adapter` - Async delivery adapter for `deliver_later/2`. `:oban` (default, durable) or `:task_supervisor` (non-durable fallback). Use `:task_supervisor` to silence the boot warning when Oban is deliberately not in deps. The default value is `:oban`.

* `:rate_limit` (`t:keyword/0`) - Rate-limiter configuration (SEND-02). The default value is `[]`.

  * `:default` (`t:keyword/0`) - Default per-(tenant, domain) bucket. Capacity + per-minute refill. The default value is `[capacity: 100, per_minute: 100]`.

  * `:overrides` (list of `t:term/0`) - Per-(tenant_id, domain) overrides as list of {{tenant_id, domain}, opts} tuples. The default value is `[]`.

* `:tracking` (`t:keyword/0`) - Open/click tracking configuration (TRACK-03). When any mailable enables opens or clicks, `:host` is REQUIRED or boot raises `%ConfigError{type: :tracking_host_missing}`. The default value is `[]`.

  * `:host` - Tracking subdomain (e.g. `track.example.com`). Must be separate from the adopter's main app host. The default value is `nil`.

  * `:scheme` - URL scheme. `http` only for dev. The default value is `"https"`.

  * `:salts` (list of `t:String.t/0`) - Phoenix.Token salts. Head signs; all verify (rotation support). The default value is `[]`.

  * `:max_age` (`t:pos_integer/0`) - Token max age in seconds. Default: 2 years. The default value is `63072000`.

* `:clock` - Module implementing `utc_now/0`. Default: `Mailglass.Clock.System`. Tests use `Mailglass.Clock.Frozen`-backed per-process freezing without overriding this key. The default value is `nil`.

* `:postmark` (`t:keyword/0`) - Postmark webhook configuration (HOOK-03). The default value is `[]`.

  * `:enabled` (`t:boolean/0`) - Enable the Postmark webhook route. Default: `true`. The default value is `true`.

  * `:basic_auth` - Basic Auth `{user, password}` tuple. Required for signature verification; omit only if the provider is disabled. The default value is `nil`.

  * `:ip_allowlist` (list of `t:String.t/0`) - Opt-in list of CIDR strings (e.g. `["50.31.156.0/24"]`). Off by default per D-04 — Postmark's origin IPs can change. The default value is `[]`.

* `:sendgrid` (`t:keyword/0`) - SendGrid webhook configuration (HOOK-04). The default value is `[]`.

  * `:enabled` (`t:boolean/0`) - Enable the SendGrid webhook route. Default: `true`. The default value is `true`.

  * `:public_key` - Base64-encoded SubjectPublicKeyInfo DER (NOT PEM — SendGrid's dashboard ships raw DER without `-----BEGIN PUBLIC KEY-----` framing). Required for signature verification; omit only if the provider is disabled. The default value is `nil`.

  * `:timestamp_tolerance_seconds` (`t:pos_integer/0`) - Replay tolerance window in seconds. Default: `300` (Stripe / Svix / Standard Webhooks consensus). The default value is `300`.

* `:webhook_retention` (`t:keyword/0`) - Retention policy for `mailglass_webhook_events` rows (HOOK-06). The default value is `[]`.

  * `:succeeded_days` - Days to retain `:succeeded` webhook_events before the Pruner deletes them. Set to `:infinity` to disable. Default: 14. The default value is `14`.

  * `:dead_days` - Days to retain `:dead` (terminal-after-retries) webhook_events before the Pruner deletes them. Set to `:infinity` to disable. Default: 90. The default value is `90`.

  * `:failed_days` - Days to retain `:failed` (investigatable) webhook_events. Default: `:infinity` (never prune). The default value is `:infinity`.

## Boot sequence

    # lib/mailglass/application.ex
    def start(_type, _args) do
      Mailglass.Config.validate_at_boot!()
      # ...
    end

Raises `NimbleOptions.ValidationError` on invalid configuration. Raising at
boot is intentional — a misconfigured mailer should never limp into
production serving half-rendered mail.

# `get_theme`
*since 0.1.0* 

```elixir
@spec get_theme() :: keyword()
```

Returns the cached brand theme keyword list.

Requires `validate_at_boot!/0` to have been called first. Returns an empty
list if the cache is unset (the caller is responsible for ensuring the boot
sequence has completed).

# `new!`
*since 0.1.0* 

```elixir
@spec new!(keyword()) :: keyword()
```

Validates and returns a keyword list of options.

Fills in defaults, raises `NimbleOptions.ValidationError` on unknown keys
or invalid values. Used primarily by `validate_at_boot!/0`; callers rarely
invoke this directly.

## Examples

    iex> config = Mailglass.Config.new!([])
    iex> Keyword.fetch!(config, :adapter)
    {Mailglass.Adapters.Fake, []}

# `validate_at_boot!`
*since 0.1.0* 

```elixir
@spec validate_at_boot!() :: :ok
```

Reads the `:mailglass` Application env, validates it against the schema,
and caches the brand theme in `:persistent_term`.

Called from `Mailglass.Application.start/2`. Raises
`NimbleOptions.ValidationError` if the Application env is invalid.

When `[telemetry: [default_logger: true]]` is configured, the default
logger handler is attached here.

---

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