One row per (Message, recipient, provider) tuple. Mutable: projection
columns are updated by Mailglass.Outbound.Projector (Plan 06).
Field order per CONTEXT.md "Claude's Discretion": id → tenant_id → foreign keys → state → metadata/flags → timestamps.
@primary_key is UUIDv7 via the Mailglass.Schema macro.
Atom Sets
:stream—:transactional | :operational | :bulk(D-10):last_event_type— full Anymail event taxonomy + mailglass internal:dispatched/:suppressed(D-14 project-level)
Projection columns (D-13)
dispatched_at, delivered_at, bounced_at, complained_at,
suppressed_at, terminal, last_event_type, last_event_at are the
only Elixir-modifiable facts. Mailglass.Outbound.Projector (Plan 06)
owns writes to these columns; metadata is a free-form jsonb bag for
adopter-supplied non-PII extras.
Optimistic locking (D-18)
:lock_version defaults to 1. Consumers chain
Ecto.Changeset.optimistic_lock(:lock_version) onto the changeset when
updating — concurrent dispatch attempts raise Ecto.StaleEntryError on
the loser.
Summary
Functions
Closed event-type atom set. Tested against api_stability.md (Phase 6 check).
Closed stream atom set.
Builds a changeset for a new %Delivery{} from an attr map.
Types
@type t() :: %Mailglass.Outbound.Delivery{ __meta__: term(), bounced_at: DateTime.t() | nil, complained_at: DateTime.t() | nil, delivered_at: DateTime.t() | nil, dispatched_at: DateTime.t() | nil, id: Ecto.UUID.t() | nil, idempotency_key: String.t() | nil, inserted_at: DateTime.t() | nil, last_error: map() | nil, last_event_at: DateTime.t() | nil, last_event_type: atom() | nil, lock_version: integer() | nil, mailable: String.t() | nil, metadata: map(), provider: String.t() | nil, provider_message_id: String.t() | nil, recipient: String.t() | nil, recipient_domain: String.t() | nil, status: :queued | :sent | :dispatched | :failed | :suppressed | nil, stream: :transactional | :operational | :bulk | nil, suppressed_at: DateTime.t() | nil, tenant_id: String.t() | nil, terminal: boolean() | nil, updated_at: DateTime.t() | nil }
Functions
@spec __event_types__() :: [atom()]
Closed event-type atom set. Tested against api_stability.md (Phase 6 check).
@spec __streams__() :: [atom()]
Closed stream atom set.
@spec changeset(map()) :: Ecto.Changeset.t()
Builds a changeset for a new %Delivery{} from an attr map.
Auto-populates :recipient_domain from :recipient (denormalization
per D-13) — a cheap cast-time computation that saves a SPLIT_PART()
at query time for rate-limit and analytics reads.
@spec changeset(t(), map()) :: Ecto.Changeset.t()