Sending Email with Swoosh via Mailgun in a Phoenix Application

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.

References

TLDR: Filling in the missing steps when sending email with Mailgun via Swoosh
Let's Make Your Next Project a Success!
Ready to take your digital presence to the next level? From design and development to ongoing support and maintenance, I provide the expertise to bring your vision to life.
Related services:
Related technologies: