Skip to main content

maily - The Universal Temporary Email Gateway & Management Platform

✉️ maily

The Universal Temporary Email Gateway & REST API Platform

Taming the disposable email zoo (Mail.tm, TempMail, 1secmail alternatives) under a single high-performance REST API, modern async Python SDK, and dark-mode web console.


⚡ Universal Temp Mail API to Rule the Disposable Email Zoo: Stop wrestling with 8 incompatible temp-mail APIs, daily domain blacklists, and fragile regexes. Maily acts as a resilient, drop-in 1secmail alternative aggregating Mail.tm, Tempmail Plus, Temp-Mail.io, and 5+ disposable email providers into one unified REST gateway with 1-line automatic OTP verification code extraction for Playwright, Pytest, and QA bots.

🇷🇺 Универсальный шлюз и REST API временной почты: объединяем зоопарк temp-mail сервисов (надёжная замена 1secmail, Mail.tm, TempMail) в едином быстром REST API с удобным тёмным веб-интерфейсом и мгновенным извлечением проверочных OTP кодов.


CI Pipeline CodeQL Security Security Audit Gitleaks Scan Code Coverage Docker GHCR PyPI server PyPI client API Docs Python License: MIT

📖 Interactive Docs & Swagger • 🚀 Server Package (PyPI) • 📦 Client SDK (PyPI) • 🐳 Docker GHCR • 🌐 Live Provider Health • ⚡ Quick Start • 🧪 Test Automation Recipes


🦁 Why Maily? Taming the Disposable Email Zoo

Integrating disposable email into automated tests, QA pipelines, or bots usually means dealing with an unmaintainable nightmare:

  • 💥 8 incompatible, brittle APIs — Each provider has custom headers, obscure JSON shapes, non-standard timestamps, or missing MIME source.
  • 🛑 Random downtime & domain blacklists — Upstream domains get blocklisted daily, breaking your E2E test suites with zero warning.
  • 🧩 Complex regex parsing — Writing and maintaining brittle regexes to fish 4–8 digit OTP codes and activation links out of raw HTML.
  • 🔓 Zero security & isolation — No access controls, no credential encryption, no audit log, and no retention sweep.

Maily solves this once and for all. It acts as a resilient, high-availability abstraction gateway over the entire temp-mail ecosystem. Switch or rotate providers dynamically with a single parameter, automatically extract verification codes, and control everything from a sleek dark dashboard or async Python SDK.

Capability Fragmented Provider Zoo ❌ Maily Universal Gateway ⚡
API Uniformity 8+ different endpoints, schemas & authentication rules Single normalized REST API & Python SDK
Domain Reliability Single point of failure; breaks when domain is blocked 40+ rotating domains across 8 provider fleets
OTP Code Extraction Manual HTML scraping, regex writing, and polling loops await api.wait_for_code(box) (instant 1-line extraction)
Activation Links Hardcoded regex URL patterns await api.wait_for_link(box) with auto-scoring
Execution Engines Custom HTTP requests with unhandled 429/502 retries Native Async (Maily) + Sync facade (SyncMaily)
Observability Blind execution; logs scattered everywhere Dark-mode web console with live telemetry & charts
Security & Privacy Public endpoints with zero key control Multi-tenant scoped API keys & Fernet-encrypted credentials
State Maintenance Orphaned mailboxes & bloated disks Background retention sweep + zero-downtime VACUUM

🏗️ Architecture & Data Flow

Maily Architecture & Data Flow Infographic

flowchart LR
    subgraph Clients["1. Clients & Test Suites"]
        direction TB
        pytest["Pytest Automation"]
        playwright["Playwright / Selenium"]
        bot["QA Bots & Scrapers"]
        sdk["maily-client (Async / Sync)"]
    end

    subgraph Gateway["2. Maily Unified Engine"]
        direction TB
        fastapi["FastAPI High-Speed Core"]
        extractor["Magic OTP & Link Extractor"]
        rbac["Scoped RBAC & Fernet Vault"]
        cache["Domain Cache & Auto-Failover"]
        retention["Retention Sweeper & SQLite WAL"]
        ui["Dark-Mode Admin Dashboard"]
    end

    subgraph Zoo["3. The Temp Mail Zoo"]
        direction TB
        p1["Mail.tm"]
        p2["TempMail.Plus"]
        p3["Temp-Mail.io"]
        p4["NoopMail.org"]
        p5["AnonymMail.net"]
        p6["DispoEmail.org"]
        p7["Temp.tf"]
        p8["Gmail OAuth2 + Aliases"]
    end

    Clients -->|Single REST / SDK Call| Gateway
    Gateway -->|Unified Adapter Engine| Zoo

✨ Features at a Glance

  • 8 Integrated Providers Under One Roof — Aggregates public temporary-mail networks and private Gmail accounts:
    • mail.tm — High reliability, custom usernames, passwords, full MIME source
    • tempmail.plus — Custom usernames, PIN protection, domains, MIME source
    • temp-mail.io — Disposable web mailboxes with automatic CORS tokens
    • noopmail.org — Domain rotation and raw source inspection
    • anonymmail.net — Session & CSRF-managed disposable mail
    • dispoemail.org — Astro-session based disposable mail
    • temp.tf — Real provider aliases on Outlook, Hotmail, Gmail, and high.edu.pl with plus/dot syntax
    • gmail — OAuth2 integration with unlimited username+alias@gmail.com mailboxes
  • ⚡ Magic Verification Extraction — Wait for an incoming email and automatically extract 4–8 digit verification codes (e.g. 849201) or confirmation action links with a single async call.
  • 🐍 Async Python Client (maily-client) — Zero-heavy-dependency standalone client (httpx, pydantic, loguru) with async context managers, async iterators, typed pydantic models, and granular exceptions.
  • 📡 Real-Time Email Streaming — Stream incoming messages via async for message in api.messages.iter_messages(box): ....
  • 🖥️ Cyberpunk Dark Web Dashboard — Modern dark-mode UI with live charts, message preview with verification highlights, auto-refresh polling, and an integrated Swagger / API documentation explorer at /docs.
  • 🔑 Scoped API Keys & Multi-Tenancy — Root keys and granular issued keys with provider/action/parent restrictions and custom TTL cleanup rules.
  • 🧹 Automatic Retention & DB Maintenance — Configurable background worker sweeps expired mailboxes and messages based on TTL policies, paired with automatic throttled database maintenance (WAL truncate, VACUUM, REINDEX, ANALYZE, PRAGMA optimize, quick_check) to defragment storage without downtime.
  • 🔄 Domain Cache & Fallback — Periodic background cache of provider domains with instant refresh and auto-failover.
  • 🐳 Docker-Ready in 10 Seconds — Hermetic multi-stage Docker build with SQLite volume persistence.

🌐 Supported Providers & Capabilities

Provider Target Kind Custom Username Custom Domain Passwords / PIN Raw Source Read Tracking
mail.tm domain ✅ Supported ✅ Supported ✅ Supported ✅ Supported ✅ Supported
tempmail.plus domain ✅ Supported ✅ Supported ✅ PIN Code ✅ Supported ✅ Supported
temp-mail.io domain ✅ Supported ✅ Supported ❌ No ✅ Supported ⚪ No-op
noopmail.org domain ✅ Supported ✅ Supported ❌ No ✅ Supported ⚪ No-op
anonymmail.net domain ✅ Supported ✅ Supported ❌ No ✅ Supported ⚪ No-op
dispoemail.org domain ✅ Supported ✅ Supported ❌ No ✅ Supported ⚪ No-op
temp.tf domain ✅ Supported ✅ Supported ❌ No ✅ Supported ⚪ No-op
gmail parent ✅ +alias ❌ Own Account ❌ OAuth2 ✅ Supported ✅ Supported

💡 Extending Providers: Want to add your own provider? Check out the comprehensive guide for developers and AI agents in docs/ADDING_PROVIDERS.md.

🌐 Live Provider Operational Status

Last Verified: 2026-11-03 00:28 UTC | Overall Health: 🟡 Degraded Performance

Provider Slug Targets API Health E2E Delivery Latency Status
Mail.tm mail.tm 1 🟢 PASS 🟢 4.3s 1.21s 🟢 Operational
TempMail Plus tempmail.plus 8 🟢 PASS 🟢 5.6s 1.24s 🟢 Operational
TempMail.io temp-mail.io 6 🟢 PASS 🟢 3.5s 0.75s 🟢 Operational
Temp.tf temp.tf 4 🟢 PASS 🔴 Failed 0.67s 🔴 Delivery Outage
AnonymMail.net anonymmail.net 6 🟢 PASS 🔴 Failed 33.01s 🔴 Delivery Outage
DispoEmail.org dispoemail.org 4 🟢 PASS 🟢 3.6s 0.66s 🟢 Operational
NoopMail.org noopmail.org 16 🟢 PASS 🟢 3.6s 25.09s 🟢 Operational

Automated health checks run hourly via GitHub Actions.


🖥️ Sleek Web Dashboard Tour

Maily includes a high-performance dark-mode web console served directly at http://127.0.0.1:8477/. Built for developers, QA engineers, and automation ops teams who need effortless visual control over their disposable email infrastructure.


Maily Interactive Web Console - Animated Tour Carousel
🎬 Live Dashboard Walkthrough: Auto-playing carousel cycling through all 6 admin console workstations (346 KB payload). Click to expand high-resolution inspection below.



🚀 Quick Start

Run Maily via official pre-built Docker containers, Docker Compose, or develop locally from source.

Option A — Docker (Pre-built Image, No Git Clone Required)

The fastest and recommended way to run maily in production without cloning the repository or building from source:

1. In One Command (docker run)

docker run -d \
  --name maily \
  -p 8477:8477 \
  -e MAILY_API_KEY=your_secret_api_key \
  -v maily_data:/data \
  --restart unless-stopped \
  ghcr.io/stormsia/maily:latest

2. Using Docker Compose

Download only the production Compose configuration:

# Linux / macOS (curl)
curl -O https://raw.githubusercontent.com/stormsia/maily/main/docker-compose.prod.yml
docker compose -f docker-compose.prod.yml up -d

# Windows (PowerShell)
Invoke-WebRequest -Uri https://raw.githubusercontent.com/stormsia/maily/main/docker-compose.prod.yml -OutFile docker-compose.prod.yml
docker compose -f docker-compose.prod.yml up -d

Updating the Pre-built Image

# If using Docker Compose:
docker compose -f docker-compose.prod.yml pull
docker compose -f docker-compose.prod.yml up -d

# If using docker run:
docker pull ghcr.io/stormsia/maily:latest
docker stop maily && docker rm maily
docker run -d --name maily -p 8477:8477 -e MAILY_API_KEY=your_secret_api_key -v maily_data:/data --restart unless-stopped ghcr.io/stormsia/maily:latest

Option B — Build from Source / Development

1. Docker Compose (Local Build)

git clone https://github.com/stormsia/maily.git && cd maily
cp .env.example .env        # adjust if needed
docker compose up -d --build

To update when building from source:

git pull
docker compose up -d --build

2. Local Python (Python 3.13+)

pip install maily-server
maily
From Git Source (Development)
git clone https://github.com/stormsia/maily.git && cd maily
python -m venv .venv
# Windows:
.venv\Scripts\activate
# Linux / macOS:
source .venv/bin/activate

pip install -e ".[dev]"
maily

Development server with auto-reload:

uvicorn maily.app.main:create_app --factory --reload --port 8477

🐍 Standalone Python Client SDK (maily-client)

The repository includes a dedicated, self-contained standalone Python client package (maily-client) requiring only httpx, pydantic, and loguru. It supports both high-concurrency async/await (Maily) and a synchronous facade (SyncMaily).

📖 Full Documentation: See CLIENT_GUIDE.md and maily-client README for comprehensive recipes (Pytest fixtures, Playwright/Selenium automation, streaming, and retry policies).

Installation

Preferred — PyPI package:

pip install maily-client

Alternative options:

# Directly from GitHub repository:
pip install "maily-client @ git+https://github.com/stormsia/maily.git#subdirectory=client"

# Or download the zero-dependency single-file client directly:
curl -O https://raw.githubusercontent.com/stormsia/maily/main/client/maily_client.py

⚠️ Important: Attribute Access vs Dictionary Key Access

In maily-client, native dot/attribute access is supported ONLY on Pydantic models and specifically ExtractedConfirmation (which implements Mapping and supports dual access: e.g. res.subject, res.confirmation_code as well as res["confirmation_link"]).

All other client methods returning standard Python dictionaries (such as await api.config.get()) DO NOT support attribute/dot access. You MUST use standard dictionary key indexing (dict["key"]), never dot access (dict.key).

1-Line Mailbox & Verification Code Extraction

import asyncio

# Preferred when using maily-client SDK:
from maily_client import Maily, WaitTimeoutError
# (Or if using the maily-server package directly: from maily import Maily, WaitTimeoutError)


async def main():
    async with Maily("http://127.0.0.1:8477", api_key="your_secret_api_key") as api:
        # Create a disposable mailbox with automatic domain selection
        box = await api.create_temp_mailbox()
        print(f"Disposable email: {box.address}")

        # Send an email to box.address, then wait for the code:
        try:
            code = await api.wait_for_code(box, timeout=60.0)
            print(f"Received verification code: {code}")
        except WaitTimeoutError:
            print("Timed out waiting for email.")


asyncio.run(main())

Confirmation Extraction (ExtractedConfirmation Dual Access)

async with Maily("http://127.0.0.1:8477") as api:
    box = await api.create_temp_mailbox()

    # Wait for email and extract both verification code and activation link
    res = await api.wait_for_confirmation_email(box, digit_code_mask=r"\b(\d{6})\b")
    if res is not None:
        # 1. Attribute / dot access:
        print(f"Subject: {res.subject}")
        print(f"Code: {res.confirmation_code}")

        # 2. Key mapping access:
        print(f"Link: {res['confirmation_link']}")
        print(f"Code: {res['confirmation_code']}")

Synchronous Client (SyncMaily)

# Standalone client:
from maily_client import SyncMaily
# Or via server package: from maily import SyncMaily

with SyncMaily("http://127.0.0.1:8477", api_key="your_secret_api_key") as api:
    box = api.create_temp_mailbox()
    code = api.wait_for_code(box, timeout=45.0)
    print(f"Received code synchronously: {code}")
async with Maily("http://127.0.0.1:8477") as api:
    box = await api.create_temp_mailbox(provider="tempmail.plus")
    print(f"Address: {box.address}")

    # Automatically extracts URLs containing 'confirm', 'verify', or 'activate'
    link = await api.wait_for_link(box, timeout=90.0)
    print(f"Confirmation URL: {link}")

Real-Time Email Streaming (Async Iterator)

async with Maily("http://127.0.0.1:8477") as api:
    box = await api.mailboxes.create(domain="mail.tm")

    # Continuously yields new messages as they arrive
    async for msg in api.messages.iter_messages(box, poll_interval=2.0, timeout=120.0):
        print(f"Incoming: {msg.subject} from {msg.from_address}")
        detail = await api.messages.get(box, msg.message_api_id)
        print("Body text:\n", detail.text)

Granular Exception Handling

All API errors inherit from ApiError, which inherits from ClientError:

from maily_client import (
    AuthenticationError,  # 401: Invalid API key
    ForbiddenError,  # 403: Scope denied
    NotFoundError,  # 404: Mailbox or message missing
    ValidationError,  # 422 / 400: Bad params
    RateLimitError,  # 429: Rate limited
    UpstreamProviderError,  # 502/504: Provider downtime
    WaitTimeoutError,  # Timeout waiting for email/code
)

try:
    detail = await api.messages.get(box, "unknown_id")
except NotFoundError:
    print("Message not found!")
except AuthenticationError:
    print("Check your API key!")

Scoped API Key Management

async with Maily("http://127.0.0.1:8477", api_key="root_secret") as api:
    # Create key restricted to mail.tm only
    new_key = await api.keys.create(
        name="bot-worker",
        scope={"providers": ["mail.tm"], "parent_ids": [], "actions": ["read", "write"]},
    )
    print(f"Key Prefix: {new_key.prefix} | Secret: {new_key.secret}")

Retention & Database Maintenance

async with Maily("http://127.0.0.1:8477", api_key="root_secret") as api:
    # Run regular retention sweep (triggers DB maintenance if interval has elapsed)
    res = await api.admin.retention_run()
    print(f"Deleted: {res.mailboxes_deleted} boxes, {res.messages_deleted} messages")

    # Or force immediate full database maintenance (VACUUM, REINDEX, ANALYZE):
    res = await api.admin.retention_run(force_maintenance=True)

🧪 E2E Test Automation Recipes (Pytest, Playwright, Selenium)

Maily is the ideal engine for automated testing and CI/CD pipelines. Here are battle-tested recipes ready to copy-paste into your test suite:

Recipe 1: Pytest Async Fixture (Automated Signup Verification)

import pytest
from maily_client import Maily, WaitTimeoutError


@pytest.fixture
async def temp_inbox():
    """Provides a fresh temporary inbox for each test, cleaned up afterwards."""
    async with Maily("http://127.0.0.1:8477", api_key="your_secret_api_key") as api:
        box = await api.create_temp_mailbox(provider="tempmail.plus")
        try:
            yield api, box
        finally:
            await api.mailboxes.delete(box)


@pytest.mark.asyncio
async def test_user_signup_with_email_otp(temp_inbox):
    api, box = temp_inbox

    # 1. Trigger registration inside your app / microservice
    # response = await test_client.post("/api/register", json={"email": box.address})
    # assert response.status_code == 201

    # 2. Wait for incoming verification code (timeout in 30s)
    code = await api.wait_for_code(box, timeout=30.0)
    assert len(code) in (4, 6, 8)

    # 3. Submit verification code back to your service
    # verify_resp = await test_client.post("/api/verify-otp", json={"code": code})
    # assert verify_resp.json()["verified"] is True

Recipe 2: Playwright Web Automation (Browser OTP Form Fill)

import asyncio
from maily_client import Maily
from playwright.async_api import async_playwright


async def run_e2e_verification():
    async with (
        Maily("http://127.0.0.1:8477", api_key="your_secret_api_key") as api,
        async_playwright() as p,
    ):
        # 1. Create a disposable email address
        box = await api.create_temp_mailbox()

        # 2. Automate browser registration flow
        browser = await p.chromium.launch(headless=True)
        page = await browser.new_page()
        await page.goto("https://example.com/signup")
        await page.fill('input[name="email"]', box.address)
        await page.click('button[type="submit"]')

        # 3. Wait for email code automatically via Maily
        code = await api.wait_for_code(box, timeout=45.0)

        # 4. Fill OTP in the browser form and assert success
        await page.fill('input[name="verification_code"]', code)
        await page.click("button#confirm")
        await page.wait_for_selector(".dashboard-welcome")
        await browser.close()


asyncio.run(run_e2e_verification())

🛡️ Architecture & CI/CD Pipeline

The project implements a state-of-the-art continuous integration and delivery architecture with multi-layer security scanning:

flowchart LR
    subgraph CI["Fast Feedback CI (< 90s)"]
        lint["Ruff + HTMLHint"]
        alembic["Alembic Migrations Check"]
        deptry["Deptry Clean Dependencies"]
        mypy["Mypy Strict Type Check"]
        pytest["Pytest Matrix (3.13-3.15) + Coverage >= 80%"]
        smoke["Docker Runtime Smoke Test"]
    end

    subgraph Security["Security & SAST"]
        codeql["CodeQL SAST (Python + JS)"]
        gitleaks["Gitleaks Secret Scanning"]
        pipaudit["pip-audit PyPA Advisory CVE"]
        trivy["Trivy Container & OS Scan"]
    end

    subgraph CD["Release & Distribution"]
        pypi["PyPI Trusted Publisher (OIDC)"]
        ghcr["Multi-Arch GHCR (amd64/arm64)"]
        sbom["SPDX Signed SBOM"]
        pages["GitHub Pages Interactive Docs"]
    end

    CI --> Security --> CD

Security & Compliance Controls

  1. GitHub CodeQL Analysis — Deep semantic static application security testing (SAST) detecting SQL injection, path traversal, and SSRF.
  2. Gitleaks Secret Scanning — Pre-merge blocking of accidental token, key, or credential commits (.gitleaks.toml configured).
  3. Trivy Container Scanner — Full CVE inspection of Debian Bookworm OS packages and Python wheels exported directly to the GitHub Security tab (SARIF).
  4. pip-audit — Automated vulnerability audit against the PyPA Advisory Database.
  5. Hermetic Test Suite — 480+ tests passing hermetically with 80%+ code coverage across Python 3.13, 3.14, and 3.15.

⚙️ Configuration Reference

Copy .env.example to .env and customize:

Variable Default Description
MAILY_HOST 127.0.0.1 Bind address (0.0.0.0 in Docker)
MAILY_PORT 8477 HTTP port
MAILY_API_KEY (empty) Root master key. If empty on loopback, open root access is allowed. Non-loopback requires a key.
MAILY_DATABASE_URL sqlite+aiosqlite:///mailtm.db SQLite database URI
MAILY_SECRET_KEY (auto-generated) Fernet encryption key used to protect credentials
MAILY_PROXY (empty) Optional HTTP/SOCKS5 proxy for upstream provider requests
MAILY_RETENTION_INTERVAL_SECONDS 60 Background retention sweep frequency
MAILY_DB_MAINTENANCE_ENABLED true Enable periodic database maintenance during retention
MAILY_DB_MAINTENANCE_INTERVAL_MINUTES 60 Minimum interval between database maintenance runs (in minutes)
MAILY_SQLITE_BUSY_TIMEOUT_MS 60000 SQLite lock wait timeout in ms to prevent request drops during maintenance
MAILY_DOMAIN_CACHE_INTERVAL_SECONDS 1800 Background domain refresh frequency
MAILY_GMAIL_CLIENT_ID (empty) Google OAuth2 Client ID
MAILY_GMAIL_CLIENT_SECRET (empty) Google OAuth2 Client Secret
MAILY_TEMP_TF_GMAIL_DOT true Enable dot-aliased Gmail addresses for temp.tf (user.name@gmail.com)
MAILY_TEMP_TF_GMAIL_PLUS true Enable plus-aliased Gmail addresses for temp.tf (username+tag@gmail.com)

🧪 Testing & Code Quality

The repository has 100% passing tests and strict typing and linting checks:

# Run full test suite across all workers
python -m pytest

# Run ruff linter & formatter checks
uv run ruff check src tests client scripts

# Run mypy static type checking
uv run mypy src client scripts

# Check Alembic migrations consistency
uv run alembic upgrade head
uv run alembic check

# Verify clean pyproject.toml dependencies
uvx deptry src

# Verify standalone client mirror integrity
python scripts/build_client.py --check

🔍 Search Discovery & Keywords Reference

Maily is engineered as the definitive open-source answer to all disposable email, temporary mailbox, and test automation search queries across Google, GitHub, and PyPI:

High-Intent Search Queries & Coverage

Search Category Problem Maily Solves Top Ranked Query Terms
Multi-Provider Temp Mail API Unifies 8+ public & private temp mail services under one normalized REST API temp mail api, disposable email api, temporary email api, fake mail api, disposable mailbox rest api, burner email api, multi-provider temp mail
Python Client / SDK Dedicated async & sync Python SDK with typed models and zero heavy dependencies temp mail python, temporary email python client, disposable email sdk, mailtm python, maily-client, python temp mail library
Alternative to Flaky Services Resilient self-hosted replacement with failover and domain rotation 1secmail alternative, mail.tm alternative, guerrilla mail alternative, tempmail plus api, fake email generator api, throwaway email service
Automated Testing & QA 1-line OTP verification code extraction and activation link scoring playwright temp mail, pytest disposable email fixture, selenium email verification, e2e email testing otp, wait for verification code email python
Self-Hosted Infrastructure Docker-ready, SQLite WAL, Fernet encrypted secrets, scoped RBAC tokens self hosted temp mail, open source temporary email server, docker disposable email, fastapi temp mail gateway, on premise disposable email
Поиск на русском языке (CIS SEO) Единый шлюз и API временной почты для тестов и ботов временная почта api, апи временной почты, одноразовая почта python, прием кодов подтверждения email, playwright временная почта, генератор одноразовой почты api
💡 Frequently Asked Questions (FAQ) & Search Index

How does Maily differ from single-provider libraries like mailtm or tempmail?

Single-provider libraries break whenever that specific upstream provider encounters downtime, changes its schema, or gets added to spam blocklists. Maily abstracts the entire disposable email ecosystem into a resilient gateway: you get a single consistent API, 40+ rotating domains across 8 provider networks, automatic domain fallback, and standardized OTP extraction. If one provider is down, switch to another with a single parameter (provider="tempmail.plus").

How fast is OTP verification code extraction in automated tests?

Incoming emails are processed within sub-second latency of arrival upstream. With await api.wait_for_code(box, timeout=30.0), Maily continuously polls and extracts 4–8 digit verification codes (e.g. 849201) or confirmation action links, returning cleanly as soon as the email hits the server.

How does Maily prevent domain blacklisting in E2E tests?

Many SaaS sign-up forms block known disposable email domains like @mailtm.com. Maily solves this by maintaining a live pool of 40+ rotating domains across multiple providers (including obscure domains and real Gmail alias domains username+tag@gmail.com via OAuth2).

Can I run Maily completely self-hosted with Docker?

Yes! Maily is packaged as an optimized multi-stage Docker container (ghcr.io/stormsia/maily:latest). Run it with a single command:

docker run -d -p 8477:8477 -v maily_data:/data ghcr.io/stormsia/maily:latest

It stores state in embedded SQLite with Write-Ahead Logging (WAL) and automatic defragmentation (VACUUM/REINDEX), requiring zero external databases or Redis caches.

Can I use my own domain or Gmail account?

Yes! Maily supports Gmail via OAuth2 with infinite username+alias@gmail.com addresses, as well as providers with custom domains (mail.tm, tempmail.plus, temp.tf).

Как Maily помогает в автотестах Playwright и Pytest?

Вместо ручного парсинга HTML и написания хрупких регулярных выражений, клиент maily-client предоставляет готовые высокоуровневые асинхронные методы: create_temp_mailbox() создает ящик за 0.1 секунды, а wait_for_code(box) ждет письмо и возвращает чистый проверочный код для подстановки в page.fill().

Как Maily объединяет зоопарк temp-mail сервисов?

Каждый провайдер временной почты (Mail.tm, TempMail.Plus, NoopMail, DispoEmail и др.) имеет свои уникальные заголовки, форматы дат и ограничения. Maily нормализует ответы всех сервисов в единый формат Mailbox и MessageDetail, автоматически кэширует доступные домены и управляет жизненным циклом ящиков.


📄 License

MIT © stormsia

Metadata

Release files for maily-server 0.8.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for maily-server 0.8.0
File Size Uploaded Provenance Actions
maily_server-0.8.0.tar.gz 3.3 MB With provenance Details for maily_server-0.8.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for maily-server 0.8.0
File Interpreter ABI Platform Actions
maily_server-0.8.0-py3-none-any.whl Python 3 none any Details for maily_server-0.8.0-py3-none-any.whl

Total release size: 3.5 MB

Release files / maily_server-0.8.0.tar.gz

Download URL maily_server-0.8.0.tar.gz
Size 3.3 MB
Tags Source
SHA-256 checksum
How to use checksums
7d410a5cb1481d838c4a1dd276cd994c052da19bc85f8e20bfca5a5ebfdfb76a
BLAKE2b-256 checksum
How to use checksums
b30724aded246a7838f6f1b040e03c9bd33d422610c9c93fb9b61b7b073d4d37
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.

Transparency log

Release files / maily_server-0.8.0-py3-none-any.whl

Download URL maily_server-0.8.0-py3-none-any.whl
Size 223.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
456dfcc3b6621c3e04c9c4bb763768d196d48f597875e44026729f75428867bc
BLAKE2b-256 checksum
How to use checksums
92245be4ecb35e029c28c6def62448bf540749bcf41db02489f71941a198cbab
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.

Transparency log

Security for maily-server 0.8.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for maily_server-0.8.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page