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):
If the project was created with the --no-mailer flag, add to mix.exs:
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¶
3. Mailer configuration¶
lib/my_app/mailer.ex:
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:
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
relaymust 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_smtpis in dependencies and variables are set beforemix 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¶
- Examples catalog
- Reference implementation (Phoenix)
- Django — similar SMTP configuration via config
- Mailexam API documentation
- Phoenix — Sending email
- Swoosh SMTP adapter