Python SDK

Official Python client for SigninID. Supports both sync and async operations.

Installation

pip install signinid

Requires Python 3.10 or later.

Basic Usage

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(f"Verification code: {email.detected_otp}")

Async Support

import asyncio
from signinid import AsyncSigninID

async def main():
    async with AsyncSigninID(secret_key="sk_live_...") as client:
        email = await client.inbox.wait_for_new(to="user@test.com")
        if email:
            print(f"OTP: {email.detected_otp}")

asyncio.run(main())

Configuration

The client reads from SIGNINID_SECRET_KEY environment variable by default. You can also pass the secret key directly:

# Using environment variable (recommended)
client = SigninID()

# Or pass secret key directly
client = SigninID(secret_key="sk_live_...")

Client Options

OptionTypeDefaultDescription
secret_keystr | Noneenv varSecret key (falls back to SIGNINID_SECRET_KEY)
timeoutint30000Request timeout in milliseconds

Inbox Methods

client.inbox.wait_for_new(**params)

Wait for a new email to arrive. Polls the inbox until a new email arrives or timeout is reached. This is the recommended method for testing signup/login flows.

Example

email = client.inbox.wait_for_new(to="user@test.com")
if email:
    print(f"OTP: {email.detected_otp}")

Parameters

ParameterTypeDefaultDescription
tostr | None-Filter by recipient (partial match)
timeoutint30Maximum wait time in seconds

Response Type: InboxEmail | None

Returns None if timeout reached.

FieldTypeDescription
email_idstrUnique identifier
detected_otpstr | NoneAuto-extracted verification code
html_bodystr | NoneHTML content
text_bodystr | NonePlain text content
from_addressstrSender email address
from_namestr | NoneSender display name
to_addressestuple[str, ...]Recipient addresses
cc_addressestuple[str, ...] | NoneCC addresses
subjectstr | NoneEmail subject
received_atdatetimeWhen email was received
message_idstr | NoneSMTP Message-ID header
has_attachmentsboolHas attachments
attachment_countintNumber of attachments
spam_scorefloat | NoneSpam score
spam_verdictPASS | FAIL | GRAY | NoneSpam classification
spam_rulesSpamRules | NoneDetailed spam rules
virus_verdictSecurityVerdictVirus scan result
spf_verdictSecurityVerdictSPF authentication
dkim_verdictSecurityVerdictDKIM verification
dmarc_verdictSecurityVerdictDMARC compliance

client.inbox.latest(**params)

Get the most recent inbox email. Returns immediately with the latest email or None.

Example

email = client.inbox.latest(to="user@test.com")
if email:
    print(f"OTP: {email.detected_otp}")

Parameters

ParameterTypeDefaultDescription
tostr | None-Filter by recipient (partial match)
afterdatetime | str | None-Only return emails received after this timestamp

Response Type: InboxEmail | None

FieldTypeDescription
email_idstrUnique identifier
detected_otpstr | NoneAuto-extracted verification code
html_bodystr | NoneHTML content
text_bodystr | NonePlain text content
from_addressstrSender email address
from_namestr | NoneSender display name
to_addressestuple[str, ...]Recipient addresses
cc_addressestuple[str, ...] | NoneCC addresses
subjectstr | NoneEmail subject
received_atdatetimeWhen email was received
message_idstr | NoneSMTP Message-ID header
has_attachmentsboolHas attachments
attachment_countintNumber of attachments
spam_scorefloat | NoneSpam score
spam_verdictPASS | FAIL | GRAY | NoneSpam classification
spam_rulesSpamRules | NoneDetailed spam rules
virus_verdictSecurityVerdictVirus scan result
spf_verdictSecurityVerdictSPF authentication
dkim_verdictSecurityVerdictDKIM verification
dmarc_verdictSecurityVerdictDMARC compliance

client.inbox.get(email_id)

Get a single inbox email by ID.

Example

email = client.inbox.get("550e8400-e29b-41d4-a716-446655440000")
print(f"Subject: {email.subject}")

Parameters

ParameterTypeDescription
email_idstrThe email ID (UUID format)

Response Type: InboxEmail

Raises NotFoundError if not found.

FieldTypeDescription
email_idstrUnique identifier
detected_otpstr | NoneAuto-extracted verification code
html_bodystr | NoneHTML content
text_bodystr | NonePlain text content
from_addressstrSender email address
from_namestr | NoneSender display name
to_addressestuple[str, ...]Recipient addresses
cc_addressestuple[str, ...] | NoneCC addresses
subjectstr | NoneEmail subject
received_atdatetimeWhen email was received
message_idstr | NoneSMTP Message-ID header
has_attachmentsboolHas attachments
attachment_countintNumber of attachments
spam_scorefloat | NoneSpam score
spam_verdictPASS | FAIL | GRAY | NoneSpam classification
spam_rulesSpamRules | NoneDetailed spam rules
virus_verdictSecurityVerdictVirus scan result
spf_verdictSecurityVerdictSPF authentication
dkim_verdictSecurityVerdictDKIM verification
dmarc_verdictSecurityVerdictDMARC compliance

client.inbox.list(**params)

List inbox email IDs with pagination. Returns only IDs - use get() to fetch full details.

Example

response = client.inbox.list(per_page=20)
for email_id in response:
    email = client.inbox.get(email_id)
    print(email.subject)

Parameters

ParameterTypeDefaultDescription
pageint | None1Page number (1, 2, 3...)
per_pageint | None10Results per page (1-100)
from_str | None-Filter by sender (partial match)
tostr | None-Filter by recipient (partial match)
subjectstr | None-Filter by subject (partial match)
beforedatetime | str | None-Emails before this date
afterdatetime | str | None-Emails after this date

Note: Use from_ (with underscore) since from is a Python reserved word.

Response Type: ListIdsResponse

Iterable collection of email IDs with pagination metadata.

FieldTypeDescription
datatuple[str, ...]Tuple of email IDs
pagination.pageintCurrent page number
pagination.per_pageintItems per page
pagination.returnedintActual count returned
pagination.has_moreboolMore results available

Sent Methods

client.sent.latest(**params)

Get the most recent sent email. Returns immediately with the latest email or None.

Example

email = client.sent.latest(to="user@example.com")
if email:
    print(f"Spam score: {email.spam_score}")

Parameters

ParameterTypeDefaultDescription
tostr | None-Filter by recipient (partial match)
afterdatetime | str | None-Only return emails sent after this timestamp

Response Type: SentEmail | None

FieldTypeDescription
email_idstrUnique identifier
detected_otpstr | NoneAuto-extracted verification code
html_bodystr | NoneHTML content
text_bodystr | NonePlain text content
from_addressstrSender email address
from_namestr | NoneSender display name
to_addressestuple[str, ...]Recipient addresses
cc_addressestuple[str, ...] | NoneCC addresses
bcc_addressestuple[str, ...] | NoneBCC addresses
subjectstr | NoneEmail subject
sent_atdatetimeWhen email was sent
message_idstr | NoneSMTP Message-ID header
has_attachmentsboolHas attachments
attachment_countintNumber of attachments
spam_scorefloat | NoneSpam score
spam_verdictPASS | FAIL | GRAY | NoneSpam classification

client.sent.get(email_id)

Get a single sent email by ID.

Example

email = client.sent.get("660f9500-f39c-52e5-b827-557766551111")
print(f"Subject: {email.subject}")

Parameters

ParameterTypeDescription
email_idstrThe email ID (UUID format)

Response Type: SentEmail

Raises NotFoundError if not found.

FieldTypeDescription
email_idstrUnique identifier
detected_otpstr | NoneAuto-extracted verification code
html_bodystr | NoneHTML content
text_bodystr | NonePlain text content
from_addressstrSender email address
from_namestr | NoneSender display name
to_addressestuple[str, ...]Recipient addresses
cc_addressestuple[str, ...] | NoneCC addresses
bcc_addressestuple[str, ...] | NoneBCC addresses
subjectstr | NoneEmail subject
sent_atdatetimeWhen email was sent
message_idstr | NoneSMTP Message-ID header
has_attachmentsboolHas attachments
attachment_countintNumber of attachments
spam_scorefloat | NoneSpam score
spam_verdictPASS | FAIL | GRAY | NoneSpam classification

client.sent.list(**params)

List sent email IDs with pagination. Returns only IDs - use get() to fetch full details.

Example

response = client.sent.list(per_page=20)
for email_id in response:
    email = client.sent.get(email_id)
    print(email.subject)

Parameters

ParameterTypeDefaultDescription
pageint | None1Page number (1, 2, 3...)
per_pageint | None10Results per page (1-100)
from_str | None-Filter by sender (partial match)
tostr | None-Filter by recipient (partial match)
subjectstr | None-Filter by subject (partial match)
beforedatetime | str | None-Emails before this date
afterdatetime | str | None-Emails after this date

Response Type: ListIdsResponse

FieldTypeDescription
datatuple[str, ...]Tuple of email IDs
pagination.pageintCurrent page number
pagination.per_pageintItems per page
pagination.returnedintActual count returned
pagination.has_moreboolMore results available

Async Methods

AsyncSigninID provides the same API with await:

import asyncio
from signinid import AsyncSigninID

async def main():
    async with AsyncSigninID() as client:
        # Wait for new email
        email = await client.inbox.wait_for_new(to="user@test.com")

        # Get latest
        email = await client.inbox.latest(to="user@test.com")

        # List and fetch
        inbox_ids = await client.inbox.list(to="user@test.com")
        for email_id in inbox_ids:
            full_email = await client.inbox.get(email_id)
            print(full_email.detected_otp)

asyncio.run(main())

Error Handling

The SDK raises typed exceptions for different failure scenarios:

ExceptionWhen Raised
AuthenticationErrorInvalid or missing API key
NotFoundErrorEmail not found (404)
ValidationErrorInvalid request parameters
RateLimitErrorToo many requests
NetworkErrorConnection failed
TimeoutErrorRequest timed out
from signinid import (
    SigninID,
    AuthenticationError,
    NotFoundError,
    ValidationError,
    RateLimitError,
    NetworkError,
    TimeoutError,
)

try:
    email = client.inbox.get("invalid-id")
except NotFoundError:
    print("Email not found")
except AuthenticationError:
    print("Invalid API key")
except ValidationError as e:
    print(f"Invalid parameters: {e.details}")
except RateLimitError as e:
    print(f"Rate limited. Retry after: {e.retry_after}s")
except NetworkError:
    print("Network error")
except TimeoutError:
    print("Request timed out")