Oban worker that delivers a transactional email asynchronously.
Flow
Accrue.Mailer.Default.deliver/2enqueues a job with string-keyed%{"type" => "...", "assigns" => %{...}}args (Oban-safe scalars only).perform/1rehydrates the assigns (locale/timezone/customer hydration viaenrich/2), resolves the template module (honoring:email_overridesrung 2 MFA and rung 3 atom), builds a%Swoosh.Email{}, and delivers viaAccrue.Mailer.Swoosh.
Queue
Host applications MUST configure an Oban queue named :accrue_mailers.
Recommended concurrency: 20.
Pitfall 7 defense
unique: [period: 60, fields: [:args, :worker]] prevents double-dispatch
when both a Billing action AND a webhook reducer try to enqueue the same
email within 60s. DO NOT TOUCH this option — it's the only guard against
the action+webhook duplication pitfall.
Summary
Functions
Enriches raw Oban-arg assigns with locale, timezone, and (optionally)
the hydrated Accrue.Billing.Customer struct (D6-03 precedence ladder).
Resolves the template module for an email type. Honors :email_overrides
(Pay-style ladder D-23)
Public accessor for the default template module for a given email
type. Used by mix accrue.mail.preview (D6-08) and by tests. Honors
the full 13-type catalogue plus the :payment_succeeded legacy alias.
Functions
Enriches raw Oban-arg assigns with locale, timezone, and (optionally)
the hydrated Accrue.Billing.Customer struct (D6-03 precedence ladder).
Precedence for locale:
assigns[:locale]/assigns["locale"]customer.preferred_locale(hydrated viaassigns[:customer_id])Accrue.Config.default_locale/0- Hardcoded
"en"fallback
Same ladder for timezone (swap preferred_timezone +
Accrue.Config.default_timezone/0 + "Etc/UTC").
Unknown locales/zones emit [:accrue, :email, :locale_fallback] /
[:accrue, :email, :timezone_fallback] telemetry with
%{requested: value} metadata (no PII) and fall back to "en" /
"Etc/UTC". enrich/2 NEVER raises — pitfall 5 defense.
Resolves the template module for an email type. Honors :email_overrides
(Pay-style ladder D-23):
- Rung 2 (MFA):
{Mod, :fun, args}callsMod.fun(type, *args)at runtime, letting hosts pick a template dynamically based on request- time context. The type atom is prepended toargsas the first argument so MFA callbacks receive it. - Rung 3 (atom):
YourModulereplaces the default template module. - No override: falls through to
default_template/1.
Public accessor for the default template module for a given email
type. Used by mix accrue.mail.preview (D6-08) and by tests. Honors
the full 13-type catalogue plus the :payment_succeeded legacy alias.