I just had a heck of a time getting mailgun working this evening, ultimately due to a typo on my mailgun domain in my config details. I thought I would share my journey for those who might run into the same issue.
Since I use direnv, I configured mailgun in config/runtime.exs to work in both dev and production environments:
config :pento, Pento.Mailer,
adapter: Swoosh.Adapters.Mailgun,
api_key: System.get_env("MAILGUN_API_KEY"),
domain: System.get_env("MAILGUN_DOMAIN"),
base_url: "https://api.mailgun.net/v3",
log_level: :debug
I likewise configured the appropriate settings for dev and production:
config :pento, Pento.Mailer, adapter: Swoosh.Adapters.Mailgun
config :swoosh, api_client: Swoosh.ApiClient.Finch, finch_name: Pento.Finch
And also added plug
and multipart
dependencies to mix.exs. I loaded up my application, reset a password and it reported success, redirecting me to the login screen. But mailgun reported no emails sent! Sadly, I am on a free plan so no logs visible on mailgun’s side. I looked through the console, but it looks like the log_level: :debug
setting for the mailer had no effect, there were no logs beyond the ones indicating a success and redirect.
I decided to change up the default UserNotifier boilerplate to log an error and sure enough, I got an error log for {405, ""}
.
case Mailer.deliver(email) do
{:ok, response} ->
Logger.info("Email sent successfully: #{inspect(response)}")
{:ok, email}
{:error, reason} ->
Logger.error("Failed to send email: #{inspect(reason)}")
{:error, email}
end
This was a start, but still missing a lot of detail. I went looking around to see if there was some way to log the lower level finch requests and after some reading came up with the following (not sure if this is correct):
defmodule Pento.Logger do
require Logger
def attach do
:telemetry.attach(
"finch-request-logger",
[:finch, :request, :stop],
&__MODULE__.handle_event/4,
nil
)
end
def handle_event(_event_name, measurements, metadata, _config) do
{_, response} = metadata.result
details = %{
response_status: response.status,
request_host: metadata.request.host,
request_method: metadata.request.method,
request_path: metadata.request.path,
duration: measurements.duration
}
if response.status > 400 do
Logger.error("#{inspect(details)}")
else
Logger.info("#{inspect(details)}")
end
end
end
Finally, I modified the generated PentoWeb.Telemetry
module to attach the logger.
@impl true
def init(_arg) do
children = [
# Telemetry poller will execute the given period measurements
# every 10_000ms. Learn more here: https://hexdocs.pm/telemetry_metrics
{:telemetry_poller, measurements: periodic_measurements(), period: 10_000},
{Finch, name: Pento.Logger}
]
Pento.Logger.attach()
Thankfully, this logged out the details that showed me where I had gone wrong, can you spot it?
[error] %{request_host: "api.mailgun.net", request_path: "/v3/https://sandbox6b3be3f286c2409ab2d71b6fb9b1d52c.mailgun.org//messages", response_status: 405, request_method: "POST", duration: 340163917}
My question for you all going forward, is this the “right way” to log http requests from a third party? If I wanted to log all external requests made by finch in the future, it seems like this is the right approach?