Python SDK

Menu

Official Python SDK for the toSend email API.

Installation

pip install tosend

Quick Start

from tosend import ToSend

client = ToSend("tsend_your_api_key")

response = client.send(
    from_address={"email": "hello@yourdomain.com", "name": "Your App"},
    to=[{"email": "user@example.com"}],
    subject="Welcome!",
    html="<h1>Hello!</h1><p>Thanks for signing up.</p>",
)

print(response.message_id)

Configuration

Simple

client = ToSend("tsend_your_api_key")

With Options

client = ToSend(
    api_key="tsend_your_api_key",
    base_url="https://api.tosend.com",  # optional
    timeout=60,  # optional, in seconds
)

Send Email

Basic Email

response = client.send(
    from_address={"email": "hello@yourdomain.com", "name": "Your App"},
    to=[
        {"email": "user@example.com"},
        {"email": "another@example.com", "name": "John Doe"},
    ],
    subject="Hello!",
    html="<h1>Welcome</h1>",
    text="Welcome",  # optional
)

With CC, BCC, and Reply-To

response = client.send(
    from_address={"email": "hello@yourdomain.com"},
    to=[{"email": "user@example.com"}],
    cc=[{"email": "cc@example.com"}],
    bcc=[{"email": "bcc@example.com"}],
    reply_to={"email": "support@yourdomain.com", "name": "Support"},
    subject="Hello",
    html="<p>Hello World</p>",
)

With Attachments

import base64

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

response = client.send(
    from_address={"email": "hello@yourdomain.com"},
    to=[{"email": "user@example.com"}],
    subject="Your Invoice",
    html="<p>Please find your invoice attached.</p>",
    attachments=[
        {
            "type": "application/pdf",
            "name": "invoice.pdf",
            "content": content,
        }
    ],
)

Batch Sending

Send multiple emails in a single request:

response = client.batch([
    {
        "from": {"email": "hello@yourdomain.com"},
        "to": [{"email": "user1@example.com"}],
        "subject": "Hello User 1",
        "html": "<p>Welcome!</p>",
    },
    {
        "from": {"email": "hello@yourdomain.com"},
        "to": [{"email": "user2@example.com"}],
        "subject": "Hello User 2",
        "html": "<p>Welcome!</p>",
    },
])

for result in response.results:
    if result.status == "success":
        print(f"Sent: {result.message_id}")
    else:
        print(f"Failed: {result.message}")

Account Info

info = client.get_account_info()

print(info.account.status)            # "active"
print(info.account.credit_balance)    # None means the account does not consume credits
print(info.account.limit_per_second)

for domain in info.domains:
    print(f"{domain.domain_name}: {domain.verification_status}")

Admin API

ToSendAdmin is a separate client for the Admin API. It takes an admin key (tsend_admin_...) and refuses a sending key at construction. Each call needs the matching scope on the key; a missing one raises ToSendError with status 403 and error.code == "insufficient_scope".

import os
from tosend import ToSendAdmin

admin = ToSendAdmin(os.environ["TOSEND_ADMIN_KEY"])

# Act on one of your client teams (sends X-Account-Id)
client = admin.for_account(4203)

domain = client.create_domain("client.example.com")
detail = client.get_domain(domain["id"])
print(detail["dns_records"]["dkim"])  # show these records to your client

# Needs api_keys:write and emails:send
key = client.create_sending_key("Client: Acme Corp")
print(key["api_key"])  # returned once, store it now

# Needs emails:send
client.send(
    from_address={"email": "hello@client.example.com"},
    to=[{"email": "user@example.com"}],
    subject="Hi",
    html="<p>Hello</p>",
)

Also available: get_info, list_domains, delete_domain, list_emails, get_email, list_suppressions, delete_suppression, list_webhooks, create_webhook, update_webhook, delete_webhook, list_sending_keys, delete_sending_key, list_teams, create_team, update_team and batch. List methods take page and per_page and return a dict with data, total, page and per_page; single-resource methods return the resource as a dict.

Error Handling

from tosend import ToSend, ToSendError

client = ToSend("tsend_your_api_key")

try:
    response = client.send(
        from_address={"email": "hello@yourdomain.com"},
        to=[{"email": "user@example.com"}],
        subject="Hello",
        html="<p>Hello</p>",
    )
except ToSendError as e:
    print(f"Error: {e.message}")
    print(f"Status: {e.status_code}")
    print(f"Details: {e.errors}")

    if e.is_validation_error:
        # Handle validation error (422)
        pass

    if e.is_authentication_error:
        # Handle auth error (401/403)
        pass

    if e.is_rate_limit_error:
        # Handle rate limit (429)
        pass

Type Hints

The SDK includes full type hints. You can use the provided dataclasses:

from tosend import ToSend, Address, SendEmailRequest

client = ToSend("tsend_your_api_key")

# Using Address dataclass
from_addr = Address(email="hello@yourdomain.com", name="Your App")
to_addr = Address(email="user@example.com")

response = client.send(
    from_address=from_addr,
    to=[to_addr],
    subject="Hello!",
    html="<h1>Welcome!</h1>",
)

Zero Dependencies

The Python SDK uses only the standard library and has no external dependencies.