Packages
phoenix_kit
1.2.9
1.7.208
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/mix/tasks/phoenix_kit/email_test_webhook.ex
defmodule Mix.Tasks.PhoenixKit.Email.TestWebhook do
@shortdoc "Test email webhook functionality"
@moduledoc """
Mix task to test email webhook functionality with sample events.
## Usage
# Test bounce event
mix phoenix_kit.email.test_webhook --event bounce
# Test open event with specific message ID
mix phoenix_kit.email.test_webhook --event open --message-id abc123
# Test delivery event
mix phoenix_kit.email.test_webhook --event delivery
# Test all event types
mix phoenix_kit.email.test_webhook --all
## Options
--event TYPE Event type to test: bounce, delivery, send, open, click, complaint
--message-id ID Use specific message ID (uses random if not provided)
--all Test all event types
--endpoint URL Custom webhook endpoint URL
--no-verify Skip signature verification (for testing)
## Event Types
send - Email send confirmation
delivery - Successful delivery
bounce - Hard/soft bounce
complaint - Spam complaint
open - Email opened (tracking pixel)
click - Link clicked
## Examples
# Test bounce handling
mix phoenix_kit.email.test_webhook --event bounce --message-id test-123
# Test all events with custom endpoint
mix phoenix_kit.email.test_webhook --all --endpoint {prefix}/webhooks/email
# Where {prefix} is your configured PhoenixKit URL prefix
# Quick delivery test
mix phoenix_kit.email.test_webhook --event delivery
"""
use Mix.Task
alias PhoenixKit.EmailTracking
def run(args) do
Mix.Task.run("app.start")
{options, _remaining} = parse_options(args)
unless EmailTracking.enabled?() do
Mix.shell().error("Email is not enabled.")
exit({:shutdown, 1})
end
Mix.shell().info(IO.ANSI.cyan() <> "\n๐งช Email Webhook Testing" <> IO.ANSI.reset())
Mix.shell().info(String.duplicate("=", 40))
if options[:all] do
test_all_events(options)
else
event_type = options[:event] || "delivery"
test_single_event(event_type, options)
end
end
defp parse_options(args) do
{options, remaining, _errors} =
OptionParser.parse(args,
strict: [
event: :string,
message_id: :string,
all: :boolean,
endpoint: :string,
no_verify: :boolean
]
)
# Set defaults
options =
options
|> Keyword.put_new(:all, false)
|> Keyword.put_new(:no_verify, false)
{options, remaining}
end
defp test_all_events(options) do
event_types = ["send", "delivery", "bounce", "complaint", "open", "click"]
Mix.shell().info("Testing all event types...\n")
results =
Enum.map(event_types, fn event_type ->
result = test_single_event(event_type, options)
# Small delay between tests
Process.sleep(500)
{event_type, result}
end)
# Summary
Mix.shell().info("\n๐ Test Summary:")
for {event_type, result} <- results do
status_icon = if result == :ok, do: "โ
", else: "โ"
Mix.shell().info(" #{status_icon} #{String.pad_trailing(event_type, 12)} #{result}")
end
end
defp test_single_event(event_type, options) do
Mix.shell().info("๐งช Testing #{event_type} event...")
# Create test email log if needed
message_id = options[:message_id] || generate_test_message_id()
test_log = ensure_test_log(message_id)
# Generate test event
test_event = generate_test_event(event_type, message_id, test_log)
# Test webhook processing
case test_webhook_processing(test_event, options) do
:ok ->
Mix.shell().info("โ
#{event_type} event processed successfully")
:ok
{:error, reason} ->
Mix.shell().error("โ #{event_type} event failed: #{reason}")
{:error, reason}
end
end
defp generate_test_message_id do
timestamp = DateTime.utc_now() |> DateTime.to_unix()
"test-webhook-#{timestamp}-#{:rand.uniform(9999)}"
end
defp ensure_test_log(message_id) do
case EmailTracking.get_log_by_message_id(message_id) do
nil ->
# Create a test log
{:ok, log} =
EmailTracking.create_log(%{
message_id: message_id,
to: "test@example.com",
from: "noreply@phoenixkit.dev",
subject: "Test Email for Webhook",
status: "sent",
provider: "test_provider",
sent_at: DateTime.utc_now()
})
Mix.shell().info("๐ง Created test email log: #{message_id}")
log
log ->
Mix.shell().info("๐ง Using existing email log: #{message_id}")
log
end
end
defp generate_test_event(event_type, message_id, _log) do
base_event = %{
"Type" => "Notification",
"MessageId" => "webhook-test-#{:rand.uniform(99999)}",
"Timestamp" => DateTime.utc_now() |> DateTime.to_iso8601(),
"Message" => Jason.encode!(generate_ses_message(event_type, message_id))
}
base_event
end
defp generate_ses_message("send", message_id) do
%{
"eventType" => "send",
"mail" => %{
"timestamp" => DateTime.utc_now() |> DateTime.to_iso8601(),
"messageId" => message_id,
"source" => "test@phoenixkit.dev",
"destination" => ["test@example.com"]
},
"send" => %{}
}
end
defp generate_ses_message("delivery", message_id) do
%{
"eventType" => "delivery",
"mail" => %{
"timestamp" => DateTime.utc_now() |> DateTime.to_iso8601(),
"messageId" => message_id,
"source" => "test@phoenixkit.dev",
"destination" => ["test@example.com"]
},
"delivery" => %{
"timestamp" => DateTime.utc_now() |> DateTime.to_iso8601(),
"processingTimeMillis" => 2000,
"recipients" => ["test@example.com"],
"smtpResponse" => "250 2.0.0 OK"
}
}
end
defp generate_ses_message("bounce", message_id) do
%{
"eventType" => "bounce",
"mail" => %{
"timestamp" => DateTime.utc_now() |> DateTime.to_iso8601(),
"messageId" => message_id,
"source" => "test@phoenixkit.dev",
"destination" => ["bounce@example.com"]
},
"bounce" => %{
"bounceType" => "Permanent",
"bounceSubType" => "General",
"timestamp" => DateTime.utc_now() |> DateTime.to_iso8601(),
"feedbackId" => "test-bounce-#{:rand.uniform(9999)}",
"bouncedRecipients" => [
%{
"emailAddress" => "bounce@example.com",
"status" => "5.1.1",
"action" => "failed",
"diagnosticCode" => "smtp; 550 5.1.1 User unknown"
}
]
}
}
end
defp generate_ses_message("complaint", message_id) do
%{
"eventType" => "complaint",
"mail" => %{
"timestamp" => DateTime.utc_now() |> DateTime.to_iso8601(),
"messageId" => message_id,
"source" => "test@phoenixkit.dev",
"destination" => ["complaint@example.com"]
},
"complaint" => %{
"complainedRecipients" => [
%{
"emailAddress" => "complaint@example.com"
}
],
"timestamp" => DateTime.utc_now() |> DateTime.to_iso8601(),
"feedbackId" => "test-complaint-#{:rand.uniform(9999)}",
"complaintFeedbackType" => "abuse"
}
}
end
defp generate_ses_message("open", message_id) do
%{
"eventType" => "open",
"mail" => %{
"timestamp" => DateTime.utc_now() |> DateTime.to_iso8601(),
"messageId" => message_id,
"source" => "test@phoenixkit.dev",
"destination" => ["test@example.com"]
},
"open" => %{
"timestamp" => DateTime.utc_now() |> DateTime.to_iso8601(),
"userAgent" => "Mozilla/5.0 (Test Webhook)",
"ipAddress" => "192.0.2.1"
}
}
end
defp generate_ses_message("click", message_id) do
%{
"eventType" => "click",
"mail" => %{
"timestamp" => DateTime.utc_now() |> DateTime.to_iso8601(),
"messageId" => message_id,
"source" => "test@phoenixkit.dev",
"destination" => ["test@example.com"]
},
"click" => %{
"timestamp" => DateTime.utc_now() |> DateTime.to_iso8601(),
"userAgent" => "Mozilla/5.0 (Test Webhook)",
"ipAddress" => "192.0.2.1",
"link" => "https://example.com/test-link",
"linkTags" => %{
"campaign" => "test"
}
}
}
end
defp test_webhook_processing(webhook_data, _options) do
# Process the webhook event using EmailTracking
case EmailTracking.process_webhook_event(webhook_data) do
{:ok, _event} ->
:ok
{:error, :email_log_not_found} ->
# This might be expected for some test cases
Mix.shell().info("โน๏ธ Note: Email log not found (this may be expected for test events)")
:ok
{:error, reason} ->
{:error, reason}
end
rescue
error ->
{:error, Exception.message(error)}
end
end