Packages
phoenix_kit
1.7.69
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 UUID
mix phoenix_kit.email.test_webhook --event open --message-uuid 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-uuid UUID Use specific message UUID (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 (AWS SES)
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.Modules.Emails
alias PhoenixKit.Utils.Date, as: UtilsDate
@impl Mix.Task
def run(args) do
Mix.Task.run("app.start")
{options, _remaining} = parse_options(args)
unless Emails.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_uuid: :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_uuid = options[:message_uuid] || generate_test_message_uuid()
test_log = ensure_test_log(message_uuid)
# Generate test event
test_event = generate_test_event(event_type, message_uuid, 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_uuid do
timestamp = UtilsDate.utc_now() |> DateTime.to_unix()
"test-webhook-#{timestamp}-#{:rand.uniform(9999)}"
end
defp ensure_test_log(message_uuid) do
case Emails.get_log_by_message_id(message_uuid) do
{:error, :not_found} ->
# Create a test log
{:ok, log} =
Emails.create_log(%{
message_id: message_uuid,
to: "test@example.com",
from: "noreply@phoenixkit.dev",
subject: "Test Email for Webhook",
status: "sent",
provider: "test_provider",
sent_at: UtilsDate.utc_now()
})
Mix.shell().info("๐ง Created test email log: #{message_uuid}")
log
{:ok, log} ->
Mix.shell().info("๐ง Using existing email log: #{message_uuid}")
log
{:error, reason} ->
Mix.shell().error("โ Error getting email log: #{inspect(reason)}")
nil
end
end
defp generate_test_event(event_type, message_uuid, _log) do
base_event = %{
"Type" => "Notification",
"MessageId" => "webhook-test-#{:rand.uniform(99999)}",
"Timestamp" => UtilsDate.utc_now() |> DateTime.to_iso8601(),
"Message" => Jason.encode!(generate_ses_message(event_type, message_uuid))
}
base_event
end
defp generate_ses_message("send", message_uuid) do
%{
"eventType" => "send",
"mail" => %{
"timestamp" => UtilsDate.utc_now() |> DateTime.to_iso8601(),
"messageId" => message_uuid,
"source" => "test@phoenixkit.dev",
"destination" => ["test@example.com"]
},
"send" => %{}
}
end
defp generate_ses_message("delivery", message_uuid) do
%{
"eventType" => "delivery",
"mail" => %{
"timestamp" => UtilsDate.utc_now() |> DateTime.to_iso8601(),
"messageId" => message_uuid,
"source" => "test@phoenixkit.dev",
"destination" => ["test@example.com"]
},
"delivery" => %{
"timestamp" => UtilsDate.utc_now() |> DateTime.to_iso8601(),
"processingTimeMillis" => 2000,
"recipients" => ["test@example.com"],
"smtpResponse" => "250 2.0.0 OK"
}
}
end
defp generate_ses_message("bounce", message_uuid) do
%{
"eventType" => "bounce",
"mail" => %{
"timestamp" => UtilsDate.utc_now() |> DateTime.to_iso8601(),
"messageId" => message_uuid,
"source" => "test@phoenixkit.dev",
"destination" => ["bounce@example.com"]
},
"bounce" => %{
"bounceType" => "Permanent",
"bounceSubType" => "General",
"timestamp" => UtilsDate.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_uuid) do
%{
"eventType" => "complaint",
"mail" => %{
"timestamp" => UtilsDate.utc_now() |> DateTime.to_iso8601(),
"messageId" => message_uuid,
"source" => "test@phoenixkit.dev",
"destination" => ["complaint@example.com"]
},
"complaint" => %{
"complainedRecipients" => [
%{
"emailAddress" => "complaint@example.com"
}
],
"timestamp" => UtilsDate.utc_now() |> DateTime.to_iso8601(),
"feedbackId" => "test-complaint-#{:rand.uniform(9999)}",
"complaintFeedbackType" => "abuse"
}
}
end
defp generate_ses_message("open", message_uuid) do
%{
"eventType" => "open",
"mail" => %{
"timestamp" => UtilsDate.utc_now() |> DateTime.to_iso8601(),
"messageId" => message_uuid,
"source" => "test@phoenixkit.dev",
"destination" => ["test@example.com"]
},
"open" => %{
"timestamp" => UtilsDate.utc_now() |> DateTime.to_iso8601(),
"userAgent" => "Mozilla/5.0 (Test Webhook)",
"ipAddress" => "192.0.2.1"
}
}
end
defp generate_ses_message("click", message_uuid) do
%{
"eventType" => "click",
"mail" => %{
"timestamp" => UtilsDate.utc_now() |> DateTime.to_iso8601(),
"messageId" => message_uuid,
"source" => "test@phoenixkit.dev",
"destination" => ["test@example.com"]
},
"click" => %{
"timestamp" => UtilsDate.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 Emails.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