seskit
The Python SDK for SESKit — a Python-native, self-hosted developer email platform built on Amazon SES.
What SESKit is
SESKit makes Amazon SES feel as simple as Resend, without giving up ownership of your sending infrastructure. You run it yourself, on your own AWS account: an HTTP API for sending, a dashboard for looking at what happened, delivery event ingestion from SNS, and signed outbound webhooks.
This package is the client, not the server. You run the server; your application installs this. The same distinction as a database and its driver.
Install
pip install seskit
Send
from seskit import SesKit
client = SesKit(api_key="sk_live_...", base_url="https://seskit.example.com")
sent = client.emails.send(
from_="hello@example.com",
to=["user@example.com"],
subject="Welcome",
html="<h1>Welcome!</h1>",
)
base_url is the address of your own instance. There is no default, because
there is no hosted SESKit to point at.
Read
email = client.emails.get(sent.id)
email.status # queued, sending, sent, failed
email.delivered_at # None until a delivery event arrives
page = client.emails.list(status="failed")
for email in page:
print(email.id, email.last_error)
list returns one page, newest first. Pass page.last_id as starting_after
while page.has_more.
Errors
Every refusal is a class, so you branch on the type rather than on the message:
from seskit import SuppressedRecipient, DomainNotVerified, SESKitError
try:
client.emails.send(...)
except SuppressedRecipient:
... # the address hard-bounced or complained; it is on your list
except DomainNotVerified:
... # the sender is not verified in SES
except SESKitError as error:
... # anything else; error.type and error.message say what
Async
The same surface, awaited — because a blocking HTTP call inside an async handler stops the event loop for every other request on that worker:
from seskit import AsyncSesKit
client = AsyncSesKit(api_key="sk_live_...", base_url="https://seskit.example.com")
sent = await client.emails.send(
from_="hello@example.com",
to=["user@example.com"],
subject="Welcome",
html="<h1>Welcome!</h1>",
)
Retries
Rate limits, 5xx responses and connection failures are retried with backoff,
honouring Retry-After. Refusals are not — asking again produces the same
refusal.
Every send carries an Idempotency-Key, generated per call unless you pass
one, so a retry after a timeout cannot deliver a second copy. Pass your own
(an order id, say) when you have something that identifies the send across
process restarts.
It is optional
The SDK is deliberately a thin client over the HTTP API. Business logic lives in the API and is never duplicated here, so a Python call and a curl command cannot disagree about what SESKit does.
The consequence is worth stating: this client can never do anything a curl
command cannot. Reaching for it is a convenience, never a requirement.
Licence
MIT. See LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
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
File details
Details for the file seskit-0.1.0.tar.gz.
File metadata
- Download URL: seskit-0.1.0.tar.gz
- Upload date:
- Size: 13.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.11.2 {"installer":{"name":"uv","version":"0.11.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fee0e5fef46e0babb3c40f46a6ca0673c9174de0c97593fd8c4366a6396b5be8
|
|
| MD5 |
d52c0a9b1eb8edacade5b4efdc487a4f
|
|
| BLAKE2b-256 |
2c3f3668b18211251070a7212aa3383183993d7bd73d0282e9328193078714d3
|
File details
Details for the file seskit-0.1.0-py3-none-any.whl.
File metadata
- Download URL: seskit-0.1.0-py3-none-any.whl
- Upload date:
- Size: 19.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.11.2 {"installer":{"name":"uv","version":"0.11.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6a33997c0d6b02b229ec710d24c267fb9b7980c55dc9cfc11ab68ffffec57c62
|
|
| MD5 |
0043c6a332d4356de5cd55ed06da8f1f
|
|
| BLAKE2b-256 |
2e76ec3311d3145b7a46a1dd160e82e01ec9acbb072011707463df3d11ac13ab
|