---
title: "Python SDK"
description: "The official Python client for the OpenEmail API. Sync and async, typed throughout, and one method for every endpoint."
url: "https://openemail.uk/docs/python"
area: "Python"
category: "Getting started"
---

# 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.

**Install**

_pip_

```bash
pip install openemail
```

_uv_

```bash
uv add openemail
```

_poetry_

```bash
poetry add openemail
```

**send_email.py**

```
import os

from openemail import init, openemail

init(os.environ['OPENEMAIL_API_KEY'])

openemail.emails.send({
    'from': 'Acme Billing <billing@acme.com>',
    'to': 'ada@example.com',
    '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`.

**send_email_async.py**

```
import asyncio

from openemail import AsyncOpenEmail

async def main() -> None:
    async with AsyncOpenEmail() as client:
        email = await client.emails.send({
            'from': 'Acme Billing <billing@acme.com>',
            'to': 'ada@example.com',
            '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

- [Install](https://openemail.uk/docs/python/install.md): Add it and send your first message.
- [Configuration](https://openemail.uk/docs/python/configuration.md): Every option, and what it refuses.
- [Async](https://openemail.uk/docs/python/async.md): The same methods, awaited, on asyncio or trio.
- [Send an email](https://openemail.uk/docs/python/emails/send.md): Every field on a message.
- [Threads](https://openemail.uk/docs/python/threads.md): Read, organise, snooze, attachments.
- [Pagination](https://openemail.uk/docs/python/pagination.md): One page, every page, or a stream of items.
- [Webhooks](https://openemail.uk/docs/python/webhooks/endpoints.md): Register an endpoint and verify it.
- [Frameworks](https://openemail.uk/docs/python/frameworks.md): Where the client lives in a web app or a worker.
- [Errors](https://openemail.uk/docs/python/errors.md): What raises, and how to narrow it.
- [Retries](https://openemail.uk/docs/python/retries.md): Why a retried send cannot duplicate.
- [Types](https://openemail.uk/docs/python/reference/types.md): A `TypedDict` for every body and response.
- [Every method](https://openemail.uk/docs/python/reference/methods.md): The complete list, one row each.

## 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.

- [API reference](https://openemail.uk/docs/api/overview.md): What each endpoint does, and how it fails.
