Python SDK
The official Python client for the OpenEmail API. Sync and async, typed throughout, and one method for every endpoint.
What it is
One package over the whole API (sending, templates, tracking, threads, drafts, labels, contacts, audiences, sign-up forms, broadcasts, domains, rules, webhooks, calendar, settings, roles, members, suppressions, files and disposable inboxes) with a TypedDict for every request and response, two error classes, retries that cannot duplicate a send, and a webhook signature verifier. It runs on Python 3.10 and newer and depends only on httpx, anyio and typing-extensions. It carries a workspace API key or an OAuth access token, so it belongs on a server or in a tool that runs on your own machine, and disposable inboxes are the one part that needs no credential.
pip install openemailimport os from openemail import init, openemail init(os.environ['OPENEMAIL_API_KEY']) openemail.emails.send({ 'from': 'Acme Billing <[email protected]>', 'to': '[email protected]', 'subject': 'Your September invoice', 'html': '<p>Invoice attached.</p>',})Sync and async
OpenEmail is synchronous, and AsyncOpenEmail is its asynchronous twin with the same options and the same methods, each one awaited. It runs on asyncio and trio, and a paginated iterate becomes an async for.
import asyncio from openemail import AsyncOpenEmail async def main() -> None: async with AsyncOpenEmail() as client: email = await client.emails.send({ 'from': 'Acme Billing <[email protected]>', 'to': '[email protected]', 'subject': 'Your September invoice', 'html': '<p>Invoice attached.</p>', }) async for thread in client.threads.iterate(folder='inbox'): print(thread['id']) print(email['id'], email['status']) asyncio.run(main())The shared openemail client is synchronous, so build an AsyncOpenEmail yourself, once, and close it with aclose() or an async with block.
Where to go
It wraps the same API as every other client
Everything here is the same surface the API reference documents, so read that for what an endpoint does and this for how to call it. There is one method for every documented operation, and the package's parity check reads the OpenAPI document to prove it.
Every TypeScript method has a Python twin under the same name in snake_case, and the parity check runs each pair with the same arguments and fails unless they send the same request, retry the same way and return the same value.