Python SDK for the SigninID sandbox email testing API. Capture and inspect test emails with automatic OTP detection.
pip install signinidfrom signinid import SigninID
# Set SIGNINID_SECRET_KEY environment variable
client = SigninID()
# Wait for a new verification email to arrive
email = client.inbox.wait_for_new(to="user@test.com")
# Extract the OTP
if email:
print("Verification code:", email.detected_otp)import asyncio
from signinid import AsyncSigninID
async def main():
async with AsyncSigninID() as client:
email = await client.inbox.wait_for_new(to="user@test.com")
if email:
print("Verification code:", email.detected_otp)
asyncio.run(main())- Full type annotations for IDE autocompletion
- Automatic OTP detection
- Polling support for E2E tests (
wait_for_new) - Filter emails by sender, recipient, subject, and date
- Page-based pagination
- Sync and async clients
from signinid import SigninID
client = SigninID(secret_key=None, timeout=30000)| Option | Type | Default | Description |
|---|---|---|---|
secret_key |
str | os.environ["SIGNINID_SECRET_KEY"] |
API secret key (must start with sk_live_) |
timeout |
int | 30000 |
Request timeout in milliseconds |
Wait for a new email to arrive. Polls until a new email arrives or timeout is reached.
email = client.inbox.wait_for_new(
to="user@test.com",
timeout=30 # 30 seconds (default)
)
if email:
print("OTP:", email.detected_otp)Get the most recent inbox email.
email = client.inbox.latest()
# With filters
email = client.inbox.latest(
to="user@test.com",
after=datetime(2024, 1, 1)
)Get a single email by ID.
email = client.inbox.get("550e8400-e29b-41d4-a716-446655440000")List inbox email IDs with pagination.
response = client.inbox.list(
page=1,
per_page=10,
to="user@test.com",
from_="noreply@app.com",
subject="verification",
after=datetime(2024, 1, 1),
before=datetime(2024, 12, 31)
)
# Fetch full details for each email
for email_id in response.data:
email = client.inbox.get(email_id)
print(email.subject)
# Check pagination
print("Has more:", response.pagination.has_more)Get the most recent sent email.
email = client.sent.latest()Get a single sent email by ID.
email = client.sent.get("550e8400-e29b-41d4-a716-446655440000")List sent email IDs with pagination.
response = client.sent.list(
page=1,
per_page=10,
to="user@example.com"
)| Parameter | Type | Description |
|---|---|---|
page |
int | Page number (default: 1) |
per_page |
int | Results per page (1-100, default: 10) |
from_ |
str | Filter by sender (partial match) |
to |
str | Filter by recipient (partial match) |
subject |
str | Filter by subject (partial match) |
before |
datetime | str | Emails before this date |
after |
datetime | str | Emails after this date |
@dataclass(frozen=True)
class InboxEmail:
email_id: str
from_address: str
from_name: str | None
to_addresses: tuple[str, ...]
cc_addresses: tuple[str, ...] | None
subject: str | None
received_at: datetime
message_id: str | None
has_attachments: bool
attachment_count: int
spam_score: float | None
spam_verdict: Literal["PASS", "FAIL", "GRAY"] | None
virus_verdict: str | None
spf_verdict: str | None
dkim_verdict: str | None
dmarc_verdict: str | None
detected_otp: str | None
html_body: str | None
text_body: str | None@dataclass(frozen=True)
class SentEmail:
email_id: str
from_address: str
from_name: str | None
to_addresses: tuple[str, ...]
cc_addresses: tuple[str, ...] | None
bcc_addresses: tuple[str, ...] | None
subject: str | None
sent_at: datetime
message_id: str | None
has_attachments: bool
attachment_count: int
spam_score: float | None
spam_verdict: Literal["PASS", "FAIL", "GRAY"] | None
detected_otp: str | None
html_body: str | None
text_body: str | Nonefrom signinid import (
SigninID,
SigninIDError,
AuthenticationError,
ValidationError,
NetworkError,
TimeoutError,
RateLimitError,
)
try:
email = client.inbox.latest()
except AuthenticationError as e:
print("Invalid API key")
except ValidationError as e:
print("Invalid parameters:", e.details)
except RateLimitError as e:
print("Rate limited. Retry after:", e.retry_after, "seconds")
except NetworkError as e:
print("Network error:", e.message)
except TimeoutError as e:
print("Request timed out")| Error | Status | Description |
|---|---|---|
AuthenticationError |
401 | Invalid or missing API key |
ValidationError |
400 | Invalid request parameters |
RateLimitError |
429 | Too many requests |
NetworkError |
- | Network connectivity issue |
TimeoutError |
- | Request timeout exceeded |
See the examples directory for runnable examples:
cd examples/basic
pip install -e ../..
pip install -r requirements.txt
# Run examples
python inbox_latest.py
python inbox_wait.py test@your-server.signinid.com
python inbox_list.py
python sent_latest.py
python error_handling.pyfrom playwright.sync_api import sync_playwright
from signinid import SigninID
import time
def test_signup_with_email_verification():
client = SigninID()
test_email = f"test-{int(time.time())}@your-server.signinid.com"
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
# Fill signup form
page.goto("/signup")
page.fill('[name="email"]', test_email)
page.click('button[type="submit"]')
# Wait for verification email
email = client.inbox.wait_for_new(
to=test_email,
timeout=30
)
assert email is not None
assert email.detected_otp is not None
# Enter OTP
page.fill('[name="otp"]', email.detected_otp)
page.click('button[type="submit"]')
assert page.url.endswith("/dashboard")
browser.close()- Python 3.10 or later
MIT