Python SDK for SigninID sandbox email testing API
Project description
SigninID Python SDK
Python SDK for the SigninID sandbox email testing API. Capture and inspect test emails with automatic OTP detection.
Installation
pip install signinid
Quick Start
from 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)
Async Support
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())
Features
- 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
API Reference
Constructor
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 |
Inbox Methods
inbox.wait_for_new(to=, timeout=)
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)
inbox.latest(to=, after=)
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)
)
inbox.get(email_id)
Get a single email by ID.
email = client.inbox.get("550e8400-e29b-41d4-a716-446655440000")
inbox.list(page=, per_page=, from_=, to=, subject=, before=, after=)
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)
Sent Methods
sent.latest(to=)
Get the most recent sent email.
email = client.sent.latest()
sent.get(email_id)
Get a single sent email by ID.
email = client.sent.get("550e8400-e29b-41d4-a716-446655440000")
sent.list(page=, per_page=, from_=, to=, subject=, before=, after=)
List sent email IDs with pagination.
response = client.sent.list(
page=1,
per_page=10,
to="user@example.com"
)
Query Parameters
| 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 |
Types
InboxEmail
@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
SentEmail
@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 | None
Error Handling
from 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 Types
| 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 |
Examples
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.py
E2E Testing Example
from 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()
Requirements
- Python 3.10 or later
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 signinid-0.3.0.tar.gz.
File metadata
- Download URL: signinid-0.3.0.tar.gz
- Upload date:
- Size: 15.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
74fc1959834fc2c7602a36a79916bda15b9dd46e5cbffe8df375c791e837e08b
|
|
| MD5 |
32da068146a734144f74c247bbc49896
|
|
| BLAKE2b-256 |
eb795d99a518e072ff24445e836dc852bebf7fb48735c9468dd33d9d5f27a0d0
|
File details
Details for the file signinid-0.3.0-py3-none-any.whl.
File metadata
- Download URL: signinid-0.3.0-py3-none-any.whl
- Upload date:
- Size: 18.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
00c02841deff072f60db4bece3c823471bd82693fd791866c3bcb2d8b9e6fa04
|
|
| MD5 |
e5650949b3c4eedf8e7495da94a2c82d
|
|
| BLAKE2b-256 |
53bb6aa9f958a410d43c599007bfc76283228276f662f4dbb9f4302170c54e94
|