CtrlK
BlogDocsLog inGet started
Tessl Logo

testland/mailpit-testing

Configures and runs Mailpit - modern dev-mailbox server for SMTP testing with built-in REST API for assertions; default SMTP `1025` + Web UI `8025`; ships single static binary or multi-architecture Docker images; features Chaos mode (configurable SMTP errors for resilience testing), message tagging (manual + auto via filters and plus-addressing), search filters. Use when the user develops email-sending code locally / in CI and needs SMTP capture with programmatic test assertions, or when migrating from MailHog (which Mailpit succeeds).

74

Quality

93%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Medium

Suggest reviewing before use

Overview
Quality
Evals
Security
Files

SKILL.md

name:
mailpit-testing
description:
Configures and runs Mailpit - modern dev-mailbox server for SMTP testing with built-in REST API for assertions; default SMTP `1025` + Web UI `8025`; ships single static binary or multi-architecture Docker images; features Chaos mode (configurable SMTP errors for resilience testing), message tagging (manual + auto via filters and plus-addressing), search filters. Use when the user develops email-sending code locally / in CI and needs SMTP capture with programmatic test assertions, or when migrating from MailHog (which Mailpit succeeds).

mailpit-testing

Overview

Per mailpit.axllent.org/docs/:

"Mailpit is packed full of features for developers wanting to test SMTP and emails. It acts as an SMTP server, provides a modern web interface to view & test intercepted emails."

Per mp-docs the differentiated features:

  • "Chaos feature to enable configurable SMTP errors for testing application resilience."
  • "Message tagging, including manual tagging or automated tagging using filtering and 'plus addressing'."
  • "A REST API for integration testing"

Mailpit succeeded MailHog as the de facto OSS dev mailbox in the mid-2020s; new projects start with Mailpit by default.

When to use

  • The repo has email-sending code (transactional emails, password reset, notifications) that needs local + CI testing.
  • Tests assert on captured email content (subject, body, headers, attachments).
  • The team needs Chaos mode to test app resilience to SMTP errors (bounce, timeout, rate-limit).
  • Migrating from MailHog (Mailpit is API-compatible at the SMTP layer + has a richer REST API).

Step 1 - Install

Per github.com/axllent/mailpit:

# macOS
brew install mailpit

# Linux + macOS via install script
sudo sh < <(curl -sL https://raw.githubusercontent.com/axllent/mailpit/develop/install.sh)

# Custom install path
sudo INSTALL_PATH=/usr/bin sh < <(curl -sL https://raw.githubusercontent.com/axllent/mailpit/develop/install.sh)

Docker is the recommended path for CI; consult mp-gh for current Docker pull commands.

Step 2 - Start

Per mp-gh:

"The Mailpit web UI listens by default on http://0.0.0.0:8025 and the SMTP port on 0.0.0.0:1025."

Foreground:

mailpit
# Web UI: http://localhost:8025
# SMTP:   localhost:1025

As a background service on macOS:

brew services start mailpit

Discover all options:

mailpit -h

Step 3 - Configure your app's SMTP

Point the application's SMTP config at Mailpit:

# example: Rails action_mailer config
smtp_settings:
  address: localhost
  port: 1025
  domain: localhost
  authentication: nil   # Mailpit accepts unauthenticated SMTP by default

Equivalent envs work for Django (EMAIL_HOST=localhost, EMAIL_PORT=1025), Spring (spring.mail.host=localhost, spring.mail.port=1025), Node nodemailer, etc.

Step 4 - Assert via REST API

Per mp-docs Mailpit ships a "REST API for integration testing." The canonical endpoints (consult mp-docs for current paths per release) follow this shape:

import requests

BASE = "http://localhost:8025"

def test_password_reset_sends_email():
    # 1. Clear inbox before the test
    requests.delete(f"{BASE}/api/v1/messages")

    # 2. Trigger the email send
    trigger_password_reset("alice@example.com")

    # 3. Poll until the email lands (typical: <1s)
    msg = poll_for_message(BASE, to="alice@example.com", timeout=5)

    # 4. Assert
    assert msg["Subject"] == "Reset your password"
    assert "/reset?token=" in msg["Text"]
    assert msg["To"][0]["Address"] == "alice@example.com"
def poll_for_message(base, to, timeout):
    import time
    deadline = time.time() + timeout
    while time.time() < deadline:
        response = requests.get(f"{base}/api/v1/search", params={"query": f"to:{to}"})
        messages = response.json().get("messages", [])
        if messages:
            return requests.get(f"{base}/api/v1/message/{messages[0]['ID']}").json()
        time.sleep(0.1)
    raise AssertionError(f"No email to {to} within {timeout}s")

The exact endpoint paths may evolve - always check the live API schema at http://localhost:8025/api/v1/ (Mailpit ships an OpenAPI schema for self-introspection).

Step 5 - Chaos mode

Per mp-docs: "Chaos feature to enable configurable SMTP errors for testing application resilience."

Use cases for app-level resilience testing:

  • Verify retry-with-backoff works when SMTP returns 421 / 451
  • Verify dead-letter handling for permanent failures (5xx)
  • Verify rate-limit handling (server returns 421 4.7.0)

Per mp-docs, Chaos is configurable per-recipient or globally; consult the live docs for current Chaos API shape.

Step 6 - Tagging + plus-addressing

Per mp-docs: "automated tagging using filtering and 'plus addressing'."

Pattern for test-isolation: each test sends to alice+test-${test_id}@example.com; Mailpit auto-tags by the +test-... suffix; tests filter by tag to isolate their email batch from concurrent test runs:

import uuid
test_id = uuid.uuid4().hex[:8]
to_addr = f"alice+test-{test_id}@example.com"
trigger_email(to_addr)
msg = requests.get(
    f"{BASE}/api/v1/search",
    params={"query": f'tag:"test-{test_id}"'},
).json()["messages"][0]

Step 7 - CI integration

services:
  mailpit:
    image: axllent/mailpit:latest
    ports: [1025:1025, 8025:8025]

steps:
  - run: pytest tests/integration/email/ -v
    env:
      SMTP_HOST: localhost
      SMTP_PORT: 1025

Anti-patterns

Anti-patternWhy it failsFix
Skip per-test inbox clearStale messages cause false-positivesDELETE /api/v1/messages in setup (Step 4)
Assume Mailpit handles authenticated SMTPDefault config is unauthenticated; auth tests need explicit configConfigure --smtp-auth-allow-insecure or proper auth config
Hardcode message IDs in testsIDs are random per send; tests failSearch by recipient/subject (Step 4)
Skip polling; assert immediatelySub-second SMTP delivery isn't guaranteedPoll with timeout (Step 4)
Test only happy pathMisses retry/dead-letter scenariosUse Chaos mode (Step 5)

Limitations

  • Mailpit does NOT actually deliver email - it only captures. For end-to-end deliverability tests, use a real-mail-with-test-domain service (Mailtrap, Mailosaur).
  • Some advanced SMTP features (DKIM signing assertion, SPF lookup) are not Mailpit's focus; verify via separate tooling.
  • The REST API surface evolves between Mailpit releases; pin a specific version in CI (axllent/mailpit:v1.20.0 not :latest).

References

  • mp-docs - official documentation
  • mp-gh - repository, install commands, ports
  • mailpit.axllent.org/docs/api-v1/ - REST API reference
  • mailhog-testing - predecessor; use Mailpit for new work
  • email-flow-test-author - build-an-X for the full email-sending workflow

SKILL.md

tile.json