AshDispatch.Event.RecipientExtractor (AshDispatch v0.5.1)
View SourceExtracts recipient identifiers and names from recipient structs using cascading configuration.
For usage examples and complete guide, see the Recipient Field Extraction topic guide.
Configuration Resolution Order
The extractor uses a cascading resolution strategy (most specific to least specific):
- Event DSL override - Configured directly in the event definition
- Audience + Transport config - Audience-specific transport configuration
- Transport config - Transport-specific configuration
- Generic default - Single default for all transports
- Error - No configuration found
Configuration Structure
# config/config.exs
config :ash_dispatch,
recipient_fields: [
# Per-transport defaults (transport-first structure)
email: [
identifier: :email,
name: [:display_name, :name, :contact_person, :full_name] # fallback chain
],
discord: [
identifier: :discord_id,
name: [:app_username, :display_name, :name]
],
in_app: [
identifier: :id,
name: [:display_name, :name]
],
sms: [
identifier: :mobile_phone,
name: [:first_name, :name]
],
# Per-audience overrides (optional)
audiences: [
admin: [
email: [name: :full_name] # Admins show full name in emails
],
customer: [
email: [
identifier: :contact_email,
name: [:company_name, :contact_person]
]
]
]
]Field Extraction Formats
The extractor supports multiple field specification formats:
:field_name- Direct atom field access{:field, :field_name}- Explicit field tuple{:field, [:nested, :path]}- Nested field access viaget_in/2{:string_field, "key"}- String key access for JSON data&Module.function/1- Custom extraction functionnil- No field (e.g., webhooks don't need names)
Examples
# Extract with generic defaults
RecipientExtractor.extract_identifier(user, :email, :user)
# → Uses config[:recipient_fields][:identifier] → :email
# Extract with transport override
RecipientExtractor.extract_identifier(user, :sms, :user)
# → Uses config[:recipient_fields][:sms][:identifier] → :mobile_phone
# Extract with audience override
RecipientExtractor.extract_name(admin, :email, :admin)
# → Uses config[:recipient_fields][:audiences][:admin][:name] → :full_name
# Extract with nested field
RecipientExtractor.extract_identifier(%{contact: %{email: "..."}}, :email, :user)
# With config: identifier: {:field, [:contact, :email]}
# → "..."
# Extract with custom function
RecipientExtractor.extract_identifier(lead, :email, :lead)
# With config: identifier: &MyApp.extract_lead_email/1
# → Calls MyApp.extract_lead_email(lead)
Summary
Functions
Extracts the recipient identifier (email, phone, webhook URL, etc.) based on transport and audience.
Extracts the recipient display name based on transport and audience.
Functions
Extracts the recipient identifier (email, phone, webhook URL, etc.) based on transport and audience.
Parameters
recipient- The recipient struct/map to extract fromtransport- The transport type (:email,:sms,:in_app, etc.)audience- The audience type (:user,:admin,:lead, etc.)event_config- Optional event-specific configuration (from DSL)
Returns
The extracted identifier string, or raises an error if extraction fails.
Examples
iex> user = %User{email: "user@example.com", phone: "555-1234"}
iex> RecipientExtractor.extract_identifier(user, :email, :user)
"user@example.com"
iex> RecipientExtractor.extract_identifier(user, :sms, :user)
"555-1234"
Extracts the recipient display name based on transport and audience.
Parameters
recipient- The recipient struct/map to extract fromtransport- The transport type (:email,:sms,:in_app, etc.)audience- The audience type (:user,:admin,:lead, etc.)event_config- Optional event-specific configuration (from DSL)
Returns
The extracted name string, or nil if no name is configured/available.
Examples
iex> user = %User{email: "user@example.com", contact_person: "John Doe"}
iex> RecipientExtractor.extract_name(user, :email, :user)
"John Doe"