Email verification infrastructure for CI pipelines — OTPs and magic links auto-extracted. No Docker, no regex, no signup.
Project description
zerodrop
Email verification infrastructure for CI pipelines and AI agents.
Send a verification email. Catch it at the edge. Get email.otp and email.magic_link back — auto-extracted, no regex, no Docker, no signup.
email = mail.wait_for_latest(inbox)
email.otp # "123456" — auto-extracted
email.magic_link # "https://..." — no regex needed
Documentation · GitHub · Status
Install
pip install zerodrop
No dependencies. Python 3.8+.
Zero-Auth Mode (Local Development)
from zerodrop import ZeroDrop
mail = ZeroDrop()
inbox = mail.generate_inbox()
# → "swift-x7k29@zerodrop-sandbox.online"
email = mail.wait_for_latest(inbox, timeout=10000)
print(email.subject) # "Reset your password"
print(email.otp) # "123456" — auto-extracted, no regex needed
print(email.magic_link) # "https://..." — auto-extracted verification link
CI Pipeline Mode (pytest)
from zerodrop import ZeroDrop
mail = ZeroDrop(api_key=os.environ.get("ZERODROP_API_KEY"))
def test_password_reset(page):
inbox = mail.generate_inbox()
page.goto("/forgot-password")
page.fill('[name="email"]', inbox)
page.click('[type="submit"]')
email = mail.wait_for_latest(inbox, timeout=15000)
assert "Reset your password" in email.subject
# No regex — magic_link is auto-extracted at the edge
page.goto(email.magic_link)
assert page.url == "/dashboard"
Email Filtering
Filter emails by sender, subject, body, or extracted fields:
from zerodrop import ZeroDrop, ZeroDropFilter
mail = ZeroDrop()
# Only match emails from a specific sender
email = mail.wait_for_latest(inbox, filter_=ZeroDropFilter(
from_="noreply@yourapp.com"
))
# Only match emails with an OTP
email = mail.wait_for_latest(inbox, filter_=ZeroDropFilter(
has_otp=True
))
# Combine filters
email = mail.wait_for_latest(inbox, timeout=15000, filter_=ZeroDropFilter(
from_="noreply@yourapp.com",
subject="Verify",
has_magic_link=True
))
All string filters are case-insensitive partial matches.
OTP Auto-Extraction
ZeroDrop extracts OTP codes and magic links at the edge before emails reach your test suite. No regex required.
email = mail.wait_for_latest(inbox)
email.otp # "123456" — 4-8 digit verification code
email.magic_link # "https://app.com/verify?token=abc" — verification/reset link
email.body # Full plain-text body (if you need it)
Both fields are None if not detected in the email.
Parallel CI Runs
generate_inbox() runs locally — no network request, no throttling:
# Safe to run in parallel — generate_inbox() is local
inboxes = [mail.generate_inbox() for _ in range(50)]
API
ZeroDrop(api_key=None, base_url=BASE_URL)
api_key— optional. Omit for free sandbox mode.base_url— override the API base URL.
mail.generate_inbox() -> str
Returns a ready-to-use email address instantly. No network request.
mail.fetch_latest(inbox, filter_=None) -> Optional[ZeroDropEmail]
Returns the latest email or None if inbox is empty.
mail.wait_for_latest(inbox, timeout=10000, poll_interval=2.0, filter_=None) -> ZeroDropEmail
Polls until an email arrives. Raises ZeroDropTimeoutError on timeout.
timeout— milliseconds to wait (default: 10000)poll_interval— seconds between polls (default: 2.0)filter_— optionalZeroDropFilterinstance
mail.on_received(inbox, webhook_url) -> dict
Registers a webhook. Requires API key (Workspace tier).
Types
@dataclass
class ZeroDropEmail:
id: str
from_: str
to: str
subject: str
body: str
raw_body: str
received_at: datetime
otp: Optional[str] # Auto-extracted OTP code (4-8 digits)
magic_link: Optional[str] # Auto-extracted verification/reset link
@dataclass
class ZeroDropFilter:
from_: Optional[str] = None # Partial match on sender address
subject: Optional[str] = None # Partial match on subject line
body: Optional[str] = None # Partial match on email body
has_otp: Optional[bool] = None # Only match emails with an OTP
has_magic_link: Optional[bool] = None # Only match emails with a magic link
Error Handling
from zerodrop import ZeroDrop, ZeroDropTimeoutError
try:
email = mail.wait_for_latest(inbox, timeout=10000)
except ZeroDropTimeoutError:
print("No email received — check your app is sending correctly")
Free vs Workspace
| Free | Workspace | |
|---|---|---|
| Inbox generation | ✓ | ✓ |
| OTP auto-extraction | ✓ | ✓ |
| Magic link extraction | ✓ | ✓ |
| Email filtering | ✓ | ✓ |
| Email retention | 30 min | Extended |
| Custom domains | ✗ | ✓ |
| API key | ✗ | ✓ |
| Webhooks | ✗ | ✓ |
| AI spam filter | On | Off |
Get a Workspace at zerodrop.dev
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file zerodrop-0.1.0.tar.gz.
File metadata
- Download URL: zerodrop-0.1.0.tar.gz
- Upload date:
- Size: 6.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b1afa0b2726ebdde5a67040fe994fbb8a4d403896cb68d11e3b80af585cb05c9
|
|
| MD5 |
081e74ebe45ff7b2b056595fe07b4d3b
|
|
| BLAKE2b-256 |
8d805b40ed6f6b0eb6abc600e92db6c60555ead75c76509cb1b2ff57a8907300
|
File details
Details for the file zerodrop-0.1.0-py3-none-any.whl.
File metadata
- Download URL: zerodrop-0.1.0-py3-none-any.whl
- Upload date:
- Size: 7.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
114c24e087f54bf790cbbef5588d14c0dc6be8881abf4d8c5c5e1f3c905669cf
|
|
| MD5 |
c90380ef7d661f0ac53edc2d638c0942
|
|
| BLAKE2b-256 |
f2f883955e0a0d17efdc51b92be2419bc8ce28f4a14128ed1c86d2d1f87fce4d
|