Skip to content

Phoenix

Guide for applications built with Phoenix 1.7+ (Elixir). Mailexam connects as SMTP via Swoosh and the Swoosh.Adapters.SMTP adapter (gen_smtp library).

What you need

  • A Mailexam account and a project with SMTP credentials.
  • Elixir 1.15+ and Erlang/OTP 26+.

Copy from the welcome email (or dashboard) for your project:

  • YOUR_LOGIN — SMTP login (for example, xxxxx);
  • YOUR_PASSWORD — SMTP password (a unique pair with the login);
  • host — YOUR_LOGIN.mailexam.io (matches the login).

1. Dependencies

Create a project (Swoosh Mailer is included in the default template):

mix phx.new my_app
cd my_app

If the project was created with the --no-mailer flag, add to mix.exs:

defp deps do
  [
    # ... Phoenix dependencies ...
    {:swoosh, "~> 1.17"},
    {:gen_smtp, "~> 1.2"}
  ]
end
mix deps.get

and create the MyApp.Mailer module manually (see below).

2. Environment variables

Before mix phx.server, export variables (or set them in IDE Run Configuration):

MAILEXAM_LOGIN=YOUR_LOGIN
MAILEXAM_PASSWORD=YOUR_PASSWORD
MAILEXAM_PORT=587
MAIL_FROM=noreply@example.test

SMTP host: YOUR_LOGIN.mailexam.io.

Sender address

MAIL_FROM can be any test address — the message goes to Mailexam, not to a real recipient.

Alternative ports

MAILEXAM_PORT=587

In config: tls: :always.

MAILEXAM_PORT=2525

tls: :always, same as for 587.

MAILEXAM_PORT=25

In config: tls: :never.

3. Mailer configuration

lib/my_app/mailer.ex:

defmodule MyApp.Mailer do
  use Swoosh.Mailer, otp_app: :my_app
end

config/runtime.exs (fragment — applied at application startup):

import Config

login = System.get_env("MAILEXAM_LOGIN")
password = System.get_env("MAILEXAM_PASSWORD")
port = String.to_integer(System.get_env("MAILEXAM_PORT") || "587")

if login && password do
  config :my_app, MyApp.Mailer,
    adapter: Swoosh.Adapters.SMTP,
    relay: "#{login}.mailexam.io",
    username: login,
    password: password,
    port: port,
    tls: if(port in [587, 2525], do: :always, else: :never),
    auth: :always
end

4. Sending mail

lib/my_app/test_email.ex:

defmodule MyApp.TestEmail do
  import Swoosh.Email

  def deliver(to \\ "user@example.test", subject \\ "Phoenix + Mailexam", body \\ "Mailexam test from Phoenix") do
    from = System.get_env("MAIL_FROM") || "noreply@example.test"

    email =
      new()
      |> from(from)
      |> to(to)
      |> subject(subject)
      |> text_body(body)

    MyApp.Mailer.deliver(email)
  end
end

5. Phoenix route

lib/my_app_web/controllers/mail_controller.ex:

defmodule MyAppWeb.MailController do
  use MyAppWeb, :controller

  def create(conn, params) do
    to = params["to"] || "user@example.test"
    subject = params["subject"] || "Phoenix + Mailexam"
    body = params["body"] || "Mailexam test from Phoenix"

    case MyApp.TestEmail.deliver(to, subject, body) do
      {:ok, _} ->
        json(conn, %{status: "ok"})

      {:error, reason} ->
        conn
        |> put_status(:internal_server_error)
        |> json(%{error: inspect(reason)})
    end
  end
end

lib/my_app_web/router.ex:

scope "/", MyAppWeb do
  post "/mail/test", MailController, :create
end

Start and verify:

export MAILEXAM_LOGIN=YOUR_LOGIN
export MAILEXAM_PASSWORD=YOUR_PASSWORD
export MAILEXAM_PORT=587
export MAIL_FROM=noreply@example.test

mix phx.server
curl -X POST http://127.0.0.1:4000/mail/test \
  -H 'Content-Type: application/json' \
  -d '{"to":"user@example.test","subject":"Test","body":"Hello"}'

The message will appear in the Mailexam dashboard → your project → inbox.

6. Local development and CI

Environment Recommendation
local export variables or .env + direnv
CI secrets MAILEXAM_LOGIN, MAILEXAM_PASSWORD in GitLab CI/CD Variables

Example for .gitlab-ci.yml:

variables:
  MAILEXAM_LOGIN: $MAILEXAM_LOGIN
  MAILEXAM_PASSWORD: $MAILEXAM_PASSWORD
  MAILEXAM_PORT: "587"
  MAIL_FROM: "noreply@example.test"

After an integration test, verify delivery via the Mailexam API.

7. Common issues

TLS or authentication failed error

  • relay must be {login}.mailexam.io, username — the same login from the email.
  • Login and password are a pair from the email for one project.

Port 587

  • Requires tls: :always, not :never.

:smtp_response / timeout

  • Check that gen_smtp is in dependencies and variables are set before mix phx.server.

Message not in the dashboard

  • View the inbox of the same Mailexam project.
  • In dev enable logs: config :logger, level: :debug.

See also