Packages
phoenix_kit
1.7.69
1.7.207
1.7.206
1.7.205
1.7.204
1.7.203
1.7.202
1.7.201
1.7.200
1.7.199
1.7.198
1.7.197
1.7.196
1.7.194
1.7.193
1.7.192
1.7.191
1.7.190
1.7.189
1.7.187
1.7.186
1.7.185
1.7.184
1.7.183
1.7.182
1.7.181
1.7.180
1.7.179
1.7.178
1.7.177
1.7.176
1.7.175
1.7.174
1.7.173
1.7.172
1.7.171
1.7.170
1.7.169
1.7.168
1.7.167
1.7.166
1.7.165
1.7.164
1.7.162
1.7.161
1.7.160
1.7.159
1.7.157
1.7.156
1.7.155
1.7.154
1.7.153
1.7.152
1.7.151
1.7.150
1.7.149
1.7.146
1.7.145
1.7.144
1.7.143
1.7.138
1.7.133
1.7.132
1.7.131
1.7.130
1.7.128
1.7.126
1.7.125
1.7.121
1.7.120
1.7.119
1.7.118
1.7.117
1.7.116
1.7.115
1.7.114
1.7.113
1.7.112
1.7.111
1.7.110
1.7.109
1.7.108
1.7.107
1.7.106
1.7.105
1.7.104
1.7.103
1.7.102
1.7.101
1.7.100
1.7.99
1.7.98
1.7.97
1.7.96
1.7.95
1.7.94
1.7.93
1.7.92
1.7.91
1.7.90
1.7.89
1.7.88
1.7.87
1.7.86
1.7.85
1.7.84
1.7.83
1.7.82
1.7.81
1.7.80
1.7.79
1.7.78
1.7.77
1.7.76
1.7.75
1.7.74
1.7.71
1.7.70
1.7.69
1.7.66
1.7.65
1.7.64
1.7.63
1.7.62
1.7.61
1.7.59
1.7.58
1.7.57
1.7.56
1.7.55
1.7.54
1.7.53
1.7.52
1.7.51
1.7.49
1.7.44
1.7.43
1.7.42
1.7.41
1.7.39
1.7.38
1.7.37
1.7.36
1.7.34
1.7.33
1.7.31
1.7.30
1.7.29
1.7.28
1.7.27
1.7.26
1.7.25
1.7.24
1.7.23
1.7.22
1.7.21
1.7.20
1.7.19
1.7.18
1.7.17
1.7.16
1.7.15
1.7.14
1.7.13
1.7.12
1.7.11
1.7.10
1.7.9
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.20
1.6.19
1.6.18
1.6.17
1.6.16
1.6.15
1.6.14
1.6.13
1.6.12
1.6.11
1.6.10
1.6.9
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.5.2
1.5.1
1.5.0
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.10
1.2.9
1.2.8
1.2.7
1.2.5
1.2.4
1.2.2
1.2.1
1.2.0
1.1.0
1.0.0
A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more
Current section
Files
Jump to
Current section
Files
lib/modules/emails/README.md
# Emails Module
The PhoenixKit Emails module provides a production-ready outbound email pipeline with logging,
analytics, AWS SES integration, and a full administration UI. This document consolidates all of
the guidance that previously lived in `CLAUDE.md`.
## Architecture Overview
- **PhoenixKit.Modules.Emails** – Main API module for email functionality
- **PhoenixKit.Modules.Emails.EmailLog** – Core email logging schema with analytics
- **PhoenixKit.Modules.Emails.EmailEvent** – Event management (delivery, bounce, click, open)
- **PhoenixKit.Modules.Emails.EmailInterceptor** – Swoosh integration for automatic logging
- **PhoenixKit.Modules.Emails.SQSWorker** – AWS SQS polling for real-time events
- **PhoenixKit.Modules.Emails.SQSProcessor** – Message parsing and event handling
- **PhoenixKit.Modules.Emails.RateLimiter** – Anti-spam and rate limiting
- **PhoenixKit.Modules.Emails.Archiver** – Data lifecycle and S3 archival
- **PhoenixKit.Modules.Emails.Metrics** – Local database analytics and dashboard data
## Core Features
- **Comprehensive Logging** – All outgoing emails logged with metadata
- **Event Management** – Real-time delivery, bounce, complaint, open, click events
- **AWS SES Integration** – Deep integration with SES webhooks for event tracking
- **Analytics Dashboard** – Engagement metrics, campaign analysis, geographic data
- **Rate Limiting** – Multi-layer protection against abuse and spam patterns
- **Data Lifecycle** – Automatic archival, compression, and cleanup
- **Settings Integration** – Configurable via admin settings interface
## Database Tables
- **phoenix_kit_email_logs** – Main email logging with extended metadata
- **phoenix_kit_email_events** – Event management (delivery, engagement)
- **phoenix_kit_email_blocklist** – Blocked addresses for rate limiting
- **phoenix_kit_email_templates** – Email template storage and management
## LiveView Interfaces
- **Emails** – Email log browsing and management at `{prefix}/admin/emails`
- **Details** – Individual email details at `{prefix}/admin/emails/email/:id`
- **Metrics** – Analytics dashboard at `{prefix}/admin/emails/dashboard`
- **Queue** – Queue management at `{prefix}/admin/emails/queue`
- **Blocklist** – Blocklist management at `{prefix}/admin/emails/blocklist`
- **Templates** – Template management at `{prefix}/admin/emails/templates`
- **Template Editor** – Template creation/editing at `{prefix}/admin/emails/templates/new`
and `{prefix}/admin/emails/templates/:id/edit`
- **Settings** – Email system configuration at `{prefix}/admin/settings/emails`
## Mailer Integration Example
```elixir
# PhoenixKit.Mailer automatically intercepts emails
email =
new()
|> to("user@example.com")
|> from("app@example.com")
|> subject("Welcome!")
|> html_body("<h1>Welcome!</h1>")
# Emails are automatically logged when sent
PhoenixKit.Mailer.deliver_email(email,
user_uuid: user.uuid,
template_name: "welcome",
campaign_id: "onboarding"
)
```
## AWS SES Infrastructure
PhoenixKit ships tooling that provisions the required AWS infrastructure and stores the resulting
configuration inside PhoenixKit settings. The automation creates:
- An SES configuration set with event publishing
- An SNS topic for SES events
- An SQS queue (and DLQ) with correct permissions
- IAM policies and roles tuned for the above resources
- Persisted configuration values in PhoenixKit Settings
## Configuration Strategy
Email system configuration is managed via the **Settings Database** (preferred) with fallbacks to
environment variables for secrets. Use `config/config.exs` only for baseline PhoenixKit integration.
### Key Settings
- `email_enabled` – Master toggle for the entire system
- `email_save_body` – Store full email content (increases storage)
- `email_ses_events` – Enable AWS SES event processing
- `email_retention_days` – Data retention period (30–365 days)
- `email_sampling_rate` – Percentage of emails to fully log
- `sqs_polling_enabled` – Enable/disable SQS polling worker
- `sqs_polling_interval_ms` – Polling interval for the worker
### Security Features
- Sampling rate controls to reduce storage load
- Per-recipient, per-sender, and global rate limiting
- Automatic blocklist for suspicious patterns
- Compression of historical email bodies
- Optional S3 archival for long-term retention
### Analytics Capabilities
- Engagement metrics (open, click, bounce rates)
- Campaign analysis and segmentation
- Geographic insights
- Provider-level deliverability tracking
- Real-time dashboards and trends
### Recommended Web UI Flow
1. Navigate to `{prefix}/admin/settings/emails`
2. Enable the email system (`email_enabled = true`)
3. Configure AWS SES region and configuration set
4. Adjust retention (`email_retention_days`) and sampling rate (`email_sampling_rate`)
5. Configure whether to persist full bodies (`email_save_body`)
6. Review additional SQS polling parameters as needed
### CLI Flow
```bash
mix phoenix_kit.configure_aws_ses --config-set "my-app-tracking"
mix phoenix_kit.configure_aws_ses --region "eu-north-1"
mix phoenix_kit.configure_aws_ses --status # Check current config
```
### Configuration (Secrets)
Configure via Settings UI at `/{prefix}/admin/settings/emails` or via config:
```elixir
# config/config.exs
config :phoenix_kit,
aws: [
access_key_id: "your-access-key",
secret_access_key: "your-secret-key"
]
```
### Important Note
⚠️ **Do not configure email settings in `config/config.exs`.** Restrict that file to the PhoenixKit
`repo` and optional `mailer` integration. Manage email configuration at runtime via the Settings UI
or mix tasks.
### Configuration Sources (Priority)
PhoenixKit uses a smart fallback system for credentials and configuration:
1. **Settings Database** – Primary source. Values entered in the UI take precedence.
2. **Environment Variables** – Fallback when Settings values are empty or missing.
3. **config/config.exs** – Only for baseline PhoenixKit integration, never for sensitive data.
### Security Best Practices
- Store AWS credentials in environment variables (or secret manager) for production.
- Keep non-sensitive configuration in the Settings Database for runtime control.
- Never commit credentials or queue URLs to version control.
### Configuration Methods
#### Method 1: Web UI (Recommended)
- Navigate to `{prefix}/admin/settings/emails`
- Configure AWS SES, SNS, SQS endpoints
- Enable/disable the email system
- Adjust retention, sampling, and polling settings
- Changes take effect immediately without deploys
#### Method 2: Mix Task (CLI)
```bash
mix phoenix_kit.configure_aws_ses --config-set "my-app-tracking"
mix phoenix_kit.configure_aws_ses --region "us-east-1"
mix phoenix_kit.configure_aws_ses --status # Check current config
```
#### Method 3: AWS Setup Script (Full Automation)
```bash
cd /app/scripts
./aws_ses_sqs_setup.sh # Creates AWS infrastructure + saves to Settings DB
```
#### Method 4: Application Config (Secrets Only)
```elixir
# config/config.exs
config :phoenix_kit,
aws: [
access_key_id: "your-key-id",
secret_access_key: "your-secret-key"
]
```
### Storage Map
**Settings Database**
- `aws_region` (default `eu-north-1`)
- `aws_sqs_queue_url`
- `aws_sqs_dlq_url`
- `aws_sqs_queue_arn`
- `aws_sns_topic_arn`
- `aws_ses_configuration_set` (default `phoenixkit-tracking`)
- `email_enabled`
- `email_save_body`
- `email_ses_events`
- `email_retention_days`
- `email_sampling_rate`
- `sqs_polling_enabled`
- `sqs_polling_interval_ms`
- All other email-related settings
**`config/config.exs`**
- `repo:` – PhoenixKit repository configuration (required)
- `mailer:` – Optional override to reuse parent app mailer
- Never store AWS credentials or email configuration here
### AWS Credentials Priority
```
1. Settings Database (primary)
└─> If credentials exist and are non-empty → use them
2. Application Config (fallback)
└─> Used when Settings Database values are blank
```
This means:
- ✅ Settings values override config for runtime control
- ✅ Config provides defaults for new installations
- ❌ Leaving both empty results in missing credentials
Example scenarios:
```bash
# 1) Web UI + Config → Settings Database wins
# Settings: aws_access_key_id = "AKIA...from_ui"
# Config: aws: [access_key_id: "AKIA...from_config"]
# Result: Uses "AKIA...from_ui"
# 2) Config only → fallback kicks in
# Settings: aws_access_key_id = ""
# Config: aws: [access_key_id: "AKIA...from_config"]
# Result: Uses "AKIA...from_config"
# 3) Nothing configured → error
# Settings: aws_access_key_id = ""
# Config: (not set)
# Result: Raises configuration error
```
### Example Application Configuration
```elixir
# config/config.exs – ONLY basic app configuration
config :phoenix_kit,
repo: MyApp.Repo,
mailer: MyApp.Mailer # Optional: delegate to parent app's mailer
# Configure your app's mailer for development
config :my_app, MyApp.Mailer,
adapter: Swoosh.Adapters.AmazonSES,
region: "eu-north-1"
# AWS credentials are provided by PhoenixKit via the Settings Database
# Configure credentials via the Web UI at {prefix}/admin/settings/emails
```
## Email System Features
The PhoenixKit email system provides:
- Comprehensive email logging and analytics
- Real-time delivery, bounce, and engagement management
- Anti-spam and rate limiting features
- Admin interfaces at `{prefix}/admin/emails/*`
- Automatic integration with PhoenixKit.Mailer
- AWS SES event tracking via SNS/SQS pipeline
## Troubleshooting
### Common Issues and Solutions
#### Problem 1: Email fails with `expected a map, got: []`
**Symptoms**
```elixir
** (FunctionClauseError) no function clause matching in Map.merge/2
expected a map, got: []
```
**Root Cause**
The `build_message_tags` function in `interceptor.ex` returned an empty list `[]` instead of a map `%{}`
whenever `message_tags` was passed in as a list.
**Solution**
✅ Fixed in v1.3.3+
A type guard was added in [`lib/phoenix_kit/emails/interceptor.ex:529-534`](lib/phoenix_kit/emails/interceptor.ex#L529-L534):
```elixir
defp build_message_tags(%Email{} = email, opts) do
base_tags =
case Keyword.get(opts, :message_tags, %{}) do
tags when is_map(tags) -> tags
_ -> %{}
end
# ...
end
```
**Verification**
```bash
mix test test/phoenix_kit/emails/interceptor_test.exs
# Expected: 13 tests, 0 failures
```
---
#### Problem 2: Logger warning while compiling the LiveView
**Symptoms**
```
warning: Logger.error/2 is undefined or private
```
**Root Cause**
The `require Logger` call lived inside a function instead of at the top of the module.
**Solution**
✅ Fixed – move `require Logger` to the top of the module:
```elixir
defmodule PhoenixKitWeb.Live.Modules.Emails.Emails do
use PhoenixKitWeb, :live_view
require Logger
alias PhoenixKit.Modules.Emails
# ...
end
```
---
#### Problem 3: No repository configured for PhoenixKit
**Symptoms**
```elixir
** (RuntimeError) No repository configured for PhoenixKit.
Please configure a repository in your application:
config :phoenix_kit, repo: MyApp.Repo
```
**Root Cause**
PhoenixKit requires a configured repository in order to talk to the database.
**Solution**
1. **Production/Development** – add the repo configuration to `config/config.exs`:
```elixir
config :phoenix_kit,
repo: MyApp.Repo
```
2. **Tests** – most functions need a database. Use only the public APIs that do not require a repo,
such as:
- `PhoenixKit.Modules.Emails.Interceptor.detect_provider/2`
- `PhoenixKit.Modules.Emails.Interceptor.build_ses_headers/2` (with a real log struct)
Example `DataCase` setup:
```elixir
defmodule PhoenixKit.DataCase do
use ExUnit.CaseTemplate
setup tags do
:ok = Ecto.Adapters.SQL.Sandbox.checkout(PhoenixKit.Repo)
unless tags[:async] do
Ecto.Adapters.SQL.Sandbox.mode(PhoenixKit.Repo, {:shared, self()})
end
:ok
end
end
```
---
#### Problem 4: AWS SES credentials are ignored
**Symptoms**
- Emails are not delivered
- No errors appear in logs
- AWS credentials exist in ENV but are ignored
**Root Cause**
PhoenixKit uses the Settings Database as the primary source for AWS credentials.
**Solution**
1. **Check the Settings Database** via the Web UI:
```
{prefix}/admin/settings/emails → aws_access_key_id field
```
2. **Check Settings UI** - Navigate to `{prefix}/admin/settings/emails` and verify AWS credentials are saved
3. **Check config** - Verify `config :phoenix_kit, aws:` is set in `config/config.exs`
**Verification**
```bash
mix phoenix_kit.configure_aws_ses --status
```
---
#### Problem 5: ConfigurationSetDoesNotExist error
**Symptoms**
```
AWS SES error: ConfigurationSetDoesNotExist
Configuration set 'myapp-emailing' does not exist
```
**Root Cause**
PhoenixKit versions before 1.4.5 required AWS CLI for SES setup (steps 8-9). In Docker/Kubernetes environments without AWS CLI installed, the setup appeared successful but the SES configuration set was never actually created in AWS.
**Solution (PhoenixKit 1.4.5+)**
✅ **Automatic** - infrastructure setup now uses SES v2 API without AWS CLI dependency
Simply re-run the setup:
```elixir
PhoenixKit.AWS.InfrastructureSetup.run(project_name: "yourapp")
```
**Solution (PhoenixKit < 1.4.5)**
1. **Recommended:** Upgrade to PhoenixKit 1.4.5+
2. Re-run setup: `PhoenixKit.AWS.InfrastructureSetup.run(project_name: "yourapp")`
**Manual workaround (if upgrade not possible):**
```bash
# Create configuration set manually
aws sesv2 create-configuration-set \
--configuration-set-name "yourapp-emailing" \
--region eu-north-1
# Configure event destination
aws sesv2 create-configuration-set-event-destination \
--configuration-set-name "yourapp-emailing" \
--event-destination-name "email-events-to-sns" \
--event-destination '{
"Enabled": true,
"MatchingEventTypes": [
"SEND", "REJECT", "BOUNCE", "COMPLAINT", "DELIVERY",
"OPEN", "CLICK", "RENDERING_FAILURE", "DELIVERY_DELAY", "SUBSCRIPTION"
],
"SnsDestination": {
"TopicArn": "arn:aws:sns:eu-north-1:123456:yourapp-email-events"
}
}' \
--region eu-north-1
```
**Verification**
Check that all 9 setup steps completed successfully:
```elixir
# Look for these log messages:
# [AWS Setup] [8/9] Creating SES Configuration Set...
# [AWS Setup] ✓ SES Configuration Set created
# [AWS Setup] [9/9] Configuring SES event tracking to SNS...
# [AWS Setup] ✓ SES Event Tracking configured
```
## Debugging Tips
- Enable verbose logging:
```elixir
# config/dev.exs
config :logger, level: :debug
# In iex
Logger.configure(level: :debug)
```
- Inspect recent logs:
```elixir
logs = PhoenixKit.Modules.Emails.list_logs(limit: 10)
failed = PhoenixKit.Modules.Emails.list_logs(status: "failed", limit: 10)
log = PhoenixKit.Modules.Emails.get_log!(123)
IO.inspect(log.error_message)
```
- Monitor queue depth:
```bash
aws sqs get-queue-attributes \
--queue-url "your-queue-url" \
--attribute-names ApproximateNumberOfMessages
```
## Performance Tuning
**Problem: Slow email sending**
- **Symptoms** – Long delivery times and increased database load.
- **Mitigations**
1. Disable full body saving:
```elixir
PhoenixKit.Settings.update_setting("email_save_body", "false")
```
2. Reduce sampling rate:
```elixir
PhoenixKit.Settings.update_setting("email_sampling_rate", "10")
```
3. Add database indexes:
```sql
CREATE INDEX idx_email_logs_sent_at ON phoenix_kit_email_logs(sent_at);
CREATE INDEX idx_email_logs_status ON phoenix_kit_email_logs(status);
```
## Testing Strategies
- **Unit tests (no DB)** – Focus on pure functions such as `detect_provider/2`.
- **Integration tests (with DB)** – Use `PhoenixKit.DataCase`, sandboxed repo.
Example:
```elixir
defmodule PhoenixKit.Modules.Emails.InterceptorTest do
use ExUnit.Case, async: true
describe "detect_provider/2" do
test "detects AWS SES from headers" do
email = Email.new() |> Email.header("X-SES-CONFIGURATION-SET", "test")
assert Interceptor.detect_provider(email, []) == "aws_ses"
end
end
end
```
## Getting Help
1. Tail application logs: `tail -f log/dev.log`
2. Enable debug logging: `Logger.configure(level: :debug)`
3. Run the email test suite: `mix test test/phoenix_kit/emails/`
4. Search GitHub issues: <https://github.com/phoenixkit/phoenix_kit/issues>
5. Revisit this README for module-specific architecture and troubleshooting details