Mailglass

Mail you can see through.

CIHex.pmHexDocsLicense

Mailglass is a batteries-included transactional email framework for Phoenix. It composes on top of Swoosh and ships the framework layer Swoosh deliberately leaves out: HEEx-native components with Outlook MSO/VML fallbacks, a LiveView preview/admin dashboard, normalized webhook events, an append-only event ledger with Postgres trigger immutability, multi-tenant routing, message streams, RFC 8058 List-Unsubscribe with signed tokens, suppression lists, and webhook-driven auto-suppression.

It is shipped as three sibling packages: mailglass (core), mailglass_admin (mountable LiveView dashboard), and mailglass_inbound (inbound routing; v0.5+). It is for senior Phoenix teams building production transactional email — welcome flows, password resets, magic links, receipts, notifications — who today rebuild the same 40% of framework plumbing on every project.

Requirements

Installation

Add mailglass to your dependencies:

# mix.exs
def deps do
  [
    {:mailglass, "~> 0.3"},
    {:mailglass_admin, "~> 0.3", only: [:dev]}
  ]
end

Fetch deps, run the installer, and migrate:

mix deps.get
mix mailglass.install
mix ecto.migrate

The installer generates: a MyApp.Mailing context, the three-table migration (mailglass_deliveries, mailglass_events, mailglass_suppressions plus the immutability trigger), router mounts for the dev preview and webhook plug, a default mailable and layout, an Oban worker stub (when Oban is installed), and a config/runtime.exs configuration block.

Quickstart

Run the full onboarding path first:

mix deps.get
mix mailglass.install
mix ecto.migrate
mix compile

Define a mailable:

defmodule MyApp.UserMailer do
  use Mailglass.Mailable, stream: :transactional

  def welcome(user) do
    new()
    |> to(user.email)
    |> from({"MyApp", "support@example.com"})
    |> subject("Welcome to MyApp")
    |> html_body("<h1>Welcome to MyApp</h1>")
    |> text_body("Welcome to MyApp")
    |> Mailglass.Message.put_function(:welcome)
  end
end

Send it — synchronously, asynchronously (via Oban when available), or in a batch:

MyApp.UserMailer.welcome(user) |> Mailglass.deliver()
MyApp.UserMailer.welcome(user) |> Mailglass.deliver_later()
Mailglass.deliver_many(Enum.map(users, &MyApp.UserMailer.welcome/1))

Preview mailables in dev at http://localhost:4000/dev/mail — sidebar of discovered mailables, device width and dark-mode toggles, HTML/Text/Raw/Headers tabs, live-editable assigns.

Deliverability Doctor

Run the DNS-only doctor against one explicit domain at a time:

mix mail.doctor --domain example.com
mix mail.doctor --domain example.com --dkim-selector default --dkim-selector selector2
mix mail.doctor --domain example.com --verbose
mix mail.doctor --domain example.com --format json

mix mail.doctor reports DNS truth and remediation guidance for SPF, DKIM, DMARC, MX, and BIMI. It can return honest cannot_verify outcomes when DNS alone is insufficient, and it does not promise inbox placement certainty or a deliverability grade.

API Stability

The canonical v1.x contract inventory for the core package lives in docs/api_stability.md.

The canonical 1.x compatibility, deprecation, and support-matrix policy lives in guides/compatibility-and-deprecations.md.

Use that document, not root-module reachability, as the source of truth for:

mailglass_admin has its own narrow contract inventory, and mailglass_inbound is outside the v1.x stability promise for this milestone.

For release posture, support floors, retained legacy bridges, and upgrade expectations, use the compatibility guide rather than inferring policy from the stability inventory alone.

Feature highlights

Packages

Package Status What it is
mailglassv1.x contract inventory documented in docs/api_stability.md Core library: mailables, rendering, delivery pipeline, event ledger, webhook ingest, streams, unsubscribe, suppressions, tenancy.
mailglass_admin Narrow v1.x admin contract documented separately Mountable LiveView dashboard with stable router/auth/operator seams and internal UI implementation details.
mailglass_inbound v0.5+ Inbound routing (Action Mailbox equivalent): recipient/subject/header matchers, ingress plugs per provider, storage adapters, Oban routing.

Roadmap

Full trajectory in .planning/ROADMAP.md and .planning/PROJECT.md.

Documentation

Contributing

Mailglass is developed in public. Contributor conventions, decision log, and phase-by-phase roadmap live in CLAUDE.md and .planning/PROJECT.md; a dedicated CONTRIBUTING.md lands in Phase 7.

Reproduce the default CI gate locally:

mix verify.foundation
mix verify.cold_start
mix compile --no-optional-deps --warnings-as-errors

License

MIT. The license is declared in mix.exs and applies across all sibling packages.