Email system for PhoenixKit - main API module.
This module provides the primary interface for email functionality, including system configuration, log management, event management, and analytics.
Core Features
- Email Logging: Comprehensive logging of all outgoing emails
- Event Management: Manage delivery, bounce, complaint, open, and click events
- AWS SES Integration: Deep integration with AWS SES for event management
- Analytics: Detailed metrics and engagement analysis
- System Settings: Configurable options for system behavior
- Rate Limiting: Protection against abuse and spam
- Archival: Automatic cleanup and archival of old data
System Settings
All settings are stored in the PhoenixKit settings system with module "email_system":
email_enabled- Enable/disable the entire systememail_save_body- Save full email body (vs preview only)email_save_headers- Save email headers (vs empty map)email_ses_events- Manage AWS SES delivery eventsemail_retention_days- Days to keep emails (default: 90)aws_ses_configuration_set- AWS SES configuration set nameemail_compress_body- Compress body after N daysemail_archive_to_s3- Enable S3 archivalemail_sampling_rate- Percentage of emails to fully logemail_create_placeholder_logs- Create placeholder logs for orphaned events (default: false)
Core Functions
System Management
enabled?/0- Check if email system is enabledenable_system/0- Enable email systemdisable_system/0- Disable email systemget_config/0- Get current system configurationplaceholder_logs_enabled?/0- Check if placeholder log creation is enabledset_placeholder_logs/1- Enable/disable placeholder log creation
Email Log Management
list_logs/1- Get emails with filtersget_log!/1- Get email log by IDcreate_log/1- Create new email logupdate_log_status/2- Update log status
Event Management
create_event/1- Create system eventlist_events_for_log/1- Get events for specific logprocess_webhook_event/1- Process incoming webhook
Analytics & Metrics
get_system_stats/1- Overall system statisticsget_engagement_metrics/1- Open/click rate analysisget_campaign_stats/1- Campaign-specific metricsget_provider_performance/1- Provider comparison
Maintenance
cleanup_old_logs/1- Remove old logscompress_old_bodies/1- Compress storagearchive_to_s3/1- Archive to S3
Usage Examples
# Check if system is enabled
if PhoenixKit.Modules.Emails.enabled?() do
# System is active
end
# Get system statistics
stats = PhoenixKit.Modules.Emails.get_system_stats(:last_30_days)
# => %{total_sent: 5000, delivered: 4850, bounce_rate: 2.5, open_rate: 23.4}
# Get campaign performance
campaign_stats = PhoenixKit.Modules.Emails.get_campaign_stats("newsletter_2024")
# => %{total_sent: 1000, delivery_rate: 98.5, open_rate: 25.2, click_rate: 4.8}
# Process webhook from AWS SES
{:ok, event} = PhoenixKit.Modules.Emails.process_webhook_event(webhook_data)
# Clean up old data
{deleted_count, _} = PhoenixKit.Modules.Emails.cleanup_old_logs(90)Configuration Example
# In your application config
config :phoenix_kit,
email_enabled: true,
email_save_body: false,
email_retention_days: 90,
aws_ses_configuration_set: "my-app-system"
Summary
Functions
Archives old emais to S3 if archival is enabled.
Checks if AWS credentials are configured, from any of the sources
get_aws_access_key/0/get_aws_secret_key/0 read (highest priority
first): the selected aws_ses Integrations connection
(emails_aws_integration_uuid), then the legacy aws_access_key_id/
aws_secret_access_key Settings, then environment variables.
The decrypted credential map for ONE aws_ses Integrations connection,
memoized under {:credentials, uuid}.
Checks if Brevo event polling is enabled.
Removes emails older than the specified number of days.
Compresses body_full field for old emails to save storage.
Counts emails with optional filtering (without loading all records).
Creates an email system event.
Creates an email log if system is enabled.
Returns the email provider actually in effect, detected from the host
app's mailer configuration (see PhoenixKit.Modules.Emails.Utils.mailer_adapter_status/0).
Deletes one account's stored AWS tracking settings, if any.
Deletes one integration's stored Brevo watermark, if any. A no-op
(still {:ok, ...}-shaped via the underlying delete) if none exists.
Deletes an email log.
Disables the email system.
Whether an email log exists for message_id, matched against either the
internal message_id or the provider aws_message_id column.
PubSub topic on which email log status changes are broadcast.
Enables the email system.
Checks if the email system is enabled.
Fetch SES events from DLQ queue for specific message ID.
Fetch SES events from main SQS queue for specific message ID.
Gets AWS access key.
Gets the AWS region for SES and SQS services.
Gets AWS secret key.
The per-account SES/SQS tracking pipeline for one aws_ses integration —
the multi-account replacement for the single global aws_sqs_queue_url /
aws_ses_configuration_set / … settings, stored as one JSON setting per
account under the aws_tracking:<integration_uuid> key (the same
prefix-keyed shape get_brevo_watermark/1 uses for its cursor).
Gets the timestamp of the last completed Brevo polling cycle, if any.
Observability only — dedup/idempotency is enforced at the DB level by
Event's unique indexes, this is not used as a fetch cursor.
Integration uuids the operator has explicitly opted OUT of Brevo event
polling — an empty list (the default) means every active Brevo
integration gets polled. BrevoPollingJob reads this fresh every
cycle (no cache invalidation needed).
Gets the Brevo polling interval in milliseconds.
The stored Brevo poll watermark for one integration — how far
BrevoPollingJob has progressed through that integration's event
stream, as %{date: Date.t(), offset: non_neg_integer()}. nil if
this integration has never been polled under the watermark scheme yet
(cold start).
Gets statistics for a specific campaign.
Gets the current email system configuration.
Gets daily delivery trend data for chart visualization.
Gets engagement metrics with trend analysis.
Gets geographic distribution of engagement events.
Gets a single email log by ID. Returns nil if not found or system is disabled.
Gets a single email log by ID.
Gets an email log by message ID.
Gets provider-specific performance metrics.
Gets the configured retention period for emails in days.
Gets the sampling rate for email logging (percentage).
Gets the AWS SES configuration set name.
Gets the AWS SNS Topic ARN for email events.
Gets comprehensive SQS configuration.
Gets the AWS SQS Dead Letter Queue URL.
Gets the maximum number of SQS messages to receive per polling cycle.
Integration uuids the operator has explicitly opted OUT of SQS event
polling — an empty list (the default) means every active aws_ses
integration gets polled. SQSPollingJob reads this fresh every cycle (no
cache invalidation needed). Same comma-separated storage format as
get_brevo_polling_excluded_integrations/0.
Gets the SQS polling interval in milliseconds.
Gets the AWS SQS Queue ARN for email events.
Gets the AWS SQS Queue URL for email events.
Gets the SQS message visibility timeout in seconds.
Gets overall system statistics for a time period.
Gets template-specific performance metrics.
Gets the most clicked links for a time period.
Invalidates the cached AWS SES credential resolution (aws_ses_credentials/0).
Every integration uuid that currently has stored AWS tracking settings —
used by SQSPollingJob to prune settings for integrations that no longer
exist, so those rows don't accumulate forever.
Every integration uuid that currently has a stored Brevo watermark —
used by BrevoPollingJob to prune watermarks for integrations that
are no longer active (deleted, or opted out of polling), so those
settings rows don't accumulate forever.
Lists events for a specific email log.
Lists emails with optional filters.
Checks if placeholder log creation is enabled.
Processes an incoming webhook event (typically from AWS SES).
Checks if full email body saving is enabled.
Checks if email headers saving is enabled.
The single aws_ses Integrations connection selected via the
emails_aws_integration_uuid setting, or nil.
Checks if AWS SES event management is enabled.
Sets the AWS region for SES and SQS services.
Persists one account's SES/SQS tracking pipeline. Accepts string- or
atom-keyed attrs; unknown keys are dropped and blank values are stored as
nil, so the stored JSON is always exactly the
["queue_url", "dlq_url", "queue_arn", "sns_topic_arn", "configuration_set", "region"] shape get_aws_tracking/1 reads back.
Enables or disables Brevo event polling.
Records the timestamp of the last completed Brevo polling cycle.
Sets the list of Brevo integration uuids excluded from polling.
Sets the Brevo polling interval in milliseconds (minimum 30 000 — Brevo's rate limits are looser than SQS's long-poll cadence, so this floor is higher than SQS's 1 000ms).
Persists one integration's Brevo poll watermark.
Sets the number of days after which to compress email bodies.
Enables or disables placeholder log creation.
Sets the retention period for emails.
Enables or disables S3 archival for old email data.
Sets the sampling rate for email logging.
Enables or disables full email body saving.
Enables or disables email headers saving.
Sets the AWS SES configuration set name.
Enables or disables AWS SES event management.
Sets the AWS SNS Topic ARN for email events.
Sets the AWS SQS Dead Letter Queue URL.
Sets the maximum number of SQS messages to receive per polling cycle.
Enables or disables SQS polling.
Sets the list of aws_ses integration uuids excluded from SQS polling.
Sets the SQS polling interval in milliseconds.
Sets the AWS SQS Queue ARN for email events.
Sets the AWS SQS Queue URL for email events.
Sets the SQS message visibility timeout in seconds.
Checks if SQS polling is enabled.
Manually sync email status by fetching events from SQS queues.
Updates the status of an email log.
Functions
Archives old emais to S3 if archival is enabled.
Examples
iex> PhoenixKit.Modules.Emails.archive_to_s3()
{:ok, archived_count: 100, s3_key: "archives/2024/01/emails.json"}
Checks if AWS credentials are configured, from any of the sources
get_aws_access_key/0/get_aws_secret_key/0 read (highest priority
first): the selected aws_ses Integrations connection
(emails_aws_integration_uuid), then the legacy aws_access_key_id/
aws_secret_access_key Settings, then environment variables.
The decrypted credential map for ONE aws_ses Integrations connection,
memoized under {:credentials, uuid}.
Keyed by uuid rather than a single :credentials slot because the SQS
poller now walks several accounts per cycle: a single-slot cache handed
whichever account was resolved first to every subsequent lookup, which
with two accounts means polling one account's queue with the other's
keys. Cleared by invalidate_aws_credentials_cache/0, which every write
site that can change a resolution already calls.
Examples
iex> PhoenixKit.Modules.Emails.aws_ses_credentials("some-uuid")
%{"access_key" => "AKIA...", "secret_key" => "...", "aws_region" => "eu-north-1"}
Checks if Brevo event polling is enabled.
Unlike SQS (which separates "event tracking" from "polling mechanism" into two flags), Brevo has only the one mechanism — this single flag gates both.
Examples
iex> PhoenixKit.Modules.Emails.brevo_events_enabled?()
false
Removes emails older than the specified number of days.
Uses the system retention setting if no days specified.
Examples
iex> PhoenixKit.Modules.Emails.cleanup_old_logs()
{150, nil} # Deleted 150 records
iex> PhoenixKit.Modules.Emails.cleanup_old_logs(180)
{75, nil} # Deleted 75 records older than 180 days
Compresses body_full field for old emails to save storage.
Examples
iex> PhoenixKit.Modules.Emails.compress_old_bodies()
{25, nil} # Compressed 25 records
iex> PhoenixKit.Modules.Emails.compress_old_bodies(60)
{40, nil} # Compressed 40 records older than 60 days
Counts emails with optional filtering (without loading all records).
Parameters
filters- Map of filters to apply (optional)
Examples
iex> PhoenixKit.Modules.Emails.count_logs(%{status: "bounced"})
42
Creates an email system event.
Examples
iex> PhoenixKit.Modules.Emails.create_event(%{
email_log_uuid: log.uuid,
event_type: "open"
})
{:ok, %Event{}}
Creates an email log if system is enabled.
Examples
iex> PhoenixKit.Modules.Emails.create_log(%{
message_id: "abc123",
to: "user@example.com",
from: "app@example.com"
})
{:ok, %Log{}}
@spec current_provider() :: String.t()
Returns the email provider actually in effect, detected from the host
app's mailer configuration (see PhoenixKit.Modules.Emails.Utils.mailer_adapter_status/0).
Falls back to "aws_ses" when the adapter can't be statically detected
(e.g. a delegated mailer configured at runtime) but AWS credentials are
present — the same heuristic Interceptor.detect_provider/2 already uses
for delegation-mode hosts — otherwise "unknown".
Examples
iex> PhoenixKit.Modules.Emails.current_provider()
"aws_ses"
Deletes one account's stored AWS tracking settings, if any.
Examples
iex> PhoenixKit.Modules.Emails.delete_aws_tracking("some-uuid")
{:ok, %Setting{}}
Deletes one integration's stored Brevo watermark, if any. A no-op
(still {:ok, ...}-shaped via the underlying delete) if none exists.
Examples
iex> PhoenixKit.Modules.Emails.delete_brevo_watermark("some-uuid")
{:ok, %Setting{}}
Deletes an email log.
Examples
iex> log = PhoenixKit.Modules.Emails.get_log!(1)
iex> PhoenixKit.Modules.Emails.delete_log(log)
{:ok, %Log{}}
Disables the email system.
Sets the "email_enabled" setting to false.
Examples
iex> PhoenixKit.Modules.Emails.disable_system()
{:ok, %Setting{}}
Whether an email log exists for message_id, matched against either the
internal message_id or the provider aws_message_id column.
A cheap existence check (no struct load); false when the system is
disabled or the id is not a binary. Used by the Brevo poller to skip
events for mail this app never sent — the account may be shared with
other senders.
PubSub topic on which email log status changes are broadcast.
Subscribed to by admin LiveViews (e.g. the emails list) and broadcast from
PhoenixKit.Modules.Emails.Log.update_log/2 whenever a log's status changes.
Single source of truth for both the broadcaster and the subscribers.
Enables the email system.
Sets the "email_enabled" setting to true.
Examples
iex> PhoenixKit.Modules.Emails.enable_system()
{:ok, %Setting{}}
Checks if the email system is enabled.
Returns true if the "email_enabled" setting is true.
Examples
iex> PhoenixKit.Modules.Emails.enabled?()
true
Fetch SES events from DLQ queue for specific message ID.
Parameters
message_id- The AWS SES message ID to search for
Returns
List of SES events matching the message ID from DLQ.
Account-aware: see search_targets/1. A message whose log carries an
integration_uuid is looked for in THAT account's queue; otherwise every
configured account is searched.
Fetch SES events from main SQS queue for specific message ID.
Parameters
message_id- The AWS SES message ID to search for
Returns
List of SES events matching the message ID.
Account-aware: see search_targets/1. A message whose log carries an
integration_uuid is looked for in THAT account's queue; otherwise every
configured account is searched.
Gets AWS access key.
Priority: selected Integrations connection → Settings Database →
Environment Variables (see aws_ses_credentials/0).
Examples
iex> PhoenixKit.Modules.Emails.get_aws_access_key()
"AKIA..."
Gets the AWS region for SES and SQS services.
Priority: selected Integrations connection → Settings Database →
Environment Variables (see aws_ses_credentials/0).
Examples
iex> PhoenixKit.Modules.Emails.get_aws_region()
"eu-north-1"
Gets AWS secret key.
Priority: selected Integrations connection → Settings Database →
Environment Variables (see aws_ses_credentials/0).
Examples
iex> PhoenixKit.Modules.Emails.get_aws_secret_key()
"secret..."
The per-account SES/SQS tracking pipeline for one aws_ses integration —
the multi-account replacement for the single global aws_sqs_queue_url /
aws_ses_configuration_set / … settings, stored as one JSON setting per
account under the aws_tracking:<integration_uuid> key (the same
prefix-keyed shape get_brevo_watermark/1 uses for its cursor).
Returns a map with every key in ["queue_url", "dlq_url", "queue_arn", "sns_topic_arn", "configuration_set", "region"] (missing
or blank entries come back as nil), or nil when this account has no
tracking settings at all — which is what the legacy single-queue fallback
in SQSPollingJob keys off, so an existing env-configured deployment
keeps polling exactly as before.
Examples
iex> PhoenixKit.Modules.Emails.get_aws_tracking("some-uuid")
%{queue_url: "https://sqs.eu-north-1.amazonaws.com/1/q", region: "eu-north-1", ...}
Gets the timestamp of the last completed Brevo polling cycle, if any.
Observability only — dedup/idempotency is enforced at the DB level by
Event's unique indexes, this is not used as a fetch cursor.
Examples
iex> PhoenixKit.Modules.Emails.get_brevo_last_polled_at()
"2026-07-19T12:00:00Z"
Integration uuids the operator has explicitly opted OUT of Brevo event
polling — an empty list (the default) means every active Brevo
integration gets polled. BrevoPollingJob reads this fresh every
cycle (no cache invalidation needed).
Examples
iex> PhoenixKit.Modules.Emails.get_brevo_polling_excluded_integrations()
[]
Gets the Brevo polling interval in milliseconds.
Examples
iex> PhoenixKit.Modules.Emails.get_brevo_polling_interval()
120_000
The stored Brevo poll watermark for one integration — how far
BrevoPollingJob has progressed through that integration's event
stream, as %{date: Date.t(), offset: non_neg_integer()}. nil if
this integration has never been polled under the watermark scheme yet
(cold start).
Examples
iex> PhoenixKit.Modules.Emails.get_brevo_watermark("some-uuid")
%{date: ~D[2026-07-19], offset: 2500}
Gets statistics for a specific campaign.
Examples
iex> PhoenixKit.Modules.Emails.get_campaign_stats("newsletter_2024")
%{
total_sent: 1000,
delivery_rate: 98.5,
open_rate: 25.2,
click_rate: 4.8
}
Gets the current email system configuration.
Returns a map with all current settings.
Examples
iex> PhoenixKit.Modules.Emails.get_config()
%{
enabled: true,
save_body: false,
ses_events: true,
retention_days: 90,
sampling_rate: 100,
ses_configuration_set: "my-system",
sns_topic_arn: "arn:aws:sns:eu-north-1:123456789012:phoenixkit-email-events",
sqs_queue_url: "https://sqs.eu-north-1.amazonaws.com/123456789012/phoenixkit-email-queue",
sqs_polling_enabled: false,
aws_region: "eu-north-1"
}
Gets daily delivery trend data for chart visualization.
Examples
iex> PhoenixKit.Modules.Emails.get_daily_delivery_trends(:last_7_days)
%{
labels: ["2024-09-01", "2024-09-02", ...],
delivered: [120, 190, 300, ...],
bounced: [5, 10, 15, ...]
}
Gets engagement metrics with trend analysis.
Examples
iex> PhoenixKit.Modules.Emails.get_engagement_metrics(:last_7_days)
%{
avg_open_rate: 24.5,
avg_click_rate: 4.2,
bounce_rate: 2.8,
engagement_trend: :increasing
}
Gets geographic distribution of engagement events.
Examples
iex> PhoenixKit.Modules.Emails.get_geo_stats("open", :last_30_days)
%{"US" => 500, "CA" => 200, "UK" => 150}
Gets a single email log by ID. Returns nil if not found or system is disabled.
Examples
iex> PhoenixKit.Modules.Emails.get_log("018f1234-5678-7890-abcd-ef1234567890")
%Log{}
iex> PhoenixKit.Modules.Emails.get_log("nonexistent")
nil
Gets a single email log by ID.
Raises Ecto.NoResultsError if the log does not exist or system is disabled.
Examples
iex> PhoenixKit.Modules.Emails.get_log!("018f1234-5678-7890-abcd-ef1234567890")
%Log{}
Gets an email log by message ID.
Examples
iex> PhoenixKit.Modules.Emails.get_log_by_message_id("msg-abc123")
{:ok, %Log{}}
iex> PhoenixKit.Modules.Emails.get_log_by_message_id("nonexistent")
{:error, :not_found}
Gets provider-specific performance metrics.
Examples
iex> PhoenixKit.Modules.Emails.get_provider_performance(:last_7_days)
%{
"aws_ses" => %{delivery_rate: 98.5, bounce_rate: 1.5},
"smtp" => %{delivery_rate: 95.0, bounce_rate: 5.0}
}
Gets the configured retention period for emails in days.
Examples
iex> PhoenixKit.Modules.Emails.get_retention_days()
90
Gets the sampling rate for email logging (percentage).
Examples
iex> PhoenixKit.Modules.Emails.get_sampling_rate()
100 # Log 100% of emails
Gets the AWS SES configuration set name.
Examples
iex> PhoenixKit.Modules.Emails.get_ses_configuration_set()
"my-app-system"
Gets the AWS SNS Topic ARN for email events.
Examples
iex> PhoenixKit.Modules.Emails.get_sns_topic_arn()
"arn:aws:sns:eu-north-1:123456789012:phoenixkit-email-events"
Gets comprehensive SQS configuration.
Examples
iex> PhoenixKit.Modules.Emails.get_sqs_config()
%{
sns_topic_arn: "arn:aws:sns:...",
queue_url: "https://sqs.eu-north-1.amazonaws.com/...",
polling_enabled: true,
polling_interval_ms: 5000,
max_messages_per_poll: 10
}
Gets the AWS SQS Dead Letter Queue URL.
Examples
iex> PhoenixKit.Modules.Emails.get_sqs_dlq_url()
"https://sqs.eu-north-1.amazonaws.com/123456789012/phoenixkit-email-dlq"
Gets the maximum number of SQS messages to receive per polling cycle.
Examples
iex> PhoenixKit.Modules.Emails.get_sqs_max_messages()
10
@spec get_sqs_polling_excluded_integrations() :: [String.t()]
Integration uuids the operator has explicitly opted OUT of SQS event
polling — an empty list (the default) means every active aws_ses
integration gets polled. SQSPollingJob reads this fresh every cycle (no
cache invalidation needed). Same comma-separated storage format as
get_brevo_polling_excluded_integrations/0.
Examples
iex> PhoenixKit.Modules.Emails.get_sqs_polling_excluded_integrations()
[]
Gets the SQS polling interval in milliseconds.
Examples
iex> PhoenixKit.Modules.Emails.get_sqs_polling_interval()
5000 # 5 seconds
Gets the AWS SQS Queue ARN for email events.
Examples
iex> PhoenixKit.Modules.Emails.get_sqs_queue_arn()
"arn:aws:sqs:eu-north-1:123456789012:phoenixkit-email-queue"
Gets the AWS SQS Queue URL for email events.
Examples
iex> PhoenixKit.Modules.Emails.get_sqs_queue_url()
"https://sqs.eu-north-1.amazonaws.com/123456789012/phoenixkit-email-queue"
Gets the SQS message visibility timeout in seconds.
Examples
iex> PhoenixKit.Modules.Emails.get_sqs_visibility_timeout()
300 # 5 minutes
Gets overall system statistics for a time period.
Examples
iex> PhoenixKit.Modules.Emails.get_system_stats(:last_30_days)
%{
total_sent: 5000,
delivered: 4850,
bounced: 150,
opened: 1200,
clicked: 240,
delivery_rate: 97.0,
bounce_rate: 3.0,
open_rate: 24.7,
click_rate: 20.0
}
Gets template-specific performance metrics.
Examples
iex> PhoenixKit.Modules.Emails.get_template_stats(:last_30_days)
%{
"welcome_email" => %{sent: 100, delivered: 95, opened: 45, clicked: 12},
"password_reset" => %{sent: 50, delivered: 48, opened: 30, clicked: 8}
}
Gets the most clicked links for a time period.
Examples
iex> PhoenixKit.Modules.Emails.get_top_links(:last_30_days, 10)
[%{url: "https://example.com/product", clicks: 150}, ...]
@spec invalidate_aws_credentials_cache() :: :ok
Invalidates the cached AWS SES credential resolution (aws_ses_credentials/0).
Call after anything that changes which credentials get_aws_access_key/0,
get_aws_secret_key/0, or get_aws_region/0 should resolve to — selecting
a different aws_ses Integrations connection, clearing the selection back
to legacy Settings, or updating the selected connection's own credentials.
Without this, a switch would still take effect, just not sooner than the
cache's 60000ms TTL.
@spec list_aws_tracking_integration_uuids() :: [String.t()]
Every integration uuid that currently has stored AWS tracking settings —
used by SQSPollingJob to prune settings for integrations that no longer
exist, so those rows don't accumulate forever.
Examples
iex> PhoenixKit.Modules.Emails.list_aws_tracking_integration_uuids()
["some-uuid"]
Every integration uuid that currently has a stored Brevo watermark —
used by BrevoPollingJob to prune watermarks for integrations that
are no longer active (deleted, or opted out of polling), so those
settings rows don't accumulate forever.
Examples
iex> PhoenixKit.Modules.Emails.list_brevo_watermark_integration_uuids()
["some-uuid"]
Lists events for a specific email log.
Examples
iex> PhoenixKit.Modules.Emails.list_events_for_log("550e8400-e29b-41d4-a716-446655440000")
[%Event{}, ...]
Lists emails with optional filters.
Options
:status- Filter by status (sent, delivered, bounced, etc.):campaign_id- Filter by campaign:template_name- Filter by template:provider- Filter by email provider:from_date- Emails sent after this date:to_date- Emails sent before this date:recipient- Filter by recipient email:limit- Limit results (default: 50):offset- Offset for pagination
Examples
iex> PhoenixKit.Modules.Emails.list_logs(%{status: "bounced", limit: 10})
[%Log{}, ...]
Checks if placeholder log creation is enabled.
When enabled, the system creates placeholder logs for events received from AWS SES that don't have an existing email log. This can help recover from synchronization issues but may mask underlying problems.
Default: false (recommended for production to expose synchronization issues)
Examples
iex> PhoenixKit.Modules.Emails.placeholder_logs_enabled?()
false
Processes an incoming webhook event (typically from AWS SES).
Examples
iex> webhook_data = %{
"eventType" => "bounce",
"mail" => %{"messageId" => "abc123"}
}
iex> PhoenixKit.Modules.Emails.process_webhook_event(webhook_data)
{:ok, %Event{}}
Checks if full email body saving is enabled.
Returns true if the "email_save_body" setting is true.
Examples
iex> PhoenixKit.Modules.Emails.save_body_enabled?()
false
Checks if email headers saving is enabled.
Returns true if the "email_save_headers" setting is true.
Examples
iex> PhoenixKit.Modules.Emails.save_headers_enabled?()
false
@spec selected_aws_integration_uuid() :: String.t() | nil
The single aws_ses Integrations connection selected via the
emails_aws_integration_uuid setting, or nil.
This is the LEGACY, one-account selection: it names the connection the
global aws_* settings (queue URL, configuration set, …) have always
described, and it is still what the send-path get_aws_* getters resolve
through. Multi-account callers should go through
PhoenixKit.Modules.Emails.AwsIntegrations.active_integration_uuids/0
instead; this getter exists so they can recognise which one account the
legacy globals may still be attributed to.
Examples
iex> PhoenixKit.Modules.Emails.selected_aws_integration_uuid()
"019f562e-0000-7000-8000-000000000000"
Checks if AWS SES event management is enabled.
Examples
iex> PhoenixKit.Modules.Emails.ses_events_enabled?()
true
Sets the AWS region for SES and SQS services.
Examples
iex> PhoenixKit.Modules.Emails.set_aws_region("eu-north-1")
{:ok, %Setting{}}
Persists one account's SES/SQS tracking pipeline. Accepts string- or
atom-keyed attrs; unknown keys are dropped and blank values are stored as
nil, so the stored JSON is always exactly the
["queue_url", "dlq_url", "queue_arn", "sns_topic_arn", "configuration_set", "region"] shape get_aws_tracking/1 reads back.
Callers that change this must also reconcile the SES tracker (a queue URL
appearing/disappearing changes SQSPollingManager.eligible?/0) — see
PhoenixKit.Modules.Emails.EventTrackerReconciler.reconcile_tracker/1.
Examples
iex> PhoenixKit.Modules.Emails.set_aws_tracking("some-uuid", %{"queue_url" => "https://..."})
{:ok, %Setting{}}
Enables or disables Brevo event polling.
Examples
iex> PhoenixKit.Modules.Emails.set_brevo_events_enabled(true)
{:ok, %Setting{}}
Records the timestamp of the last completed Brevo polling cycle.
Examples
iex> PhoenixKit.Modules.Emails.set_brevo_last_polled_at(DateTime.utc_now())
{:ok, %Setting{}}
Sets the list of Brevo integration uuids excluded from polling.
Examples
iex> PhoenixKit.Modules.Emails.set_brevo_polling_excluded_integrations(["uuid-1"])
{:ok, %Setting{}}
Sets the Brevo polling interval in milliseconds (minimum 30 000 — Brevo's rate limits are looser than SQS's long-poll cadence, so this floor is higher than SQS's 1 000ms).
Examples
iex> PhoenixKit.Modules.Emails.set_brevo_polling_interval(60_000)
{:ok, %Setting{}}
Persists one integration's Brevo poll watermark.
Examples
iex> PhoenixKit.Modules.Emails.set_brevo_watermark("some-uuid", ~D[2026-07-19], 2500)
{:ok, %Setting{}}
Sets the number of days after which to compress email bodies.
Examples
iex> PhoenixKit.Modules.Emails.set_compress_after_days(30)
{:ok, %Setting{}}
Enables or disables placeholder log creation.
Parameters
enabled- true to enable placeholder logs, false to disable
Examples
iex> PhoenixKit.Modules.Emails.set_placeholder_logs(false)
{:ok, %Setting{}}
Sets the retention period for emails.
Examples
iex> PhoenixKit.Modules.Emails.set_retention_days(180)
{:ok, %Setting{}}
Enables or disables S3 archival for old email data.
Examples
iex> PhoenixKit.Modules.Emails.set_s3_archival(true)
{:ok, %Setting{}}
Sets the sampling rate for email logging.
Examples
iex> PhoenixKit.Modules.Emails.set_sampling_rate(80) # Log 80% of emails
{:ok, %Setting{}}
Enables or disables full email body saving.
Examples
iex> PhoenixKit.Modules.Emails.set_save_body(true)
{:ok, %Setting{}}
Enables or disables email headers saving.
Examples
iex> PhoenixKit.Modules.Emails.set_save_headers(true)
{:ok, %Setting{}}
Sets the AWS SES configuration set name.
Examples
iex> PhoenixKit.Modules.Emails.set_ses_configuration_set("my-system-set")
{:ok, %Setting{}}
Enables or disables AWS SES event management.
Examples
iex> PhoenixKit.Modules.Emails.set_ses_events(true)
{:ok, %Setting{}}
Sets the AWS SNS Topic ARN for email events.
Examples
iex> PhoenixKit.Modules.Emails.set_sns_topic_arn("arn:aws:sns:eu-north-1:123456789012:phoenixkit-email-events")
{:ok, %Setting{}}
Sets the AWS SQS Dead Letter Queue URL.
Examples
iex> PhoenixKit.Modules.Emails.set_sqs_dlq_url("https://sqs.eu-north-1.amazonaws.com/123456789012/phoenixkit-email-dlq")
{:ok, %Setting{}}
Sets the maximum number of SQS messages to receive per polling cycle.
Examples
iex> PhoenixKit.Modules.Emails.set_sqs_max_messages(20)
{:ok, %Setting{}}
Enables or disables SQS polling.
Examples
iex> PhoenixKit.Modules.Emails.set_sqs_polling(true)
{:ok, %Setting{}}
Sets the list of aws_ses integration uuids excluded from SQS polling.
Examples
iex> PhoenixKit.Modules.Emails.set_sqs_polling_excluded_integrations(["uuid-1"])
{:ok, %Setting{}}
Sets the SQS polling interval in milliseconds.
Examples
iex> PhoenixKit.Modules.Emails.set_sqs_polling_interval(3000) # 3 seconds
{:ok, %Setting{}}
Sets the AWS SQS Queue ARN for email events.
Examples
iex> PhoenixKit.Modules.Emails.set_sqs_queue_arn("arn:aws:sqs:eu-north-1:123456789012:phoenixkit-email-queue")
{:ok, %Setting{}}
Sets the AWS SQS Queue URL for email events.
Examples
iex> PhoenixKit.Modules.Emails.set_sqs_queue_url("https://sqs.eu-north-1.amazonaws.com/123456789012/phoenixkit-email-queue")
{:ok, %Setting{}}
Sets the SQS message visibility timeout in seconds.
Examples
iex> PhoenixKit.Modules.Emails.set_sqs_visibility_timeout(600) # 10 minutes
{:ok, %Setting{}}
Checks if SQS polling is enabled.
Examples
iex> PhoenixKit.Modules.Emails.sqs_polling_enabled?()
true
Manually sync email status by fetching events from SQS queues.
This function searches for events in both the main SQS queue and DLQ that match the given message_id and processes them to update email status.
Parameters
message_id- The AWS SES message ID or internal PhoenixKit message ID to sync
Returns
{:ok, result}- Successful sync with processing results{:error, reason}- Error during sync process
Examples
iex> PhoenixKit.Modules.Emails.sync_email_status("0110019971abc123-...")
{:ok, %{events_processed: 3, log_updated: true}}
iex> PhoenixKit.Modules.Emails.sync_email_status("pk_abc123...")
{:ok, %{events_processed: 1, log_updated: true}}
Updates the status of an email log.
Examples
iex> PhoenixKit.Modules.Emails.update_log_status(log, "delivered")
{:ok, %Log{}}