Sendr Docs
SDKs

Python SDK

Official Python SDK for the Sendr email API.

Installation

pip install sendr
# or with poetry
poetry add sendr
# or with uv
uv add sendr

Requires Python 3.9+.

Initialization

import sendr

# Simple initialization
client = sendr.Client(api_key="sndr_live_your_api_key")

# Or from environment variable
import os
client = sendr.Client(api_key=os.environ["SENDR_API_KEY"])

# With configuration
client = sendr.Client(
    api_key=os.environ["SENDR_API_KEY"],
    base_url="https://api.sendr.dev",
    timeout=30,       # seconds
    max_retries=2,
)

Emails

# Send a single email
email = client.emails.send(
    from_="Acme <hello@acme.com>",
    to="user@example.com",
    subject="Welcome!",
    html="<h1>Welcome to Acme!</h1>",
)
print(email.id)      # em_abc123
print(email.status)  # queued

# Send to multiple recipients
client.emails.send(
    from_="hello@acme.com",
    to=["alice@example.com", "bob@example.com"],
    subject="Team announcement",
    html="<p>Big news...</p>",
)

# Send with attachment
import base64

with open("invoice.pdf", "rb") as f:
    content = base64.b64encode(f.read()).decode()

client.emails.send(
    from_="billing@acme.com",
    to="user@example.com",
    subject="Your invoice",
    html="<p>Please find your invoice attached.</p>",
    attachments=[
        {
            "filename": "invoice.pdf",
            "content": content,
            "content_type": "application/pdf",
        }
    ],
)

# Send using a template
client.emails.send(
    from_="hello@acme.com",
    to="user@example.com",
    template_id="tmpl_abc123",
    variables={"name": "Alice", "plan": "Pro"},
)

# Batch send (up to 100 at once)
result = client.emails.send_batch(
    from_="hello@acme.com",
    subject="Order update",
    emails=[
        {"to": "alice@example.com", "html": "<p>Alice, your order shipped!</p>"},
        {"to": "bob@example.com", "html": "<p>Bob, your order shipped!</p>"},
    ],
)
for item in result.data:
    print(item.id, item.status)

# Get email status
email = client.emails.get("em_abc123")
print(email.status)  # delivered

# List emails
page = client.emails.list(limit=25, status="delivered")
for email in page.data:
    print(email.id, email.subject)

# Paginate
while page.has_more:
    page = client.emails.list(cursor=page.next_cursor)
    for email in page.data:
        print(email.id)

# Cancel a scheduled email
client.emails.cancel("em_abc123")

Async support

import asyncio
import sendr

async def main():
    client = sendr.AsyncClient(api_key=os.environ["SENDR_API_KEY"])

    email = await client.emails.send(
        from_="hello@acme.com",
        to="user@example.com",
        subject="Hello!",
        html="<p>Async email!</p>",
    )
    print(email.id)

asyncio.run(main())

Domains

# Add a domain
domain = client.domains.create(name="acme.com")
for record in domain.dns_records:
    print(f"{record.type} {record.host}{record.value}")

# Verify after DNS propagation
result = client.domains.verify("dom_abc123")
print(result.status)  # verified

client.domains.list()
client.domains.get("dom_abc123")
client.domains.remove("dom_abc123")

Error handling

from sendr.exceptions import (
    ApiError,
    AuthenticationError,
    RateLimitError,
    ValidationError,
)
import time

try:
    client.emails.send(
        from_="hello@acme.com",
        to="user@example.com",
        subject="Hello",
        html="<p>Hi</p>",
    )
except AuthenticationError:
    print("Invalid API key — check SENDR_API_KEY")
except RateLimitError as e:
    print(f"Rate limited. Retry after {e.retry_after} seconds")
    time.sleep(e.retry_after)
except ValidationError as e:
    print("Validation failed:", e.details)
except ApiError as e:
    print(f"API error {e.status_code}: {e.code}{e.message}")

Context manager

with sendr.Client(api_key=os.environ["SENDR_API_KEY"]) as client:
    email = client.emails.send(
        from_="hello@acme.com",
        to="user@example.com",
        subject="Hello",
        html="<p>Hi</p>",
    )
# Connection pool closed on exit

On this page