In-memory, time-advanceable test adapter (TRANS-02, D-01..D-03).
The merge-blocking release gate (D-13). Every PR runs the full
pipeline against this adapter. Mirrors Swoosh.Adapters.Sandbox:
ownership-by-pid, $callers inheritance, allow/2 for
cross-process delegation (LiveView, Playwright, Oban worker), shared
mode for global tests.
Stored record shape
%{
message: %Mailglass.Message{},
delivery_id: Ecto.UUID.t(),
provider_message_id: String.t(),
recorded_at: DateTime.t()
}Records %Mailglass.Message{} (NOT raw %Swoosh.Email{}) so
assert_mail_sent(mailable: UserMailer) can recover the originating
Mailable. Tenant stamped from the message at record time.
provider_message_id lets trigger_event/3 look up the Delivery row
by id and simulate a Phase-4 webhook event via the REAL
Events.append_multi/3 + Projector.update_projections/2 write path
(D-03). This keeps the Fake in sync with the production write path.
Public API
deliveries/0,1— list recorded deliveries (optionally filtered)last_delivery/0,1— most recent (by insertion order)clear/0,1— wipe current owner's bucket (:allwipes every bucket)trigger_event/3— simulate a webhook-shaped eventadvance_time/1— delegates toMailglass.Clock.Frozen.advance/1- Ownership:
checkout/0,checkin/0,allow/2,set_shared/1
Async: true safety
Ownership keys every ETS bucket by owner pid; each test is its own
owner (via Mailglass.MailerCase setup, Plan 06). Cross-process
deliveries (LiveView, Task.Supervisor, Oban worker) resolve via
$callers or explicit allow/2.
Summary
Functions
Advances the process-local frozen clock. Delegates to Mailglass.Clock.Frozen.advance/1.
Clears recorded deliveries.
Returns all recorded deliveries for the current owner (or a specified owner).
Returns the most recent delivery for the current owner, or nil.
Simulates a webhook-shaped event for a previously-delivered message (D-03).
Functions
@spec advance_time(integer()) :: DateTime.t()
Advances the process-local frozen clock. Delegates to Mailglass.Clock.Frozen.advance/1.
@spec clear(keyword() | :all) :: :ok
Clears recorded deliveries.
clear()— clears the current owner's bucket.clear([owner: pid])— clears the specified owner's bucket.clear(:all)— clears every owner's bucket (flushes the entire ETS table).
Returns all recorded deliveries for the current owner (or a specified owner).
Options
:owner— pid; defaults toself():tenant— filter byrecord.message.tenant_id:mailable— filter byrecord.message.mailable:recipient— filter by any address inrecord.message.swoosh_email.to
Returns the most recent delivery for the current owner, or nil.
@spec trigger_event(String.t(), atom(), keyword()) :: {:ok, Mailglass.Events.Event.t()} | {:error, term()}
Simulates a webhook-shaped event for a previously-delivered message (D-03).
Looks up the %Delivery{} row by provider_message_id, builds an
%Events.Event{}, and runs it through
Events.append_multi/3 + Projector.update_projections/2 inside
Repo.transact/1. This is the SAME write path Phase 4 webhook ingest
uses — the Fake proves the production write path.
After the transaction commits, broadcasts via
Projector.broadcast_delivery_updated/3 (D-04).
Opts
:occurred_at— DateTime; defaults toMailglass.Clock.utc_now():reject_reason— atom from the reject_reason closed set:metadata— map stored inEvent.metadata(Phase 4:raw_payloadmoved tomailglass_webhook_events; see D-15)
Returns
{:ok, %Events.Event{}}on success{:error, :not_found}ifprovider_message_idhas no matching Delivery{:error, term()}for other failures