unsent
unsent.dev
Get Started

Python

Official Unsent Python SDK for sending emails and managing contacts.

This guide shows how to install and use the official unsent Python SDK.

Installation

Install the SDK from PyPI using pip:

pip install unsent

Initialize

Import the unsent class and initialize the client with your API key.

from unsent import unsent

# Initialize with raise_on_error=False to return errors as tuples
client = unsent("un_xxx", raise_on_error=False)

Send an email

Now you can send an email. The SDK uses TypedDict definitions (like EmailCreate) to provide type hinting in your editor, but at runtime, you simply pass a standard Python dictionary.

Here is an example of sending a simple HTML email:

from unsent import unsent, types

client = unsent("un_xxx")

# Define the email payload
payload: types.EmailCreate = {
    "to": "user@example.com",
    "from": "no-reply@yourdomain.com",
    "subject": "Welcome",
    "html": "<strong>Hello!</strong>",
    "headers": {"X-Campaign": "welcome"},
}

# Send the email
data, err = client.emails.send(payload)

if err:
    print("Error:", err)
else:
    print("Email sent:", data)

Note

Unsent forwards your custom headers to SES. Only the X-Unsent-Email-ID and References headers are managed automatically by Unsent.

Attachments and scheduling

You can also send emails with attachments and schedule them for later delivery.

  • Attachments: Provide a list of attachments, where each attachment has a filename and content (Base64 encoded string).
  • Scheduling: Use the scheduledAt field with a datetime object.
from datetime import datetime, timedelta
from unsent import types

payload: types.EmailCreate = {
    "to": ["user1@example.com", "user2@example.com"],
    "from": "no-reply@yourdomain.com",
    "subject": "Report",
    "text": "See attached.",
    "attachments": [
        {"filename": "report.txt", "content": "SGVsbG8gd29ybGQ="},  # Content must be Base64 encoded
    ],
    "scheduledAt": datetime.utcnow() + timedelta(minutes=10), # Schedule for 10 minutes from now
}

data, err = client.emails.create(payload)

Batch send

To send multiple emails efficiently in a single request, use the batch method.

items: list[types.EmailBatchItem] = [
    {"to": "a@example.com", "from": "no-reply@yourdomain.com", "subject": "A", "html": "<p>A</p>"},
    {"to": "b@example.com", "from": "no-reply@yourdomain.com", "subject": "B", "html": "<p>B</p>"},
]

data, err = client.emails.batch(items)

Retrieve and manage emails

You can retrieve details of sent emails, update scheduled emails, or cancel them.

Get an email

Fetch the status and details of a specific email using its ID:

email, err = client.emails.get("email_123")

Update schedule time

Change the scheduled delivery time for a pending email:

from datetime import datetime, timedelta

update: types.EmailUpdate = {"scheduledAt": datetime.utcnow() + timedelta(hours=1)}
data, err = client.emails.update("email_123", update)

Cancel a scheduled email

Cancel a scheduled email so it won't be sent:

data, err = client.emails.cancel("email_123")

Contacts

Manage your contacts and organize them into contact books. All contact operations require a contact book ID (book_id).

Create a contact

Add a new contact to a specific contact book. You can include custom properties.

create: types.ContactCreate = {
    "email": "user@example.com",
    "firstName": "Jane",
    "properties": {"plan": "pro"},
}

data, err = client.contacts.create("book_123", create)

Get a contact

Retrieve a contact's details:

contact, err = client.contacts.get("book_123", "contact_456")

Update a contact

Update a contact's information:

update: types.ContactUpdate = {"subscribed": False}

data, err = client.contacts.update("book_123", "contact_456", update)

Upsert a contact

Use upsert to create a contact if they don't exist, or update them if they do.

upsert: types.ContactUpsert = {
    "email": "user@example.com",
    "firstName": "Jane",
}

data, err = client.contacts.upsert("book_123", "contact_456", upsert)

Delete a contact

Remove a contact from a book:

data, err = client.contacts.delete(book_id="book_123", contact_id="contact_456")

Campaigns

Campaigns allow you to send emails to all contacts in a specific contact book.

Create a campaign

Create a new campaign by defining its content and the target contact book.

campaign: types.CampaignCreate = {
    "name": "Welcome Series",
    "subject": "Welcome!",
    "html": "<p>Thanks for joining us!</p>",
    "from": "welcome@yourdomain.com",
    "contactBookId": "book_123",
}

data, err = client.campaigns.create(campaign)

Schedule a campaign

Schedule the campaign to be sent at a specific time.

schedule: types.CampaignSchedule = {
    "scheduledAt": "2024-12-01T10:00:00Z"
}

data, err = client.campaigns.schedule("campaign_123", schedule)

Pause and Resume

Control the delivery of your campaign.

# Pause
data, err = client.campaigns.pause("campaign_123")

# Resume
data, err = client.campaigns.resume("campaign_123")

Domains

Manage your sending domains.

List domains

Get a list of all domains and their statuses.

data, err = client.domains.list()

Create a domain

Register a new domain for sending.

domain: types.DomainCreate = {
    "domain": "yourdomain.com",
    "region": "us-east-1",
}

data, err = client.domains.create(domain)

Verify a domain

Check the verification status of a domain.

data, err = client.domains.verify(123)

Error handling

The SDK supports two modes of error handling.

Raising Exceptions (Default)

By default, the client raises unsentHTTPError for non-2xx responses. This is useful for standard exception handling.

from unsent import unsent, unsentHTTPError

# Raises exceptions on errors (default)
client = unsent("un_xxx")

try:
    data, _ = client.emails.get("email_123")
except unsentHTTPError as e:
    print("Request failed:", e)

Returning Error Tuples

If you prefer to check for errors in the return value instead of using try-except blocks, pass raise_on_error=False when initializing the client.

# Returns (None, error) instead of raising
client = unsent("un_xxx", raise_on_error=False)

data, err = client.emails.get("email_123")

if err:
    print("Error:", err)
else:
    print("Success:", data)