GreenMail

Local SMTP+IMAP email server for Elixir dev/test environments. Wraps GreenMail — catches all outbound email at the SMTP level. No emails leave your machine. Ever.

Why not Swoosh.Adapters.Local?

Because it only catches emails sent through Swoosh. If your app talks SMTP directly (a SmtpClient, a background mailer, a third-party library), Swoosh.Local never sees those messages. GreenMail catches everything — it's a real SMTP server listening on localhost.

Setup

1. Add dependency

# mix.exs
defp deps do
[
{:greenmail, "~> 0.1", only: :dev}
]
end

2. Install the JAR

mix greenmail.install

Downloads greenmail-standalone.jar to ~/.greenmail/. One download, shared by all projects.

Requires: Java 17+ (brew install openjdk on macOS)

3. Add to supervision tree (dev only)

# application.ex
def start(_type, _args) do
children = [
# ... your children ...
] ++ greenmail_children()
opts = [strategy: :one_for_one, name: MyApp.Supervisor]
Supervisor.start_link(children, opts)
end
defp greenmail_children do
if Application.get_env(:my_app, :greenmail, false) do
[{GreenMail.Server, [supervisor: MyApp.Supervisor]}]
else
[]
end
end
# config/dev.exs
config :my_app, greenmail: true

4. Point SMTP at GreenMail

Any SMTP config pointing at localhost:3025 will be caught. For IMAP ingestion, use localhost:3143.

Auth is disabled — any username/password works and auto-provisions a mailbox for that address.

API

GreenMail.running?() # => true
GreenMail.status() # => {:ok, %{smtp_port: 3025, imap_port: 3143, os_pid: 12345, ...}}
GreenMail.stop() # Stop server, free ports
GreenMail.start() # Restart after stop
GreenMail.restart() # Flush all mailboxes

Ports

ProtocolPort
SMTP3025
IMAP3143

How it works

Reading caught emails

Use any IMAP client. From Elixir, you can use :gen_smtp or Mail:

# The email sent to alice@example.com is in that address's IMAP inbox
# Login: alice@example.com / any-password
# Host: localhost, Port: 3143, SSL: off

Or just use a mail client (Thunderbird, etc.) pointed at localhost:3143.

License

MIT