Adapter bridging to any Swoosh.Adapter.
Adopters configure their Swoosh adapter once and mailglass wraps it —
they keep existing Postmark/SendGrid/Mailgun/SES/Resend/SMTP config.
mailglass adds error normalization into %Mailglass.SendError{}. The
authoritative dispatch span belongs to the outbound facade's call_adapter/2,
so a provider call emits one span rather than a nested duplicate.
Pure: no DB, no PubSub, no Process.put. Caller's process owns the
HTTP request via Swoosh's :api_client (adopter-supplied, typically
Finch).
Configuration
config :mailglass,
adapter: {Mailglass.Adapters.Swoosh,
swoosh_adapter: {Swoosh.Adapters.Postmark,
api_key: System.fetch_env!("POSTMARK_API_KEY")}}The :swoosh_adapter opt carries either a module (for Swoosh adapters
with no config) or a {module, opts} tuple.
Error mapping (v0.1)
| Swoosh shape | Mapped SendError :type | Context fields |
|---|---|---|
{:api_error, 429, _} or 500..599 | :adapter_failure / transient | provider_status, reason_class, provider_module |
{:api_error, 400..499, _} | :adapter_failure / permanent | provider_status, reason_class, provider_module |
| Known transport/timeouts | :adapter_failure / transient | reason_class: :transport, provider_module |
| Unknown or malformed outcomes | :adapter_failure / permanent | reason_class: :unknown, provider_module |
PII policy: Provider response bodies and reason text never enter error
context, exception messages, JSON, or persisted delivery errors. The 8 forbidden keys
(:to, :from, :body, :html_body, :subject, :headers, :recipient, :email)
NEVER appear in error context. NoPiiInTelemetryMeta
enforces.
What this module does NOT do
- Does not call
Swoosh.Mailer.deliver/1— forbidden in library code. CallsSwoosh.Adapter.deliver/2(the behaviour callback) directly. - Is not a GenServer — pure function, stateless.
- Does not touch
mailglass_events,mailglass_deliveries, orPhoenix.PubSub. Side-effect-free by design.