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 email service provider to send emails</p>",
"text": "unsent is the best email service provider 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")
Idempotent Retries
# Idempotent retries: same payload + same key returns the original response
payload = {
"to": "hello@acme.com",
"from": "hello@company.com",
"subject": "Welcome!",
"html": "<p>Welcome to our service</p>",
}
resp, _ = client.emails.send(
payload=payload,
options={"idempotency_key": "signup-123"},
)
# Works for batch requests as well
resp, _ = client.emails.batch(
payload=[payload],
options={"idempotency_key": "bulk-welcome-1"},
)
# If the same key is reused with a different payload, the API responds with HTTP 409.
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 forcreate)client.emails.create(payload)- Create and send an emailclient.emails.batch(emails)- Send multiple emails in batchclient.emails.get(email_id)- Get email detailsclient.emails.update(email_id, payload)- Update a scheduled emailclient.emails.cancel(email_id)- Cancel a scheduled email
Contact Methods
client.contacts.create(book_id, payload)- Create a contactclient.contacts.get(book_id, contact_id)- Get contact detailsclient.contacts.update(book_id, contact_id, payload)- Update a contactclient.contacts.upsert(book_id, contact_id, payload)- Upsert a contactclient.contacts.delete(book_id, contact_id)- Delete a contact
Campaign Methods
client.campaigns.create(payload)- Create a campaignclient.campaigns.get(campaign_id)- Get campaign detailsclient.campaigns.schedule(campaign_id, payload)- Schedule a campaignclient.campaigns.pause(campaign_id)- Pause a campaignclient.campaigns.resume(campaign_id)- Resume a campaign
Domain Methods
client.domains.list()- List all domainsclient.domains.create(payload)- Create a domainclient.domains.verify(domain_id)- Verify a domainclient.domains.get(domain_id)- Get domain details
Requirements
- Python 3.8+
- requests >= 2.32.0
- typing_extensions >= 4.7
License
MIT
Support
Project details
Release history Release notifications | RSS feed
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.1.tar.gz
(10.6 kB
view details)
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
unsent-1.0.1-py3-none-any.whl
(11.4 kB
view details)
File details
Details for the file unsent-1.0.1.tar.gz.
File metadata
- Download URL: unsent-1.0.1.tar.gz
- Upload date:
- Size: 10.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.2.1 CPython/3.13.8 Darwin/25.0.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2b9602d51e334cdf3de0045738ace6bfedb150d3cf3a1c86314fd15dfbd086db
|
|
| MD5 |
52d9146daf2311450b73dd55c206343a
|
|
| BLAKE2b-256 |
2ca259c0e8a20e8b4bc96df681299633b4d4e4e6cbbf3f358042fcfc3f5a87fd
|
File details
Details for the file unsent-1.0.1-py3-none-any.whl.
File metadata
- Download URL: unsent-1.0.1-py3-none-any.whl
- Upload date:
- Size: 11.4 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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f72b43c6fce64f9f04d84cbf4ae1545a84f105f352d05ce3b283eb4c2a8c2dfb
|
|
| MD5 |
90d001bd991007d7b57ce238902f1251
|
|
| BLAKE2b-256 |
6456779cee41277b6df89766ce64e71af44380469319a945d873d3a26bbf5666
|