We can't find the internet
Something went wrong!
Sending Email with Swoosh via Mailgun in a Phoenix Application

- Created: 25/09/2025
- Last updated: 25/09/2025
Setting up Swoosh with Mailgun requires some dependencies and configuration that aren’t immediately obvious from the documentation. This guide covers the missing pieces.
Overview
This guide assumes you already have a Phoenix application. We’ll focus on the tricky parts that aren’t well documented elsewhere - specifically configuring Swoosh to work reliably with Mailgun, handling the gotchas, and getting emails actually sending in production.
Prerequisites
- A Mailgun account with API credentials
- Some knowledge of Elixir and Phoenix
Starting point
To get to out starting point so that you can follow along if you like:
-
Init a new app
-
mix archive.install hex phx_new
- Update dev and test config
-
Set up the database
mix ecto.create
-
-
Set up releases
-
mix phx.gen.release --docker
-
-
Add user authentication with
-
mix phx.gen.auth Accounts User users
-
mix deps.get
-
mix ecto.migrate
-
-
Run tests to make sure everything works as expected
-
mix test
-
- Seed a user account:
alias Mailgunner.Repo
alias Mailgunner.Accounts
alias Mailgunner.Accounts.User
{:ok, user} =
Accounts.register_user(%{
email: "user@user.user"
})
user
|> User.password_changeset(%{password: "qweQWE123"})
|> User.confirm_changeset()
|> Repo.update()
mix ecto.reset
Now we have a working phoenix application with users, user authentication and authorization, and also release configuration with a docker image to run the app.
There are modules in place to handle user notifications. All we need to do is configure Swoosh to use its provided MailgunAdapter to deliver emails.
You could also check out Initial commit
on the project repo.
First attempt
In ./config/runtime.exs
I set Mailgun configuration as shown in the Swoosh MailgunAdapter documentation. https://hexdocs.pm/swoosh/Swoosh.Adapters.Mailgun.html And also set up configuration for sender address and name.
config :mailgunner, Mailgunner.Mailer,
adapter: Swoosh.Adapters.Mailgun,
base_url: System.fetch_env!("MAILGUN_BASE_URL")
api_key: System.fetch_env!("MAILGUN_API_KEY"),
domain: System.fetch_env!("MAILGUN_DOMAIN")
Set environment variables to align with Mailgun. base_url
is required if you are using the EU region.
Mailgun will provide the required environment variable values if you go to https://app.mailgun.com/mg/sending/domains
and select your domain.
Also… if you are testing this out in dev mode, you will want to comment this out in ./config/dev/exs
:
# Disable swoosh api client as it is only required for production adapters.
# config :swoosh, :api_client, false
When you try to run the app, it doesn’t work without additional dependencies.
Adding dependencies
Swoosh comes with a mailgun adapter, as we have seen however, it doesn’t actually work without several additional dependencies.
We need hackney for Swoosh.Adapters.Mailgun
to work. This is stated in swoosh installation guide as “optional-ish”. Its not optional.
(Optional-ish) Most adapters (non SMTP ones) use Swoosh.ApiClient to talk to the service provider. Swoosh comes with Swoosh.ApiClient.Hackney configured by default. If you want to use it, you just need to include Hackney as a dependency of your app.
As stated in Swoosh.Adapters.Mailgun
docs, we need some addition dependencies; Plug and Multipart.
And then when you got to run the app, you will see an error message, saying that you need 2 further dependencies:
[error] The following dependencies are required to use Swoosh.Adapters.Mailgun:
- Elixir.Multipart from :multipart
- Elixir.Plug.Conn.Query from :plug
So all together we can add the following to mix.exs
:
#...
{:hackney, "~> 1.9"},
{:multipart, "~> 0.4.0"},
{:plug, "~> 1.18"}
#...
These were up to date versions at the time of writing, but it would be worth a check to see what version you should be installing.
Sending emails
Now that we have the required dependencies installed, and suitable configuration provided, we can make it send some emails!
alias Mailgunner.Accounts.User
alias Mailgunner.Accounts.UserNotifier
alias Mailgunner.Repo
user = User |> Repo.one()
user |> Accounts.UserNotifier.deliver_update_email_instructions("https://n10e.co")
See mailgun logs to make sure they got it:
https://app.mailgun.com/mg/reporting/logs
Common issues and solutions
Possible long feedback loop
Do your initial testing locally in dev mode to avoid a long feedback loop with this one. Even if dev mode will actually use Swoosh.Adapters.Local
when you are done.
Sandbox delivery errors
If you are testing with your mailgun sandbox address, ensure that you have added your users email address to the recipient allow list.
Conclusion
Once you have the right dependencies, Swoosh and Mailgun work well together. The main issue is that several “optional” dependencies are actually required.