Mailglass.Config (Mailglass v1.0.0)

Copy Markdown View Source

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

  • :feedback_id - Optional Feedback-ID prefix (RFC 8058/Deliverability). When set, auto-populates as {sender_id}:{mailable}:{tenant_id}:{stream}. The default value is nil.

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

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

  • :adapters (list of term/0) - Optional named adapter registry for runtime route refs. Each entry is {ref, module} or {ref, {module, opts}}, where ref is an atom or string. The default value is [].

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

    • :colors (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 (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 (keyword/0) - Telemetry options. The default value is [].

    • :default_logger (boolean/0) - Attach the default logger handler at boot. Default: false. The default value is false.
  • :renderer (keyword/0) - Renderer options. The default value is [].

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

    • :plaintext (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 (keyword/0) - Rate-limiter configuration (RATE-01). The default value is [].

    • :tenant_recipient (keyword/0) - Per-{tenant, domain} rate limits. The default value is [].

      • :default (keyword/0) - Default per-{tenant, domain} bucket. The default value is [capacity: 100, per_minute: 100].

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

    • :global_recipient (keyword/0) - Global per-recipient domain rate limits. The default value is [].

      • :default (keyword/0) - Default global per-domain bucket. The default value is [capacity: 1000, per_minute: 1000].

      • :overrides (list of term/0) - Global per-domain overrides as {domain, opts}. The default value is [].

    • :sender_domain (keyword/0) - Global per-sender domain rate limits. The default value is [].

      • :default (keyword/0) - Default global per-sender domain bucket. The default value is [capacity: 500, per_minute: 500].

      • :overrides (list of term/0) - Global per-sender domain overrides as {domain, opts}. The default value is [].

  • :tracking (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 [].

    • :endpoint - Phoenix.Token endpoint/secret override for open/click tracking. When nil, Mailglass.Tracking.endpoint/0 falls back to :adapter_endpoint. The default value is nil.

    • :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 String.t/0) - Phoenix.Token salts. Head signs; all verify (rotation support). The default value is [].

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

  • :compliance (keyword/0) - RFC 8058 unsubscribe configuration. Phase 11 reads this subtree through Mailglass.Config accessors only so router/controller/token code avoids new direct compile-env lookups. The default value is [].

    • :endpoint - Phoenix.Token endpoint/secret override for unsubscribe signing. When nil, Mailglass.Config.compliance_endpoint/0 falls back to the tracking endpoint chain. The default value is nil.

    • :host - Canonical host used for unsubscribe URLs (for example unsubscribe.example.com). The default value is nil.

    • :scheme - Unsubscribe URL scheme. http is intended for local development only. The default value is "https".

    • :mount_path (String.t/0) - Absolute path prefix used when generating unsubscribe URLs. The default value is "/mailglass/unsubscribe".

    • :previous_secrets (list of String.t/0) - Raw prior secret_key_base values accepted during unsubscribe token verification after endpoint-secret rotation. The default value is [].

    • :redirect - Optional GET unsubscribe redirect escape hatch (for example /settings/unsubscribe). The default value is nil.

    • :max_age (pos_integer/0) - Unsubscribe token max age in seconds. Default: 2 years. The default value is 63072000.

    • :lifecycle (atom/0) - Module implementing Mailglass.Lifecycle for transaction-local unsubscribe side effects. The default value is Mailglass.Lifecycle.Noop.

  • :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 (keyword/0) - Postmark webhook configuration (HOOK-03). The default value is [].

    • :enabled (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 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 (keyword/0) - SendGrid webhook configuration (HOOK-04). The default value is [].

    • :enabled (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 (pos_integer/0) - Replay tolerance window in seconds. Default: 300 (Stripe / Svix / Standard Webhooks consensus). The default value is 300.

  • :mailgun (keyword/0) - Mailgun webhook configuration. The default value is [].

    • :enabled (boolean/0) - Enable the Mailgun webhook route when explicitly mounted. The default value is true.

    • :signing_key - Mailgun webhook signing key used for HMAC verification. Required for signature verification; omit only if the provider is disabled. The default value is nil.

    • :timestamp_tolerance_seconds (pos_integer/0) - Maximum accepted age for the Mailgun signature timestamp in seconds. Default: 28_800. The default value is 28800.

    • :future_skew_seconds (pos_integer/0) - Maximum accepted future skew for the Mailgun signature timestamp in seconds. Default: 300. The default value is 300.

    • :replay_cache_ttl_seconds (pos_integer/0) - Replay cache retention window for Mailgun tokens in seconds. Default: 28_800. The default value is 28800.

  • :ses (keyword/0) - SES webhook configuration. The default value is [].

    • :enabled (boolean/0) - Enable the SES webhook route when explicitly mounted. The default value is true.

    • :cert_cache_ttl_seconds (pos_integer/0) - TTL in seconds for cached SNS signing certificates. Default: 86_400. The default value is 86400.

  • :resend (keyword/0) - Resend webhook configuration. The default value is [].

    • :enabled (boolean/0) - Enable the Resend webhook route when explicitly mounted. The default value is true.

    • :secret - Svix webhook secret used for Resend signature verification. Required for verification; omit only if the provider is disabled. The default value is nil.

    • :timestamp_tolerance_seconds (pos_integer/0) - Maximum accepted age for the Svix timestamp in seconds. Default: 300. The default value is 300.

  • :webhook_retention (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.

Summary

Functions

Returns the validated named adapter registry keyed by stable route ref.

Returns the validated compliance subtree with defaults applied.

Resolves the current unsubscribe signing endpoint.

Returns the validated global default adapter as {module, opts}.

Returns the cached brand theme keyword list.

Validates and returns a keyword list of options.

Resolves a named adapter ref into the normalized {module, opts} shape.

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

Functions

adapters()

(since 0.4.0)
@spec adapters() :: %{optional(atom() | String.t()) => {module(), keyword()}}

Returns the validated named adapter registry keyed by stable route ref.

compliance()

(since 0.1.0)
@spec compliance() :: keyword()

Returns the validated compliance subtree with defaults applied.

compliance_endpoint()

(since 0.1.0)
@spec compliance_endpoint() :: module() | binary()

Resolves the current unsubscribe signing endpoint.

Falls back to Mailglass.Tracking.endpoint/0 so unsubscribe tokens reuse the same endpoint-secret chain unless adopters opt into a compliance-specific override.

compliance_host()

(since 0.1.0)
@spec compliance_host() :: String.t() | nil

compliance_lifecycle()

(since 0.1.0)
@spec compliance_lifecycle() :: module()

compliance_max_age()

(since 0.1.0)
@spec compliance_max_age() :: pos_integer()

compliance_mount_path()

(since 0.1.0)
@spec compliance_mount_path() :: String.t()

compliance_previous_secrets()

(since 0.1.0)
@spec compliance_previous_secrets() :: [String.t()]

compliance_redirect()

(since 0.1.0)
@spec compliance_redirect() :: String.t() | nil

compliance_scheme()

(since 0.1.0)
@spec compliance_scheme() :: String.t()

default_adapter()

(since 0.4.0)
@spec default_adapter() :: {module(), keyword()}

Returns the validated global default adapter as {module, opts}.

get_theme()

(since 0.1.0)
@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!(opts \\ [])

(since 0.1.0)
@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, []}

resolve_adapter_ref(ref)

(since 0.4.0)
@spec resolve_adapter_ref(atom() | String.t()) :: {module(), keyword()}

Resolves a named adapter ref into the normalized {module, opts} shape.

validate_at_boot!()

(since 0.1.0)
@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.