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.
# 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
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())
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}")
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)
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}")
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)
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 |
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.
Authenticate all requests with the X-API-Key HTTP header.
curl -X GET "${window.location.origin}/v1/targets" \
-H "X-API-Key: ${getSavedKey() || 'YOUR_API_KEY'}" \
-H "Accept: application/json"
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"}'
curl -X GET "${window.location.origin}/v1/mailboxes/1/messages" \
-H "X-API-Key: ${getSavedKey() || 'YOUR_API_KEY'}"
curl -X GET "${window.location.origin}/v1/mailboxes/1/messages/MESSAGE_ID" \
-H "X-API-Key: ${getSavedKey() || 'YOUR_API_KEY'}"
curl -X POST "${window.location.origin}/v1/admin/retention/run?force_maintenance=true" \
-H "X-API-Key: ${getSavedKey() || 'YOUR_API_KEY'}"