SDKs
Python SDK
Official Python SDK for the Sendry email API.
Installation
pip install sendry
# or with poetry
poetry add sendry
# or with uv
uv add sendry
Requires Python 3.9+.
Initialization
from sendry import Sendry
# Simple initialization
client = Sendry(api_key="sn_live_your_api_key")
# Or from environment variable
import os
client = Sendry(api_key=os.environ["SENDRY_API_KEY"])
# With configuration
client = Sendry(
api_key=os.environ["SENDRY_API_KEY"],
base_url="https://api.sendry.online",
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 os
from sendry import AsyncSendry
async def main():
client = AsyncSendry(api_key=os.environ["SENDRY_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")
Segments
seg = client.segments.create({"name": "High-Value Users"})
client.segments.add_contacts(seg["id"], {"contact_ids": ["ct_1", "ct_2"]})
client.segments.list_contacts(seg["id"])
Topics
topic = client.topics.create({"name": "product-updates", "opt_in_required": True})
client.topics.subscribe(topic["id"], "user@example.com")
Contact properties
client.contact_properties.create({"name": "plan", "label": "Plan", "type": "string"})
client.contact_properties.set_values("ct_123", {"plan": "pro"})
Deliverability insights
insights = client.deliverability_insights.for_email("em_abc123")
# insights["score"] — 0-100; insights["checks"] — per-rule feedback
Email sharing (48h preview links)
link = client.email_sharing.create("em_abc123")
print(link["url"], link["expires_at"])
Attachment download
attach = client.attachments.download("em_abc123", 0)
with open(attach.filename or "attachment.bin", "wb") as f:
f.write(attach.content)
Per-domain tracking toggles
client.tracking.set_for_domain("dom_abc123", {"opens": True, "clicks": False})
Exports (CSV)
job = client.exports.create({"resource": "contacts"})
# Poll client.exports.get(job["id"]) until status == "ready"
csv_bytes = client.exports.download(job["id"])
Postmaster (Gmail Postmaster Tools)
metrics = client.postmaster.metrics({"domain_id": "dom_abc"})
client.postmaster.sync()
Dead-letter queue (admin)
failed = client.dlq.list({"queue": "email-sender"})
client.dlq.retry(failed["data"][0]["id"])
Error handling
from sendry 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 SENDRY_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 Sendry(api_key=os.environ["SENDRY_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
Source
github.com/sendry-dev/sendry-python — MIT licensed. Published as sendry on PyPI.