โœ‰ Maily Developer Hub
โ† Dashboard

Standalone Python Async Client

maily-client is a zero-dependency (only httpx, loguru, pydantic) single-file client. Full async support, typed pydantic models, granular exception hierarchy, and high-level verification helpers.

Installation
# Preferred โ€” PyPI package:
pip install maily-client

# Alternative โ€” directly from GitHub:
pip install "maily-client @ git+https://github.com/stormsia/maily.git#subdirectory=client"
# Alternative โ€” single-file download (zero install):
curl -O https://raw.githubusercontent.com/stormsia/maily/main/client/client.py
Quickstart ยท Receive verification code in 1 line
import asyncio
from maily.client import Maily, WaitTimeoutError, AuthenticationError

async def main():
    async with Maily("http://127.0.0.1:8477", api_key="sk-...") as api:
        # 1. Create temporary mailbox automatically picking the best domain
        box = await api.create_temp_mailbox()
        print(f"Created mailbox: {box.address}")

        # 2. Wait for incoming verification email and extract 6-digit code
        try:
            code = await api.wait_for_code(box, timeout=60.0)
            print(f"Verification code: {code}")
        except WaitTimeoutError:
            print("Timed out waiting for code.")

asyncio.run(main())
Extract confirmation link
async with Maily("http://127.0.0.1:8477", api_key="sk-...") as api:
    box = await api.create_temp_mailbox(provider="tempmail.plus")

    # Wait for email and extract confirmation URL containing 'verify' or 'activate'
    link = await api.wait_for_link(
        box,
        url_contain=["verify", "confirm", "activate", "token"],
        timeout=60.0,
    )
    print(f"Activation link: {link}")
Real-time email stream (Async Generator)
async with Maily("http://127.0.0.1:8477") as api:
    box = await api.mailboxes.create(domain="mail.tm")
    print(f"Listening for incoming messages on {box.address}...")

    # Continuously yields incoming messages as they arrive
    async for msg in api.messages.iter_messages(box, poll_interval=2.0, timeout=120.0):
        print(f"New mail from {msg.from_address}: {msg.subject}")
        detail = await api.messages.get(box, msg.message_api_id)
        print("Body:", detail.text)
Manage scoped API Keys
async with Maily("http://127.0.0.1:8477", api_key="root_secret") as api:
    # Create key restricted to mail.tm only
    key = await api.keys.create(
        name="bot-worker",
        scope={"providers": ["mail.tm"], "parent_ids": [], "actions": ["read", "write"]},
    )
    print(f"Issued Key: {key.prefix}... Secret: {key.secret}")
Retention sweep & database maintenance
async with Maily("http://127.0.0.1:8477", api_key="root_secret") as api:
    # Run regular retention sweep (performs VACUUM / maintenance if interval is due)
    res = await api.admin.retention_run()
    print(f"Deleted: {res.mailboxes_deleted} mailboxes, {res.messages_deleted} messages")

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

Active Provider Adapters

Maily seamlessly aggregates public temporary-mail networks and private Gmail parent accounts into one unified REST API.

Provider Slug Kind Custom Username Custom Domain Password / PIN Raw RFC822 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 Parent account OAuth2 Supported Supported

Adding a New Provider?

See the developer guide in docs/ADDING_PROVIDERS.md for a complete step-by-step walkthrough and copy-pasteable boilerplate for adding any new email service with hermetic unit tests.

cURL & Authentication Cheat Sheet

Authenticate all requests with the X-API-Key HTTP header.

List available targets (domains)
curl -X GET "${window.location.origin}/v1/targets" \
  -H "X-API-Key: ${getSavedKey() || 'YOUR_API_KEY'}" \
  -H "Accept: application/json"
Create disposable mailbox
curl -X POST "${window.location.origin}/v1/mailboxes" \
  -H "X-API-Key: ${getSavedKey() || 'YOUR_API_KEY'}" \
  -H "Content-Type: application/json" \
  -d '{"provider": "mail.tm", "domain": "mail.tm"}'
Fetch messages for mailbox
curl -X GET "${window.location.origin}/v1/mailboxes/1/messages" \
  -H "X-API-Key: ${getSavedKey() || 'YOUR_API_KEY'}"
Inspect single message (text & HTML)
curl -X GET "${window.location.origin}/v1/mailboxes/1/messages/MESSAGE_ID" \
  -H "X-API-Key: ${getSavedKey() || 'YOUR_API_KEY'}"
Run retention sweep & database maintenance
curl -X POST "${window.location.origin}/v1/admin/retention/run?force_maintenance=true" \
  -H "X-API-Key: ${getSavedKey() || 'YOUR_API_KEY'}"