Skip to main content

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.

Homepage | Documentation

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

signinid-0.1.0.tar.gz (14.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

signinid-0.1.0-py3-none-any.whl (18.5 kB view details)

Uploaded Python 3

File details

Details for the file signinid-0.1.0.tar.gz.

File metadata

  • Download URL: signinid-0.1.0.tar.gz
  • Upload date:
  • Size: 14.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.11

File hashes

Hashes for signinid-0.1.0.tar.gz
Algorithm Hash digest
SHA256 0579072bea633032bc9806c82f7a55b3878f38a4e01a388b3ec47caa79c57d28
MD5 70149c02ad4a033f4a5b9b90a9d2e5fe
BLAKE2b-256 068164cd146427ab0a533bdbdbeb491064eaf57668be46188245506df0b9e679

See more details on using hashes here.

File details

Details for the file signinid-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: signinid-0.1.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

Hashes for signinid-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 15460477361c07133ee3d436048a4b1f9d1ad05ea275d8b6ac292290f46f2a8b
MD5 b2b9940cfba51dd682d3057b62645b19
BLAKE2b-256 ee47ac17724a8e7414bee915332ad4f006d0d35f4b0275d36373de5f7a8f11ed

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page