# Mailglass v0.1.0 - Table of Contents Transactional email framework for Phoenix. Composes on Swoosh ## Pages - Overview - [Mailglass](readme.md) - [CLAUDE.md — mailglass](claude.md) - Guides - [Getting Started](getting-started.md) - [Authoring Mailables](authoring-mailables.md) - [Components](components.md) - [Preview](preview.md) - [Mailglass Webhooks Guide](webhooks.md) - [Multi-Tenancy](multi-tenancy.md) - [Telemetry](telemetry.md) - [Testing](testing.md) - [Migration from raw Swoosh](migration-from-swoosh.md) - Maintainers - [Maintaining Mailglass](maintaining.md) - [Contributing to Mailglass](contributing.md) - [Security Policy](security.md) - [Contributor Covenant Code of Conduct](code_of_conduct.md) ## Modules - [Mailglass.Clock](Mailglass.Clock.md): The single legitimate source of wall-clock time in mailglass (TEST-05). Phase 6 `LINT-12 NoDirectDateTimeNow` forbids `DateTime.utc_now/0` outside this module. - [Mailglass.Clock.Frozen](Mailglass.Clock.Frozen.md): Test helper that freezes `Mailglass.Clock.utc_now/0` in the current process. Per-process isolation makes it `async: true`-safe. - [Mailglass.Clock.System](Mailglass.Clock.System.md): Production clock impl. Wraps `DateTime.utc_now/0`. - [Mailglass.Compliance](Mailglass.Compliance.md): Injects RFC-required and mailglass-specific headers into outbound messages. - [Mailglass.Components.CSS](Mailglass.Components.CSS.md): CSS style-string utilities for email component rendering. - [Mailglass.Components.Layout](Mailglass.Components.Layout.md): Email document layout with MSO head and CSS reset. - [Mailglass.Components.Theme](Mailglass.Components.Theme.md): Theme-token resolver backed by `:persistent_term`. - [Mailglass.Credo.NoBareOptionalDepReference](Mailglass.Credo.NoBareOptionalDepReference.md): ## Basics - [Mailglass.Credo.NoCompileEnvOutsideConfig](Mailglass.Credo.NoCompileEnvOutsideConfig.md): ## Basics - [Mailglass.Credo.NoDefaultModuleNameSingleton](Mailglass.Credo.NoDefaultModuleNameSingleton.md): ## Basics - [Mailglass.Credo.NoDirectDateTimeNow](Mailglass.Credo.NoDirectDateTimeNow.md): ## Basics - [Mailglass.Credo.NoFullResponseInLogs](Mailglass.Credo.NoFullResponseInLogs.md): ## Basics - [Mailglass.Credo.NoOtherAppEnvReads](Mailglass.Credo.NoOtherAppEnvReads.md): ## Basics - [Mailglass.Credo.NoOversizedUseInjection](Mailglass.Credo.NoOversizedUseInjection.md): ## Basics - [Mailglass.Credo.NoPiiInTelemetryMeta](Mailglass.Credo.NoPiiInTelemetryMeta.md): ## Basics - [Mailglass.Credo.NoRawSwooshSendInLib](Mailglass.Credo.NoRawSwooshSendInLib.md): ## Basics - [Mailglass.Credo.NoTrackingOnAuthStream](Mailglass.Credo.NoTrackingOnAuthStream.md): ## Basics - [Mailglass.Credo.NoUnscopedTenantQueryInLib](Mailglass.Credo.NoUnscopedTenantQueryInLib.md): ## Basics - [Mailglass.Credo.PrefixedPubSubTopics](Mailglass.Credo.PrefixedPubSubTopics.md): ## Basics - [Mailglass.Credo.TelemetryEventConvention](Mailglass.Credo.TelemetryEventConvention.md): ## Basics - [Mailglass.Error](Mailglass.Error.md): Namespace and behaviour for the mailglass error hierarchy. - [Mailglass.Events.Event](Mailglass.Events.Event.md): Append-only row in `mailglass_events`. - [Mailglass.Events.Reconciler](Mailglass.Events.Reconciler.md): Pure Ecto query functions for orphan-webhook reconciliation (D-19). - [Mailglass.Gettext](Mailglass.Gettext.md): Gettext backend for mailglass default strings. - [Mailglass.IdempotencyKey](Mailglass.IdempotencyKey.md): Generates deterministic idempotency keys for webhook deduplication and event-ledger entries. - [Mailglass.Installer.Apply](Mailglass.Installer.Apply.md): Applies installer operations with deterministic ordering and outcome labels. - [Mailglass.Installer.Conflict](Mailglass.Installer.Conflict.md): Conflict sidecar writer used when installer changes cannot be applied safely. - [Mailglass.Installer.Manifest](Mailglass.Installer.Manifest.md): `.mailglass.toml` manifest helpers for deterministic installer reruns. - [Mailglass.Installer.Operation](Mailglass.Installer.Operation.md): Typed operation contract used by the installer planner and apply engine. - [Mailglass.Installer.Plan](Mailglass.Installer.Plan.md): Deterministic installer plan builder. - [Mailglass.Installer.Templates](Mailglass.Installer.Templates.md): Installer template helpers for owned files and managed shared-file patches. - [Mailglass.Oban.TenancyMiddleware](Mailglass.Oban.TenancyMiddleware.md): Serializes `Mailglass.Tenancy.current/0` across Oban job boundaries (D-33). - [Mailglass.OptionalDeps](Mailglass.OptionalDeps.md): Namespace for optional dependency gateway modules. - [Mailglass.OptionalDeps.GenSmtp](Mailglass.OptionalDeps.GenSmtp.md): Gateway for the optional gen_smtp dependency (`{:gen_smtp, "~> 1.3"}`). - [Mailglass.OptionalDeps.Mjml](Mailglass.OptionalDeps.Mjml.md): Gateway for the optional MJML NIF dependency (`{:mjml, "~> 5.3"}`). - [Mailglass.OptionalDeps.OpenTelemetry](Mailglass.OptionalDeps.OpenTelemetry.md): Gateway for the optional OpenTelemetry dependency (`{:opentelemetry, "~> 1.7"}`). - [Mailglass.OptionalDeps.Sigra](Mailglass.OptionalDeps.Sigra.md): Gateway for the optional Sigra integration (`{:sigra, "~> 0.2"}`). - [Mailglass.Outbound.Delivery](Mailglass.Outbound.Delivery.md): One row per (Message, recipient, provider) tuple. Mutable: projection columns are updated by `Mailglass.Outbound.Projector` (Plan 06). - [Mailglass.PubSub.Topics](Mailglass.PubSub.Topics.md): Typed topic builder for `Mailglass.PubSub` (SEND-05, D-27). Every topic is prefixed `mailglass:` — Phase 6 `LINT-06 PrefixedPubSubTopics` enforces the prefix at lint time. - [Mailglass.RateLimiter](Mailglass.RateLimiter.md): Per-`{tenant_id, recipient_domain}` ETS token bucket (SEND-02). - [Mailglass.RateLimiter.Supervisor](Mailglass.RateLimiter.Supervisor.md): Supervises `Mailglass.RateLimiter.TableOwner` (D-22). - [Mailglass.RateLimiter.TableOwner](Mailglass.RateLimiter.TableOwner.md): Init-and-idle GenServer owning the `:mailglass_rate_limit` ETS table (D-22). Owns nothing beyond ETS table creation — no `handle_call/3`, `handle_cast/2`, or `handle_info/2` implementations. Hot-path reads and writes happen directly from caller processes via `:ets.update_counter/4` — NO GenServer mailbox serialization. - [Mailglass.Repo](Mailglass.Repo.md): Thin facade over the host-configured `Ecto.Repo`. - [Mailglass.Schema](Mailglass.Schema.md): Stamps mailglass-wide schema conventions onto a module. - [Mailglass.Stream](Mailglass.Stream.md): Stream policy seam (SEND-01 stage 3, D-25). - [Mailglass.Suppression.Entry](Mailglass.Suppression.Entry.md): Ecto schema for a row in `mailglass_suppressions`. - [Mailglass.SuppressionStore](Mailglass.SuppressionStore.md): Behaviour for suppression-list storage backends. - [Mailglass.SuppressionStore.ETS](Mailglass.SuppressionStore.ETS.md): ETS-backed implementation of `Mailglass.SuppressionStore` (D-28). - [Mailglass.SuppressionStore.ETS.TableOwner](Mailglass.SuppressionStore.ETS.TableOwner.md): Init-and-idle GenServer owning the `:mailglass_suppression_store` ETS table. Same pattern as `Mailglass.RateLimiter.TableOwner` (D-22). - [Mailglass.Telemetry](Mailglass.Telemetry.md): Telemetry integration for mailglass. - [Mailglass.TemplateEngine](Mailglass.TemplateEngine.md): Behaviour for mailglass template engines. - [Mailglass.Tenancy.ResolveFromPath](Mailglass.Tenancy.ResolveFromPath.md): Opt-in URL-prefix tenant resolver (D-12 sugar). - [Mailglass.Tenancy.SingleTenant](Mailglass.Tenancy.SingleTenant.md): Default `Mailglass.Tenancy` resolver: `scope/2` is a no-op; `resolve_webhook_tenant/1` returns `{:ok, "default"}`. - [Mailglass.Tracking](Mailglass.Tracking.md): Tracking public facade. Off by default per TRACK-01 / D-08. - [Mailglass.Tracking.ConfigValidator](Mailglass.Tracking.ConfigValidator.md): Boot-time validator for TRACK-03 configuration (D-32). - [Mailglass.Tracking.Guard](Mailglass.Tracking.Guard.md): Runtime auth-stream tracking guard (D-38). - [Mailglass.Tracking.Plug](Mailglass.Tracking.Plug.md): Mountable Plug endpoint for open-pixel + click-redirect URLs (TRACK-03). - [Mailglass.Tracking.Rewriter](Mailglass.Tracking.Rewriter.md): Pure HTML transform: open-pixel injection + click link rewriting (TRACK-03). - [Mailglass.Tracking.Token](Mailglass.Tracking.Token.md): Phoenix.Token-signed tokens for open pixel + click redirect URLs (TRACK-03, D-33..D-35). - [Mailglass.Webhook.CachingBodyReader](Mailglass.Webhook.CachingBodyReader.md): Custom `Plug.Parsers` `:body_reader` that preserves raw request bytes in `conn.private[:raw_body]` for HMAC verification while still allowing JSON parsing downstream. - [Mailglass.Webhook.Ingest](Mailglass.Webhook.Ingest.md): Webhook ingest — the single `Ecto.Multi` that HOOK-06 reduces to. - [Mailglass.Webhook.Providers.Postmark](Mailglass.Webhook.Providers.Postmark.md): Postmark webhook verifier + normalizer. - [Mailglass.Webhook.Providers.SendGrid](Mailglass.Webhook.Providers.SendGrid.md): SendGrid Event Webhook verifier + normalizer. - [Mailglass.Webhook.Telemetry](Mailglass.Webhook.Telemetry.md): Co-located span helpers for the webhook ingest surface (CONTEXT D-22). - [Mailglass.Webhook.WebhookEvent](Mailglass.Webhook.WebhookEvent.md): Ecto schema for the `mailglass_webhook_events` table (V02 migration, Plan 04-01). Mutable + prunable — UNLIKE `mailglass_events` which is append-only via the SQLSTATE 45A01 trigger (CONTEXT D-15 split). - Core - [Mailglass](Mailglass.md): Transactional email framework for Phoenix. - [Mailglass.Config](Mailglass.Config.md): Runtime configuration for mailglass, validated at boot via NimbleOptions. - [Mailglass.Events](Mailglass.Events.md): Append-only event writer. The only legitimate path to `mailglass_events`. Phase 6 `NoRawEventInsert` Credo check enforces that no other code calls `Repo.insert(%Event{})` or `Repo.insert_all("mailglass_events", ...)`. - [Mailglass.Message](Mailglass.Message.md): A rendered or partially-rendered email message. - [Mailglass.Outbound](Mailglass.Outbound.md): Public facade for the mailglass send pipeline (TRANS-04, SEND-01). - Authoring - [Mailglass.Components](Mailglass.Components.md): HEEx function components for transactional email composition. - [Mailglass.Mailable](Mailglass.Mailable.md): Behaviour + `use` macro for adopter-defined mailable modules (AUTHOR-01). - [Mailglass.Renderer](Mailglass.Renderer.md): Pure-function render pipeline: HEEx → plaintext → CSS inlining → data-mg-* strip. - Transport - [Mailglass.Adapter](Mailglass.Adapter.md): Behaviour every mailglass adapter implements (TRANS-01). - [Mailglass.Adapters.Fake](Mailglass.Adapters.Fake.md): In-memory, time-advanceable test adapter (TRANS-02, D-01..D-03). - [Mailglass.Adapters.Swoosh](Mailglass.Adapters.Swoosh.md): Adapter bridging to any `Swoosh.Adapter` (TRANS-03). - Webhooks - [Mailglass.Webhook](Mailglass.Webhook.md): Webhook boundary root. - [Mailglass.Webhook.Plug](Mailglass.Webhook.Plug.md): Single-ingress webhook orchestrator (CONTEXT D-10). - [Mailglass.Webhook.Router](Mailglass.Webhook.Router.md): Router macro for mounting Mailglass webhook endpoints in an adopter Phoenix router. - Operations - [Mailglass.Tenancy](Mailglass.Tenancy.md): Tenancy behaviour + process-dict helpers. - [Mailglass.TestAssertions](Mailglass.TestAssertions.md): Test assertions extending Swoosh.TestAssertions (TEST-01, D-05). - Internal - [Mailglass.Adapters.Fake.Storage](Mailglass.Adapters.Fake.Storage.md): GenServer owning the `:mailglass_fake_mailbox` ETS table. Mirrors `Swoosh.Adapters.Sandbox.Storage` pattern: the GenServer handles ownership mutations (`checkout`, `checkin`, `allow`, `set_shared`, `find_owner`, `{:DOWN, ...}`) but READS happen directly against ETS to bypass the mailbox. - [Mailglass.Adapters.Fake.Supervisor](Mailglass.Adapters.Fake.Supervisor.md): Supervises `Mailglass.Adapters.Fake.Storage`. Started unconditionally in `Mailglass.Application` (D-02) via the `Code.ensure_loaded?/1`-gated `maybe_add/3` call placed in Plan 01 (I-08). - [Mailglass.Application](Mailglass.Application.md): Supervision tree for the Mailglass framework. - [Mailglass.Migration](Mailglass.Migration.md): Public migration API for mailglass. - [Mailglass.Migrations.Postgres](Mailglass.Migrations.Postgres.md): Internal migration runner for Postgres. - [Mailglass.OptionalDeps.Oban](Mailglass.OptionalDeps.Oban.md): Gateway for the optional Oban dependency (`{:oban, "~> 2.21"}`). - [Mailglass.Outbound.Projector](Mailglass.Outbound.Projector.md): The single place where `mailglass_deliveries` projection columns are updated (D-14). Consumed by Phase 3 dispatch, Phase 4 webhook ingest, and Phase 4+ orphan reconciliation. No projection update happens outside this module — a Phase 6 candidate Credo check (`NoProjectorOutsideOutbound`) will enforce at lint time. - [Mailglass.Outbound.Worker](Mailglass.Outbound.Worker.md): Oban worker that dispatches a queued Delivery (SEND-03). Conditionally compiled — entire module elided when `:oban` is not loaded. - [Mailglass.PubSub](Mailglass.PubSub.md): Name atom for the mailglass-owned Phoenix.PubSub child. - [Mailglass.Suppression](Mailglass.Suppression.md): Public preflight facade for suppression checks (SEND-04). - [Mailglass.SuppressionStore.ETS.Supervisor](Mailglass.SuppressionStore.ETS.Supervisor.md): Supervises `Mailglass.SuppressionStore.ETS.TableOwner` (D-22). - [Mailglass.SuppressionStore.Ecto](Mailglass.SuppressionStore.Ecto.md): Default Ecto-backed `Mailglass.SuppressionStore` implementation. - [Mailglass.TemplateEngine.HEEx](Mailglass.TemplateEngine.HEEx.md): Default HEEx template engine for mailglass. - [Mailglass.Webhook.Provider](Mailglass.Webhook.Provider.md): Behaviour for webhook providers (SendGrid, Postmark, etc). - [Mailglass.Webhook.Pruner](Mailglass.Webhook.Pruner.md): Oban cron worker that prunes `mailglass_webhook_events` rows by status + age (CONTEXT D-16). - [Mailglass.Webhook.Reconciler](Mailglass.Webhook.Reconciler.md): Oban cron worker that closes the orphan-webhook race window (CONTEXT D-17, D-18). - Exceptions - [Mailglass.ConfigError](Mailglass.ConfigError.md): Raised when mailglass is misconfigured. - [Mailglass.Error.BatchFailed](Mailglass.Error.BatchFailed.md): Raised by `Mailglass.Outbound.deliver_many!/2` when one or more deliveries in the batch have `status: :failed`. - [Mailglass.EventLedgerImmutableError](Mailglass.EventLedgerImmutableError.md): Raised when the `mailglass_events` append-only immutability trigger fires. - [Mailglass.RateLimitError](Mailglass.RateLimitError.md): Raised when a rate limit is exceeded. - [Mailglass.SendError](Mailglass.SendError.md): Raised when email delivery fails. - [Mailglass.SignatureError](Mailglass.SignatureError.md): Raised when webhook signature verification fails. - [Mailglass.SuppressedError](Mailglass.SuppressedError.md): Raised when delivery is blocked by the suppression list. - [Mailglass.TemplateError](Mailglass.TemplateError.md): Raised when a template cannot be compiled or rendered. - [Mailglass.TenancyError](Mailglass.TenancyError.md): Raised when tenant context is required but not stamped on the process. ## Mix Tasks - [mix mailglass.gen.migration](Mix.Tasks.Mailglass.Gen.Migration.md): Generates the 8-line wrapper migration file in `priv/repo/migrations/` that delegates `up/0` and `down/0` to `Mailglass.Migration`. - [mix mailglass.install](Mix.Tasks.Mailglass.Install.md): Install mailglass into a Phoenix host app. - [mix mailglass.publish.check](Mix.Tasks.Mailglass.Publish.Check.md): Verify the published tarball before Hex.pm release. - [mix mailglass.reconcile](Mix.Tasks.Mailglass.Reconcile.md): Manually trigger the same reconciliation sweep that `Mailglass.Webhook.Reconciler` runs on its Oban cron schedule. - [mix mailglass.webhooks.prune](Mix.Tasks.Mailglass.Webhooks.Prune.md): Manually trigger the same retention sweep that `Mailglass.Webhook.Pruner` runs on its Oban cron schedule.