Skip to main content

Python SDK for the Unsent API - Send transactional emails with ease

Project description

unsent Python SDK

Prerequisites

Installation

pip

pip install unsent

poetry

poetry add unsent

Usage

Basic Setup

from unsent import unsent

client = unsent("us_12345")

Environment Variables

You can also set your API key using environment variables:

# Set UNSENT_API_KEY or UNSENT_API_KEY in your environment
# Then initialize without passing the key
client = unsent()

Sending Emails

Simple Email

data, error = client.emails.send({
    "to": "hello@acme.com",
    "from": "hello@company.com",
    "subject": "unsent email",
    "html": "<p>unsent is the best open source product to send emails</p>",
    "text": "unsent is the best open source product to send emails",
})

if error:
    print(f"Error: {error}")
else:
    print(f"Email sent! ID: {data['id']}")

Email with Attachments

data, error = client.emails.send({
    "to": "hello@acme.com",
    "from": "hello@company.com",
    "subject": "Email with attachment",
    "html": "<p>Please find the attachment below</p>",
    "attachments": [
        {
            "filename": "document.pdf",
            "content": "base64-encoded-content-here",
        }
    ],
})

Scheduled Email

from datetime import datetime, timedelta

# Schedule email for 1 hour from now
scheduled_time = datetime.now() + timedelta(hours=1)

data, error = client.emails.send({
    "to": "hello@acme.com",
    "from": "hello@company.com",
    "subject": "Scheduled email",
    "html": "<p>This email was scheduled</p>",
    "scheduledAt": scheduled_time,
})

Batch Emails

emails = [
    {
        "to": "user1@example.com",
        "from": "hello@company.com",
        "subject": "Hello User 1",
        "html": "<p>Welcome User 1</p>",
    },
    {
        "to": "user2@example.com",
        "from": "hello@company.com",
        "subject": "Hello User 2",
        "html": "<p>Welcome User 2</p>",
    },
]

data, error = client.emails.batch(emails)

if error:
    print(f"Error: {error}")
else:
    print(f"Sent {len(data['emails'])} emails")

Managing Emails

Get Email Details

data, error = client.emails.get("email_id")

if error:
    print(f"Error: {error}")
else:
    print(f"Email status: {data['status']}")

Update Email

data, error = client.emails.update("email_id", {
    "subject": "Updated subject",
    "html": "<p>Updated content</p>",
})

Cancel Scheduled Email

data, error = client.emails.cancel("email_id")

if error:
    print(f"Error: {error}")
else:
    print("Email cancelled successfully")

Managing Contacts

Create Contact

data, error = client.contacts.create("contact_book_id", {
    "email": "user@example.com",
    "firstName": "John",
    "lastName": "Doe",
    "metadata": {
        "company": "Acme Inc",
        "role": "Developer"
    }
})

Get Contact

data, error = client.contacts.get("contact_book_id", "contact_id")

Update Contact

data, error = client.contacts.update("contact_book_id", "contact_id", {
    "firstName": "Jane",
    "metadata": {
        "role": "Senior Developer"
    }
})

Upsert Contact

# Creates if doesn't exist, updates if exists
data, error = client.contacts.upsert("contact_book_id", "contact_id", {
    "email": "user@example.com",
    "firstName": "John",
    "lastName": "Doe",
})

Delete Contact

data, error = client.contacts.delete(
    book_id="contact_book_id",
    contact_id="contact_id"
)

Managing Campaigns

Create Campaign

from unsent import types

campaign_payload: types.CampaignCreate = {
    "name": "Welcome Series",
    "subject": "Welcome to our service!",
    "html": "<p>Thanks for joining us!</p>",
    "from": "welcome@example.com",
    "contactBookId": "cb_1234567890",
}

campaign_resp, error = client.campaigns.create(payload=campaign_payload)

if error:
    print(f"Error: {error}")
else:
    print(f"Campaign created! ID: {campaign_resp['id']}")

Schedule Campaign

from unsent import types

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

schedule_resp, error = client.campaigns.schedule(
    campaign_id=campaign_resp["id"],
    payload=schedule_payload
)

if error:
    print(f"Error: {error}")
else:
    print("Campaign scheduled successfully!")

Pause/Resume Campaigns

# Pause a campaign
pause_resp, error = client.campaigns.pause(campaign_id="campaign_123")

if error:
    print(f"Error: {error}")
else:
    print("Campaign paused successfully!")

# Resume a campaign
resume_resp, error = client.campaigns.resume(campaign_id="campaign_123")

if error:
    print(f"Error: {error}")
else:
    print("Campaign resumed successfully!")

Get Campaign Details

data, error = client.campaigns.get("campaign_id")

if error:
    print(f"Error: {error}")
else:
    print(f"Campaign status: {data['status']}")
    print(f"Recipients: {data['total']}")
    print(f"Sent: {data['sent']}")

Managing Domains

List Domains

data, error = client.domains.list()

if error:
    print(f"Error: {error}")
else:
    for domain in data:
        print(f"Domain: {domain['domain']}, Status: {domain['status']}")

Create Domain

data, error = client.domains.create({
    "domain": "example.com"
})

Verify Domain

data, error = client.domains.verify(domain_id=123)

if error:
    print(f"Error: {error}")
else:
    print(f"Verification status: {data['status']}")

Get Domain

data, error = client.domains.get(domain_id=123)

Error Handling

By default, the SDK raises exceptions on HTTP errors:

from unsent import unsent, unsentHTTPError

client = unsent("us_12345")

try:
    data, error = client.emails.send({
        "to": "invalid-email",
        "from": "hello@company.com",
        "subject": "Test",
        "html": "<p>Test</p>",
    })
except unsentHTTPError as e:
    print(f"HTTP {e.status_code}: {e.error['message']}")

To disable automatic error raising:

client = unsent("us_12345", raise_on_error=False)

data, error = client.emails.send({
    "to": "hello@acme.com",
    "from": "hello@company.com",
    "subject": "Test",
    "html": "<p>Test</p>",
})

if error:
    print(f"Error: {error['message']}")
else:
    print("Success!")

Custom Session

For advanced use cases, you can provide your own requests.Session:

import requests
from unsent import unsent

session = requests.Session()
session.verify = False  # Not recommended for production!

client = unsent("us_12345", session=session)

API Reference

Client Methods

  • unsent(key, url, raise_on_error=True, session=None) - Initialize the client

Email Methods

  • client.emails.send(payload) - Send an email (alias for create)
  • client.emails.create(payload) - Create and send an email
  • client.emails.batch(emails) - Send multiple emails in batch
  • client.emails.get(email_id) - Get email details
  • client.emails.update(email_id, payload) - Update a scheduled email
  • client.emails.cancel(email_id) - Cancel a scheduled email

Contact Methods

  • client.contacts.create(book_id, payload) - Create a contact
  • client.contacts.get(book_id, contact_id) - Get contact details
  • client.contacts.update(book_id, contact_id, payload) - Update a contact
  • client.contacts.upsert(book_id, contact_id, payload) - Upsert a contact
  • client.contacts.delete(book_id, contact_id) - Delete a contact

Campaign Methods

  • client.campaigns.create(payload) - Create a campaign
  • client.campaigns.get(campaign_id) - Get campaign details
  • client.campaigns.schedule(campaign_id, payload) - Schedule a campaign
  • client.campaigns.pause(campaign_id) - Pause a campaign
  • client.campaigns.resume(campaign_id) - Resume a campaign

Domain Methods

  • client.domains.list() - List all domains
  • client.domains.create(payload) - Create a domain
  • client.domains.verify(domain_id) - Verify a domain
  • client.domains.get(domain_id) - Get domain details

Requirements

  • Python 3.8+
  • requests >= 2.32.0
  • typing_extensions >= 4.7

License

MIT

Support

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

unsent-1.0.0.tar.gz (10.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

unsent-1.0.0-py3-none-any.whl (11.1 kB view details)

Uploaded Python 3

File details

Details for the file unsent-1.0.0.tar.gz.

File metadata

  • Download URL: unsent-1.0.0.tar.gz
  • Upload date:
  • Size: 10.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.2.1 CPython/3.13.8 Darwin/25.0.0

File hashes

Hashes for unsent-1.0.0.tar.gz
Algorithm Hash digest
SHA256 9cdd8789852b8df4efd5d4e97302f0181a6bd8881893c981ae4020468cfe01a0
MD5 1932e5868cbf77f136c3193a41a05134
BLAKE2b-256 4c0e16db4929747d411a820c0695b98581eb59401a1533c9bda5e67ff3bcff1c

See more details on using hashes here.

File details

Details for the file unsent-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: unsent-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 11.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.2.1 CPython/3.13.8 Darwin/25.0.0

File hashes

Hashes for unsent-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e7073e52523a03cb777f6ec5029aa14aab24924232e934a44f619d9c843035c9
MD5 6ff3f13476603a2174e1e7e4cfd08d10
BLAKE2b-256 598606719638d937118c3e14fa09d971681f449ae67e80cfa17352c7820c980d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page