PyPIfreecustom-emailPython 3.9+async + sync

Python SDK

Test, debug, and automate signup, OTP, and email-based authentication flows — with real-time observability.

Why this exists

Testing auth flows is painful:

  • Flaky email delivery
  • Polling delays
  • OTP parsing issues
  • No visibility into failures

FreeCustom.Email solves this by giving you: 👉 real-time auth flow debugging.

📦 Installation

bash
pip install freecustom-email

🚀 Quick Start (Auth Flow Testing)

python
import asyncio
from freecustom_email import FreeCustomEmail

async def main():
    client = FreeCustomEmail(api_key="fce_your_api_key_here")
    email = "test@ditube.info"

    # 1. Create inbox (pass `is_testing=True` for zero-latency testing mode)
    await client.inboxes.register(email, is_testing=True)

    # 2. Start test run (NEW - Groups events in your timeline)
    await client.inboxes.start_test(email, "signup-test-1")

    # 3. Trigger your app (e.g. using httpx or playwright)
    # await httpx.post("https://yourapp.com/api/send-otp", json={"email": email})

    # 4. Wait for OTP
    otp = await client.otp.wait_for(email)
    print(f"OTP: {otp}")

    # 5. Debug the full flow
    timeline = await client.inboxes.get_timeline(email, "signup-test-1")
    print(timeline)

if __name__ == "__main__":
    asyncio.run(main())

🔥 Debug Your Auth Flow

Timeline (see what actually happened)

python
timeline = await client.inboxes.get_timeline(email)
for event in timeline.events:
    print(f"[{event.type}] - {event.time}ms")

Insights (why your test failed)

python
insights = await client.inboxes.get_insights(email)
for insight in insights:
    print(f"[{insight.type}] {insight.message}")

Test Runs (group your flows)

python
await client.inboxes.start_test(email, "signup-test-1")
timeline = await client.inboxes.get_timeline(email, "signup-test-1")

⚡ Real-time Debugging (WebSocket)

python
ws = client.realtime(mailbox=email)

@ws.on("email")
async def on_email(event):
    print(f"Flow update: {event}")

await ws.connect()
await ws.wait()

⚙️ Synchronous Mode (Selenium / Pytest)

python
from freecustom_email import FreeCustomEmail

client = FreeCustomEmail(api_key="fce_...", sync=True)

# 1. Register
client.inboxes.register("test@ditube.info", is_testing=True)

# 2. Wait
otp = client.otp.wait_for("test@ditube.info")
print("OTP:", otp)

🔁 Old vs New Mental Model

Old (Temp Mail)New (FreeCustom.Email)
receive emailstest auth flows
read inboxdebug flows
parse OTP manuallyauto extract + analyze
pollingreal-time events

🔥 Most Important Methods (for devs)

  • client.inboxes.start_test(email, test_id)
  • client.otp.wait_for(email)
  • client.inboxes.get_timeline(email, test_id)
  • client.inboxes.get_insights(email)

📚 Full API Reference

Client

python
from freecustom_email import FreeCustomEmail

# Async client
client = FreeCustomEmail(
    api_key="fce_...",      # required
    base_url="https://...", # optional
    timeout=10,             # optional, seconds
)

# Sync client
sync_client = FreeCustomEmail(api_key="fce_...", sync=True)

Inboxes

python
# Register
await client.inboxes.register("mytest@ditube.info")

# List all registered inboxes
inboxes = await client.inboxes.list()

# Unregister
await client.inboxes.unregister("mytest@ditube.info")

Messages

python
# List all messages
messages = await client.messages.list("mytest@ditube.info")

# Get a specific message
msg = await client.messages.get("mytest@ditube.info", "D3vt8NnEQ")
print(msg.subject, msg.otp)

# Delete a message
await client.messages.delete("mytest@ditube.info", "D3vt8NnEQ")

# Wait for a message
msg = await client.messages.wait_for("mytest@ditube.info", timeout=30)

OTP

python
# Get latest OTP
result = await client.otp.get("mytest@ditube.info")
if result.otp:
    print(f"OTP: {result.otp}")

# Wait for OTP
otp = await client.otp.wait_for("mytest@ditube.info", timeout=30)
print(f"Got OTP: {otp}")

Real-time WebSocket

python
ws = client.realtime(
    mailbox="mytest@ditube.info", 
    auto_reconnect=True
)

@ws.on("connected")
async def on_connected(info):
    print("Connected")

@ws.on("email")
async def on_email(email):
    print(f"New email OTP: {email.otp}")

await ws.connect()
await ws.wait()

Domains

python
# List available domains
domains = await client.domains.list()

# Custom domains
custom = await client.domains.list_custom()
result = await client.domains.add_custom("mail.yourdomain.com")
verification = await client.domains.verify_custom("mail.yourdomain.com")
await client.domains.remove_custom("mail.yourdomain.com")

Webhooks

python
# Register a webhook
hook = await client.webhooks.register(
    "mytest@ditube.info",
    "https://your-server.com/hooks/email"
)

# List active webhooks
hooks = await client.webhooks.list()

# Unregister
await client.webhooks.unregister(hook.id)

Account

python
# Account info
info = await client.account.info()

# Usage stats
usage = await client.account.usage()

Error Handling

python
from freecustom_email import (
    AuthError, 
    PlanError, 
    RateLimitError, 
    NotFoundError, 
    TimeoutError
)

try:
    otp = await client.otp.get("mytest@ditube.info")
except AuthError:
    print("Invalid API key")
except PlanError as e:
    print(f"Plan too low: {e}")

Links