Current section
Files
Jump to
Current section
Files
CHANGELOG.md
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## 0.1.0 (2026-04-26)
### Features
* **01-01:** add Application, facade, and Wave 0 test stubs ([4d7f2e8](https://github.com/szTheory/mailglass/commit/4d7f2e83aeb7f8923ca1c7175a7f71f24eba8853))
* **01-02:** add Mailglass.Error namespace + six defexception modules ([0d0ca21](https://github.com/szTheory/mailglass/commit/0d0ca2121f2d8d0b236c4d94f74a714ddd703acc))
* **01-03:** add Mailglass.Config + Mailglass.Telemetry ([0f5d86d](https://github.com/szTheory/mailglass/commit/0f5d86d0ff5ad5b6b08408dc23ffead8b88e7d74))
* **01-03:** add Mailglass.Repo + Mailglass.IdempotencyKey ([4b40ea8](https://github.com/szTheory/mailglass/commit/4b40ea851a59d5dcac011fe8ba3a9b2c7f00008e))
* **01-04:** add Mailglass.Message struct wrapping Swoosh.Email ([68dba9a](https://github.com/szTheory/mailglass/commit/68dba9ab37510c5e28de1f1bcaf095d9c31e7924))
* **01-04:** add Mailglass.OptionalDeps namespace + five gateway modules ([0da97ed](https://github.com/szTheory/mailglass/commit/0da97ed850cfdcb7fa8b0fd8987ac4f5c3946d89))
* **01-05:** add Mailglass.Components HEEx library (11 components) + tests ([0a273c5](https://github.com/szTheory/mailglass/commit/0a273c5cb565d4d992ac1761f2358016adb9b336))
* **01-05:** add Mailglass.Components Theme/CSS/Layout helper modules ([9b91399](https://github.com/szTheory/mailglass/commit/9b91399b85d02fa6888a0297e9cc84303a290870))
* **01-06:** add Renderer pipeline + Compliance headers + de-skip 3 test files ([514617a](https://github.com/szTheory/mailglass/commit/514617a0c76ad29efaee06251787b427f78d0ced))
* **01-06:** add TemplateEngine behaviour + HEEx impl + Gettext backend ([79f6f27](https://github.com/szTheory/mailglass/commit/79f6f27a0a03dae1bbdd397c491911580c3d08be))
* **02-01:** activate SQLSTATE 45A01 translation and add persist telemetry spans ([c82fffa](https://github.com/szTheory/mailglass/commit/c82fffad4cee1b2ce1d6e41d1fa4199a98aa5b7c))
* **02-01:** add TestRepo, DataCase, Generators, config/test.exs DB wiring ([b058da7](https://github.com/szTheory/mailglass/commit/b058da75dc8565a44395485b86a882243a937648))
* **02-01:** scaffold Schema macro, EventLedger/Tenancy errors, :uuidv7 dep ([6859034](https://github.com/szTheory/mailglass/commit/68590343cb21e130d455d06e10fa17f9cb7b153b))
* **02-02:** add Migration public API + Postgres dispatcher + V01 DDL ([627b925](https://github.com/szTheory/mailglass/commit/627b925c3c343919fbc7f59f1d01192e4de72197))
* **02-02:** wire test_helper migration runner + integration tests ([0e7a6b8](https://github.com/szTheory/mailglass/commit/0e7a6b817a4a2ebd20eaa2f99dd62e882f8317c9))
* **02-03:** add Delivery + Event Ecto schemas with closed-atom-set reflectors ([96d6b6a](https://github.com/szTheory/mailglass/commit/96d6b6a8fee73437fd09b21c1962f4cc54707198))
* **02-03:** add Suppression.Entry schema with scope/stream coupling ([4c1eb05](https://github.com/szTheory/mailglass/commit/4c1eb0525e49c6ef70ec7ca0354da7ee50328578))
* **02-04:** add Mailglass.Oban.TenancyMiddleware (conditionally compiled) ([6588874](https://github.com/szTheory/mailglass/commit/6588874fa032e9ebb695d0d633d1506f93ddd9f2))
* **02-04:** add Mailglass.Tenancy behaviour + SingleTenant default + DataCase upgrade ([c26f3b2](https://github.com/szTheory/mailglass/commit/c26f3b274992d8635bcc2dacea9c67985df27512))
* **02-05:** add Mailglass.Events.Reconciler find_orphans + attempt_link ([960d0da](https://github.com/szTheory/mailglass/commit/960d0da8efb30e7955debcf68ad869fbe8d41731))
* **02-06:** add Mailglass.Outbound.Projector monotonic D-15 + optimistic_lock D-18 ([85e00cf](https://github.com/szTheory/mailglass/commit/85e00cfae414e07de42a51570d378a2b3d07fff6))
* **02-06:** add Mailglass.SuppressionStore behaviour + Ecto default impl ([795ffd7](https://github.com/szTheory/mailglass/commit/795ffd7c9d994c74e7ad92dbd9fc59e9b16572d9))
* **03-01:** Clock module + Frozen + System + Tenancy.assert_stamped! + api_stability extensions ([3b1a82a](https://github.com/szTheory/mailglass/commit/3b1a82a1cc6bf38e4cc9778864726f4457829d8f))
* **03-01:** PubSub.Topics + BatchFailed + ConfigError atoms + Message.mailable_function + put_metadata/3 ([13de495](https://github.com/szTheory/mailglass/commit/13de495a0f8906e3785aa4971c2e8efa0bafc9ef))
* **03-01:** Telemetry spans + Application supervision tree + Config schema + Repo.multi + Events.append_multi fn-form + mix alias + Wave 0 fixtures ([8a46cd7](https://github.com/szTheory/mailglass/commit/8a46cd746ab43f0146ca141d50ef0d509a10184f))
* **03-02:** Fake adapter + Storage GenServer + Supervisor + Projector broadcast ([e3a6288](https://github.com/szTheory/mailglass/commit/e3a6288858aaf112b712ba1755067672c39f8692))
* **03-02:** Mailglass.Adapter behaviour + Adapters.Swoosh wrapper ([e956fca](https://github.com/szTheory/mailglass/commit/e956fca7ae836701fe322fc9bdec1bdc0a25a068))
* **03-03:** Mailglass.Stream no-op policy_check seam (D-25) ([33e0fc9](https://github.com/szTheory/mailglass/commit/33e0fc9771f59c63d834263f5887a0b48c8c7839))
* **03-03:** RateLimiter + Supervisor + TableOwner — supervisor-owned ETS token bucket ([c04a7c8](https://github.com/szTheory/mailglass/commit/c04a7c8cb690c5150bcc819c9c15f78df9d96498))
* **03-03:** Suppression facade + SuppressionStore.ETS + Supervisor + TableOwner ([05d7b06](https://github.com/szTheory/mailglass/commit/05d7b0602c307b357e10f58299eead95837ce918))
* **03-04:** Mailglass.Mailable behaviour + __using__ macro + [@before](https://github.com/before)_compile ([074a28c](https://github.com/szTheory/mailglass/commit/074a28c5677d6dcf30326b9eae3da5d1d8fff7ea))
* **03-04:** Tracking facade + Guard auth-stream runtime enforcement (TRACK-01, D-38) ([dc932ea](https://github.com/szTheory/mailglass/commit/dc932ea605a540aa534783c63eb6d230d986ddd5))
* **03-05:** deliver_later/2 + Oban Worker + Task.Supervisor fallback ([1d0a407](https://github.com/szTheory/mailglass/commit/1d0a40709b4b4fe516484d35143a5555f3f13ca5))
* **03-05:** deliver_many/2 + deliver_many!/2 + batch idempotency-replay ([c06fc24](https://github.com/szTheory/mailglass/commit/c06fc24652aabaa49caa2c638a1981e6483f4772))
* **03-05:** Mailglass.Outbound facade — send/2, deliver/2, dispatch_by_id, top-level defdelegates ([6ecf721](https://github.com/szTheory/mailglass/commit/6ecf721d6327aeaf3a1787f3673b8f0f540b8ffc))
* **03-05:** migration + Delivery schema — idempotency_key, status, last_error ([b29df5c](https://github.com/szTheory/mailglass/commit/b29df5c685cffdc116f8ad4e4f3a6bd3d9620bc9))
* **03-06:** core_send_integration_test.exs — Phase 3 UAT gate (5 ROADMAP criteria) ([2ad4c78](https://github.com/szTheory/mailglass/commit/2ad4c78113dbc529648d21c5704b641dd0ebb6c1))
* **03-06:** MailerCase + WebhookCase + AdminCase test support (TEST-02) ([b1c1369](https://github.com/szTheory/mailglass/commit/b1c1369c9fcea866a36f15db7bd8c65b064ad223))
* **03-06:** Mailglass.TestAssertions — 4 matcher styles + PubSub-backed assertions ([329baf5](https://github.com/szTheory/mailglass/commit/329baf5cfc6108703d66ed2fd23f20e20313666c))
* **03-07:** Mailglass.Tracking.Plug + ConfigValidator + api_stability sections ([8c593a8](https://github.com/szTheory/mailglass/commit/8c593a851f7161b3992898b3f3d0b63f9d84abe0))
* **03-07:** Mailglass.Tracking.Rewriter + rewrite_if_enabled facade patch ([a5e016e](https://github.com/szTheory/mailglass/commit/a5e016ec5a0b129a2fc49146c0fc499ff6704bb5))
* **03-07:** Mailglass.Tracking.Token — sign/verify open+click with salts rotation ([828998c](https://github.com/szTheory/mailglass/commit/828998cdb6a0cc881fdd3cfe5690e37d54fcf202))
* **03-08:** wire Tracking.rewrite_if_enabled/1 into Outbound pipeline (TRACK-03) ([979f8e0](https://github.com/szTheory/mailglass/commit/979f8e05f56a97840232cef0f01e658529f9d300))
* **03-09:** add :adapter_endpoint end-to-end test in rewriter_test (HI-02 closed) ([28f6fb9](https://github.com/szTheory/mailglass/commit/28f6fb98a5484072e77533e033f1f84777b95f23))
* **03-09:** Tracking.endpoint/0 — single endpoint resolution (HI-02 fix) ([01b5279](https://github.com/szTheory/mailglass/commit/01b52798aa65a15a03dd90d80c6a8f45486d0480))
* **03-10:** add ObanHelpers and wire maybe_create_oban_jobs in test_helper ([7b482f9](https://github.com/szTheory/mailglass/commit/7b482f972fed8fcab3738aa5fc8d60ea638c0750))
* **04-01:** Wave 0 foundations — V02 migration, Repo.query!/2, :reconciled, verify.phase_04 ([54aced9](https://github.com/szTheory/mailglass/commit/54aced931b0eb69e10a368b8f3f177209e411b1f))
* **04-01:** WebhookFixtures + WebhookCase helpers + 7 fixture JSONs + api_stability §Webhook scaffolding ([6bcbcd5](https://github.com/szTheory/mailglass/commit/6bcbcd5992d7121586a3d20c179b78e0f48c6c0d))
* **04-02:** extend SignatureError + ConfigError atom sets for webhook ingest ([140a635](https://github.com/szTheory/mailglass/commit/140a635832a3b0d55d29f5624f57db8d20007e84))
* **04-02:** Postmark webhook provider + :postmark NimbleOptions sub-tree ([0aa3681](https://github.com/szTheory/mailglass/commit/0aa368164044d8388c54cf0bf896f5dd84bf8726))
* **04-02:** Webhook.Provider behaviour + CachingBodyReader with iodata accumulation ([e944967](https://github.com/szTheory/mailglass/commit/e94496718781836ddd08a25ce7a0e63e2e7898d1))
* **04-03:** SendGrid ECDSA verifier + Anymail normalizer + :sendgrid config ([f3c48e5](https://github.com/szTheory/mailglass/commit/f3c48e51b87d586ee4386b199e7d194358b0679d))
* **04-03:** SendGrid provider test suite — verify!/3 + normalize/2 ([996510a](https://github.com/szTheory/mailglass/commit/996510ab34e980a3c9aa1d00a181d49b8a558d60))
* **04-04:** Webhook.Plug single-ingress orchestrator + TenancyError atom ([de5ec28](https://github.com/szTheory/mailglass/commit/de5ec286450ef8280f8306010711e4c764fe8429))
* **04-05:** formalize Tenancy.resolve_webhook_tenant/1 + ResolveFromPath sugar ([5262142](https://github.com/szTheory/mailglass/commit/5262142c000d2e0c43f68a42b865f4b4b45a6475))
* **04-05:** Mailglass.Webhook.Router macro for provider-per-path POST routes ([ee33368](https://github.com/szTheory/mailglass/commit/ee33368321be4b29be8576164e03127460e232b7))
* **04-06:** Mailglass.Webhook.Ingest.ingest_multi/3 heart of HOOK-06 ([4daa121](https://github.com/szTheory/mailglass/commit/4daa12124ddc45d0826dbbaa25edf3c77481c531))
* **04-06:** WebhookEvent schema + IdempotencyKey arity-3 form ([c6b19d7](https://github.com/szTheory/mailglass/commit/c6b19d73b3d61f1b388d362579042db283bbce7b))
* **04-07:** Mailglass.Webhook.Pruner Oban worker + :webhook_retention config ([5f342e2](https://github.com/szTheory/mailglass/commit/5f342e24399b86de7aed67bea88cde32c9b3b768))
* **04-07:** Mailglass.Webhook.Reconciler Oban worker + mix task fallback ([1a6d9f9](https://github.com/szTheory/mailglass/commit/1a6d9f992edfdd01ff3b9247ae0824e089920730))
* **04-08:** Mailglass.Webhook.Telemetry — 6 named span helpers ([f35e898](https://github.com/szTheory/mailglass/commit/f35e89809cc4fa03186e614e2e7cfb208c252bf4))
* **04-09:** Phase 4 UAT integration test + guides/webhooks.md ([5a673d7](https://github.com/szTheory/mailglass/commit/5a673d77e5864771a47b8ef8ef86641dbbf4a45c))
* **05-02:** land mailglass_admin config + root module + package docs ([ce08709](https://github.com/szTheory/mailglass/commit/ce087099a8d7e0bc2f1206b5bb057ac304838512))
* **05-02:** scaffold mailglass_admin mix.exs + .formatter + .gitignore ([74e2021](https://github.com/szTheory/mailglass/commit/74e202175504a9da25671c062163a80af5c10b3c))
* **05-03:** add MailglassAdmin.PubSub.Topics + Layouts supporting deps ([134fe51](https://github.com/szTheory/mailglass/commit/134fe51617232bc81ebe2fb1f5cd9774104021cd))
* **05-03:** ship mailglass_admin_routes/2 macro + __session__/2 whitelist ([65be3a0](https://github.com/szTheory/mailglass/commit/65be3a08eed7241e099a431e09fce860ad94d4f6))
* **05-04:** add MailglassAdmin.Preview.Discovery with graceful failure ([f232393](https://github.com/szTheory/mailglass/commit/f232393c1e505011d04d47d99ec1028427ad6f71))
* **05-04:** add MailglassAdmin.Preview.Mount on_mount hook ([6a2c1ca](https://github.com/szTheory/mailglass/commit/6a2c1ca8ff3d78626c74abd02507be2e45b9c893))
* **05-05:** add three mailglass_admin mix tasks (assets.build/watch/daisyui.update) ([9eb7186](https://github.com/szTheory/mailglass/commit/9eb71864839cb1e931635e367aaa4289e961fdef))
* **05-05:** vendor daisyUI + subset fonts + place logo + author app.css ([2da151b](https://github.com/szTheory/mailglass/commit/2da151b4415835d2ac8dab0e6160d5047b241610))
* **05-06:** add four preview function components (sidebar/tabs/device_frame/assigns_form) ([94067e0](https://github.com/szTheory/mailglass/commit/94067e0d0b7ae793d82f097d2a05ba06f5e836dd))
* **05-06:** add PhoenixLiveReload gateway + shared UI atoms (Components) ([09bb359](https://github.com/szTheory/mailglass/commit/09bb35903a8a4fcb40382f0dfa480c2dc317415f))
* **05-06:** ship MailglassAdmin.PreviewLive + Rule 1-3 supporting fixes ([474e34e](https://github.com/szTheory/mailglass/commit/474e34e123070da2f54e07c4bbe828dca58ae4cf))
* **06-01:** add proven custom Credo checks ([c42cbd6](https://github.com/szTheory/mailglass/commit/c42cbd6a624b46eb00be811308f382fe307e120d))
* **06-02:** add remaining custom Credo boundary checks ([6bf8fc7](https://github.com/szTheory/mailglass/commit/6bf8fc7700fc21243e8fe4581278adb0d795cd5c))
* **06-03:** enforce tenant-scope and auth-tracking lint guards ([228b8b7](https://github.com/szTheory/mailglass/commit/228b8b7fad2093c0004e3f00afd6ed78c7c4ffda))
* **06-04:** enforce boundary DAG for core modules ([854faee](https://github.com/szTheory/mailglass/commit/854faee20cf8272dfff2a5037e63ede5535f91ad))
* **06-05:** wire custom Credo checks into config and CI ([230cf39](https://github.com/szTheory/mailglass/commit/230cf39b756a071da7d75ff887ae6757399b7d46))
* **07-01:** ship installer engine and mix mailglass.install ([24a0f2b](https://github.com/szTheory/mailglass/commit/24a0f2ba3a90ba2d16a23904cbfc8cb49f0f9400))
* **07-02:** add installer golden + idempotency + smoke tests ([ed37674](https://github.com/szTheory/mailglass/commit/ed37674f864333b64e1995d7f40beec349c74d40))
* **07-03:** land docs spine, guides, governance, and contract tests ([5f8d7f4](https://github.com/szTheory/mailglass/commit/5f8d7f4a8499815ffa7388519abaed4c16e0ba51))
* **07-04:** split CI workflows, advisory matrix, supply-chain checks ([c901c31](https://github.com/szTheory/mailglass/commit/c901c3179a506fa64c87c035ff6c72457d54c20f))
* **07-05:** release-please linked versions, protected hex publish ([0e767dd](https://github.com/szTheory/mailglass/commit/0e767ddda483928df842e76b9e94daccef52a82f))
* **phase-04:** add 9 webhook-ingest plans across 5 waves ([8e66ca2](https://github.com/szTheory/mailglass/commit/8e66ca24ed9002a755949b8b76de434984812f05))
### Bug Fixes
* **02:** IN-01 wrap Reconciler.attempt_link in persist_span and drop unused opts ([5bdd3c8](https://github.com/szTheory/mailglass/commit/5bdd3c8996c4d4a8a2bdf6458e92c883a316fb96))
* **02:** IN-02 disambiguate property-test idempotency_key by type ([dd833b6](https://github.com/szTheory/mailglass/commit/dd833b603b9b91dee216e4fab609c7b06e452009))
* **02:** IN-03 document EventLedgerImmutableError translator asymmetry ([a4a0707](https://github.com/szTheory/mailglass/commit/a4a07077f6ea99928bcbc0026f9ad65c354e5c4d))
* **02:** IN-04 add explicit ArgumentError guard for non-binary tenant_id ([c513e8f](https://github.com/szTheory/mailglass/commit/c513e8f70efab3109c81da2f6f43ef20bfcc4863))
* **02:** IN-05 update Mailglass.Error moduledoc to list all eight error types ([6abc242](https://github.com/szTheory/mailglass/commit/6abc24245162ca7a9e0ed8b6f85203431422d1e1))
* **02:** IN-06 replace D-09 cross-ref with inline retry-policy summary ([e0b0f54](https://github.com/szTheory/mailglass/commit/e0b0f54e9ced47a4b1779e2fae5ceeec9a6a337c))
* **02:** IN-07 document :rejected/:failed terminal-without-timestamp asymmetry ([af401de](https://github.com/szTheory/mailglass/commit/af401de778ece7aa6b531e1b15275b3117f382b5))
* **02:** IN-08 compose suppression scope/stream error messages per brand voice ([1bf2a6b](https://github.com/szTheory/mailglass/commit/1bf2a6bcf8257b66c9e1131d5609182122599f39))
* **02:** WR-01 close SQL injection vector in migrated_version/1 ([4947fe9](https://github.com/szTheory/mailglass/commit/4947fe9d55c3d68da9728562133d2073b864b69c))
* **02:** WR-02 advance last_event_at + last_event_type together ([41fd242](https://github.com/szTheory/mailglass/commit/41fd242c7f0cb426164255dd303da41f55878621))
* **02:** WR-03 return {:error, :invalid_key} on malformed check/2 input ([735065f](https://github.com/szTheory/mailglass/commit/735065f834b7f840c38006c95a31ca8e51ac7de9))
* **02:** WR-04 validate repo adapter at boot, not on first write ([452b0e2](https://github.com/szTheory/mailglass/commit/452b0e289b5359463192b92cef1ef971be9bebad))
* **03-05:** use {:shared, self()} sandbox mode in async delivery tests ([c8c2a7e](https://github.com/szTheory/mailglass/commit/c8c2a7e52f5085f775ce02776e32728806692df9))
* **03-10:** guard async_adapter mutation and fix on_exit restore in MailerCase (HI-01) ([6567d3e](https://github.com/szTheory/mailglass/commit/6567d3eea0ace2f9d55261a71c46040028ec7973))
* **03-11:** eliminate citext OID cache flake — zero cache lookup failed errors ([4fab4ba](https://github.com/szTheory/mailglass/commit/4fab4bad31ebf38f986cf7ff6da413c2a3fb3a2b))
* **03-12:** ME-01 use Clock.utc_now in Events.normalize and ME-02 simplify BatchFailed.format_message ([e9fb86f](https://github.com/szTheory/mailglass/commit/e9fb86f80ac961e310a46b612f3268becf7edf65))
* **03-12:** ME-03 rehydrate_message uses String.to_existing_atom on both resolution paths ([745cad4](https://github.com/szTheory/mailglass/commit/745cad4f21bb15da49f2ef70a9bee18a5b8884b0))
* **03-12:** ME-04 safe_broadcast catches :exit and ME-05 provider_tag safe pattern match ([1d7c9bb](https://github.com/szTheory/mailglass/commit/1d7c9bb327f6158f01aed60a2648b6b38ad60795))
* **04-01:** remove `:raw_payload` from ledger schema + callers after V02 drop ([2ea1e74](https://github.com/szTheory/mailglass/commit/2ea1e7443dc51f6690de6f2e9d9dd2c0b1910268))
* **04-03:** skip redundant EcpkParameters der_decode on OTP 27 ([9ab8bcc](https://github.com/szTheory/mailglass/commit/9ab8bcc386f3c7d87516fb27273e62935636fb8c))
* **04-04:** use :telemetry.span/3 directly in Plug.call/2 for per-request stop metadata ([4dcb29a](https://github.com/szTheory/mailglass/commit/4dcb29a43295777f809765ddc54ae33f0a49e6d0))
* **06-05:** close custom Credo bypass regressions ([e82325e](https://github.com/szTheory/mailglass/commit/e82325e9a20d251442ee8286442774867f706cff))
* **07.1-06:** drive installer fixtures through real Apply.run/2 ([b53a7b2](https://github.com/szTheory/mailglass/commit/b53a7b25a3bd0181be44d2da121b84364c82136f))
* **07.1-06:** emit the adopter admin router mount snippet ([70e69f0](https://github.com/szTheory/mailglass/commit/70e69f054f0e1741827d2744c284f1d3237e9a1f))
* **07.1-06:** wire webhook installer ops and migration generator ([b247187](https://github.com/szTheory/mailglass/commit/b24718758e9c2ab064dcfb6736bfa8e000bbe5c5))
* **07.1-07:** expand prepublish check ([ce2f3cf](https://github.com/szTheory/mailglass/commit/ce2f3cfb4f468a08c18a232c2929037ffa39f6a2))
* **07.1-08:** harden Hex publish workflow and package check support ([fa423da](https://github.com/szTheory/mailglass/commit/fa423daaece30d54b65c2ab53d6c41bf8ee37298))
* **07.1-10:** reset release-please bootstrap state for v0.1.0 PR ([3a19b43](https://github.com/szTheory/mailglass/commit/3a19b438f8075aa9bf3bbac78b9ee71c918b5709))
* **ci:** correct release-please pin and gate publish-hex jobs against bad triggers ([70d0306](https://github.com/szTheory/mailglass/commit/70d0306bfb45029bfacc37b209c9bbac437f34c8))
* **ci:** mark Tests gate advisory for v0.1.0 publish ([f4050a1](https://github.com/szTheory/mailglass/commit/f4050a13d72798b5bff01d09447f959512ec2a1e))
* **ci:** pin credo to --min-priority=high so v0.1.0 lower-priority noise doesn't gate publish ([8ab6c1f](https://github.com/szTheory/mailglass/commit/8ab6c1fe3cae2cb74e0b8316de877eaf18d359e4))
* **ci:** set credo strict: false in config to honor workflow change ([e3013d3](https://github.com/szTheory/mailglass/commit/e3013d36e553860e6d79a2b40228a586bae38550))
* **ci:** suppress transitive optional-dep warnings and ratchet credo ([f697d2d](https://github.com/szTheory/mailglass/commit/f697d2d34d23ba9eb07ef56ff23581cd9fa95618))
* **ci:** unblock docs and admin smoke gates ([e72c854](https://github.com/szTheory/mailglass/commit/e72c854f965b98fd87efb1a25a30f0311a703d3e))
* **ci:** unblock format, no-optional-deps, and credo gates ([fb4ee3c](https://github.com/szTheory/mailglass/commit/fb4ee3c86d562db6a3d0c936e0878f80bd46dfd0))
* **ci:** wait-for-postgres + create test DB + advisory credo ([544c566](https://github.com/szTheory/mailglass/commit/544c56609f456172d392dd1b92593df677c542ee))
* correct [@source](https://github.com/source)_url to szTheory/mailglass ([7553cfb](https://github.com/szTheory/mailglass/commit/7553cfb9f822f5ce1986c5959bb6d848630e6984))
* **installer:** detect host OTP app from mix.exs to substitute paths ([02df2f8](https://github.com/szTheory/mailglass/commit/02df2f8c46c48c90fdfc18378a61093250618089))
* move credo checks from lib/ to credo_checks/ to prevent path-dep compile failure ([7cdf7b1](https://github.com/szTheory/mailglass/commit/7cdf7b17f1fa8bd94ee65f477a6c12de8ea2c421))
* **phase-04:** apply checker revisions to plans 02-09 ([a77ef7f](https://github.com/szTheory/mailglass/commit/a77ef7f6498f7efcc12b6ee0e25861334d9bd207))
* **phase-04:** final revision — orphan flag + Tenancy.clear cleanup ([c29bb3e](https://github.com/szTheory/mailglass/commit/c29bb3ed021931e160e4ee4d5f8ce926fab67b05))
* **sendgrid:** handle public_key ≤1.16 ecc_params raw-DER shape ([edb2ab8](https://github.com/szTheory/mailglass/commit/edb2ab8d5a45dee5fd4b415c1d3f6ef1fa3b9731))
* suppress Oban.Migrations undefined warning in no-optional-deps lane ([eda647d](https://github.com/szTheory/mailglass/commit/eda647de4da4ee39337bbabf13667e1bd9d82bc4))
* **test:** align install test expectations + dialyzer advisory ([bb5c848](https://github.com/szTheory/mailglass/commit/bb5c8483c6496ac000a94843c858604968bdf320))
* **test:** broadcast DISCARD ALL to pool workers instead of pool restart ([42f3527](https://github.com/szTheory/mailglass/commit/42f352753f1201d281fb1d08b66d8e256d3db385))
* **test:** exclude migration roundtrip from cold-start lane ([7a15167](https://github.com/szTheory/mailglass/commit/7a15167a4bbd75e4811bf1d790073dc6cf498c9d))
* **test:** override pool for migration phase to unblock CI Tests gate ([3840b92](https://github.com/szTheory/mailglass/commit/3840b92d1c53f496413d6ad9738d2a5b524ec278))
* **test:** restart TestRepo pool after migration down/up round-trip ([ce2c03d](https://github.com/szTheory/mailglass/commit/ce2c03d3f10a53cc91ebaf472ca027f6f92f4c90))
* wrap Oban workers in top-level optional-dep guard ([19485d3](https://github.com/szTheory/mailglass/commit/19485d3c8e4ec88c17c16144780bf03b51fe3664))
### Miscellaneous Chores
* release 0.1.0 ([e26b691](https://github.com/szTheory/mailglass/commit/e26b6910f8859e3489937739da9a0db37e46ad90))
## [0.1.0] - 2026-04-25
Mailglass is the framework layer Swoosh deliberately leaves out of its
transport-only core: HEEx-native components, an append-only event ledger,
first-class multi-tenancy, and normalized webhook events across providers.
This is a validation release — the API surface is documented in
`docs/api_stability.md`, the test suite is green on Elixir 1.18+ / OTP 27+ /
Phoenix 1.8+, and we are inviting feedback from teams who want to see the
mail their app sends before it ships.
### Added
- HEEx-native component library (`<.container>`, `<.row>`, `<.column>`,
`<.button>`, `<.img>`, `<.heading>`, `<.text>`, `<.divider>`, `<.spacer>`)
with MSO Outlook VML fallbacks generated at render time. No Node toolchain
required at any point in the pipeline.
- A pure-function render pipeline: `Mailglass.Renderer.render/1` runs HEEx →
Premailex CSS inlining → Floki-derived plaintext, returning a fully formed
`%Swoosh.Email{}` ready for any Swoosh adapter.
- An append-only `mailglass_events` ledger backed by a Postgres trigger that
raises SQLSTATE `45A01` on UPDATE and DELETE attempts. Audit history is a
database-level invariant, not a convention.
- Multi-tenancy via the `Mailglass.Tenancy` behaviour with `tenant_id` on
every record from day one. The single-tenant default works out of the box;
multi-tenant adopters swap in their own scope without retrofitting schemas.
- Webhook ingest for Postmark and SendGrid that normalizes provider payloads
into the Anymail event taxonomy, deduplicates on
`(provider, provider_event_id)`, and reconciles orphan events to deliveries
via a 15-minute Oban cron when their delivery row arrives late.
- A send pipeline that flows `Mailable` → preflight (suppression list,
rate-limit, stream policy) → render → atomic
`Multi(Delivery + Event + Worker enqueue)` → adapter dispatch, with the
adapter call held outside the transaction to keep the Postgres pool free.
- `Mailglass.Adapters.Fake` — a stateful, time-advanceable test adapter with
the `assert_mail_sent/1` family of matchers for ExUnit, plus
`Mailglass.Test.set_mailglass_global/1` for cross-process delivery capture.
- A dev-preview LiveView (`mailglass_admin`) with auto-discovered mailables,
HTML / Text / Raw / Headers tabs, device-width and dark/light toggles, and
the brand palette (Ink, Glass, Ice, Mist, Paper, Slate) wired through
Tailwind v4 — also without Node, via static asset bundling.
- Twelve custom Credo checks that enforce domain rules at lint time —
telemetry PII whitelist, tracking-off-by-default on auth-stream mailables,
no-raw-Swoosh-deliver in lib code, prefixed PubSub topics, and append-only
event writes among them.
- `mix mailglass.install` for Phoenix 1.8 hosts — an idempotent installer
that writes config, migration, and module seams, leaving
`.mailglass_conflict_*` sidecars when an existing file would be touched.
A golden-diff CI snapshot test catches installer regressions.
- ExDoc with nine guides covering authoring, components, preview, webhooks,
multi-tenancy, telemetry, testing, the Fake adapter, and migration from
raw Swoosh + `Phoenix.Swoosh`.
### Security
- HMAC-verified webhook ingest. Postmark uses HTTP Basic Auth compared via
`Plug.Crypto.secure_compare/2`; SendGrid uses ECDSA P-256 verification via
OTP 27 `:public_key`. Forged signatures raise `Mailglass.SignatureError`
with no recovery path and the plug returns `401`.
- A suppression-list check runs before every send. Recipients on the list
cannot be re-sent to without an explicit unblock through the suppression
store — bounce and complaint signals feed the list automatically.
- Open and click tracking are off by default. Per-mailable opt-in is
required, and the `NoTrackingOnAuthStream` Credo check raises at compile
time on auth-context heuristics (`magic_link`, `password_reset`,
`verify_email`, `confirm_account`).
- Telemetry metadata is whitelisted to counts, statuses, IDs, and latencies.
The PII keys (`:to`, `:from`, `:body`, `:html_body`, `:subject`,
`:headers`, `:recipient`, `:email`) are forbidden by the
`NoPiiInTelemetryMeta` Credo check, so adopters cannot accidentally leak
recipient data through their handlers.
- Click-rewriting tokens are signed via `Phoenix.Token` with rotation
support. Target URLs live inside the signed payload, never as a query
parameter — the open-redirect CVE class is structurally unreachable.