AshDispatch.Workers.SendEmail (AshDispatch v0.5.0)
View SourceOban worker for sending emails asynchronously.
This worker:
- Fetches the DeliveryReceipt by ID
- Marks receipt as
:sending - Sends the email via configured email backend
- Marks receipt as
:sentor:failed
Usage
Jobs are enqueued automatically by AshDispatch.Transports.Email:
# Email transport enqueues job
Email.deliver(receipt, context, channel, event_config)
# Worker processes job asynchronously
%{
"receipt_id" => "...",
"recipient_email" => "user@example.com",
"subject" => "Order Created",
"from" => "orders@example.com",
"html_body" => "<h1>Order #1234</h1>",
"text_body" => "Order #1234 created"
}Idempotency
This worker is designed to be idempotent and handles duplicate jobs gracefully:
- Unique jobs: Only one job per
receipt_idcan be in available/scheduled/executing state at a time. This prevents duplicate jobs from "send now" while original is queued. - Terminal state check: If receipt is already in
:sent,:skipped, or:failed_permanentstate, the job completes successfully without retrying. - Race condition handling: If state transition fails due to concurrent processing, the job completes successfully (another job already handled it).
Retries
Oban handles retries automatically:
- Max 5 attempts (configurable)
- Exponential backoff (configurable)
- Failed jobs can be manually retried
Email Backend
Currently mocked. Consuming apps should configure their email backend:
# config/config.exs
config :ash_dispatch,
email_backend: MyApp.Emails.BackendThe backend should implement send_email/1:
defmodule MyApp.Emails.Backend do
def send_email(%{
to: to,
from: from,
subject: subject,
html_body: html,
text_body: text
}) do
# Send via Swoosh, Bamboo, etc.
{:ok, %{id: "provider_message_id"}}
end
end
Summary
Functions
Processes email sending job.