AshDispatch.Workers.SendEmail (AshDispatch v0.5.0)

View Source

Oban worker for sending emails asynchronously.

This worker:

  1. Fetches the DeliveryReceipt by ID
  2. Marks receipt as :sending
  3. Sends the email via configured email backend
  4. Marks receipt as :sent or :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_id can 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_permanent state, 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.Backend

The 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.

Functions

perform(job)

Processes email sending job.

Job Args

  • receipt_id - DeliveryReceipt UUID
  • recipient_email - Email address to send to
  • subject - Email subject
  • from - Sender email address
  • html_body - HTML email body
  • text_body - Plain text email body

Returns

  • :ok on success
  • {:error, reason} on failure (Oban will retry)