Skip to main content

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.

Metadata

Release files for seskit 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for seskit 0.1.0
File Size Uploaded Provenance
seskit-0.1.0.tar.gz 13.4 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for seskit 0.1.0
File Interpreter ABI Platform
seskit-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 32.3 kB

Release files / seskit-0.1.0.tar.gz

Download URL seskit-0.1.0.tar.gz
Size 13.4 kB
Tags Source
SHA-256 checksum
How to use checksums
fee0e5fef46e0babb3c40f46a6ca0673c9174de0c97593fd8c4366a6396b5be8
BLAKE2b-256 checksum
How to use checksums
2c3f3668b18211251070a7212aa3383183993d7bd73d0282e9328193078714d3
Upload date
Uploaded using Trusted Publishing?
What is 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}

Release files / seskit-0.1.0-py3-none-any.whl

Download URL seskit-0.1.0-py3-none-any.whl
Size 19.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6a33997c0d6b02b229ec710d24c267fb9b7980c55dc9cfc11ab68ffffec57c62
BLAKE2b-256 checksum
How to use checksums
2e76ec3311d3145b7a46a1dd160e82e01ec9acbb072011707463df3d11ac13ab
Upload date
Uploaded using Trusted Publishing?
What is 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}

Security for seskit 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page