---
title: "Types and helpers"
description: "What else the package exports."
url: "https://openemail.uk/docs/python/reference/types"
area: "Python"
category: "Reference"
---

# Types and helpers

What else the package exports.

## Runtime exports

| Export | What it is |
| --- | --- |
| `init`, `openemail` | Configure the shared client once, then import `openemail` anywhere. It builds itself from `OPENEMAIL_API_KEY` if `init` never ran. |
| `get_client`, `reset_client` | The shared client itself, and a way to drop it so the next call builds a fresh one, which is what a test wants between cases. |
| `OpenEmail`, `create_client` | A separate client. `OpenEmail()` reads the environment for anything you leave out, and `create_client` is another name for it. |
| `AsyncOpenEmail` | The same client with every method awaited, on asyncio or trio. |
| `create_temp_mail`, `create_async_temp_mail` | A disposable-inbox client that carries no API key, and its async twin. |
| `OpenEmailError`, `OpenEmailApiError`, `OpenEmailNetworkError`, `WebhookVerificationError` | The errors the package raises, all under `OpenEmailError`. An `OpenEmailApiError` carries the parsed error response as `body`, and `fields` when a form sign-up was refused. |
| `verify_webhook_signature` | Constant-time, with a replay window. Returns the parsed payload and raises `WebhookVerificationError` on any failure. |
| `to_base64` | Base64 for attachment bytes, from `bytes`, `bytearray` or `memoryview`. |
| `is_api_key` | Whether a string has the `oe_live_` or `oe_test_` shape. A shape check, not proof the key still works. |
| `is_access_token` | Whether a string has the shape of an OAuth access token: 1 to 512 characters, not beginning `oe_`. |
| `is_sealed`, `MESSAGE_ENCRYPTION_FORMATS` | Whether a message’s body is ciphertext, and the five envelopes ingest can name. `is_sealed` is false for the two SIGNED formats, whose bodies arrived in the clear, which is why it ships rather than being left to a caller to derive from the union. |
| `LANGUAGES`, `resolve_language`, `language_by_code`, `is_rtl_language` | The bundled language table, and the lookups a language picker needs. |
| `API_SCOPES` | The scope vocabulary, for a key-creation screen. |
| `WEBHOOK_EVENTS`, `WEBHOOK_SIGNATURE_HEADERS` | The events an endpoint can subscribe to, and the names of the headers a delivery carries. |
| `RULE_FIELDS`, `RULE_OPERATORS`, `RULE_ACTIONS` | The vocabulary a rule’s conditions and actions are built from. |
| `PAGE_LIMITS` | The largest and the default `limit` on most paged lists: 100 and 25. `contacts.list`, `audiences.list_contacts` and the `tracking` lists take up to 200 with a default of 50, and `temp_mail.list_messages` takes up to 50. |
| `ERROR_TYPES` | The frozen error vocabulary. |
| `VERSION`, `__version__` | The package version. |
| `THREAD_SORTS`, `PEOPLE_SORTS`, `CONTACT_THREAD_SORTS`, `FILE_SORTS` | The orders the thread, people, contact thread and file lists can be sorted in. |
| `FILE_KINDS`, `FILE_DIRECTIONS`, `CONTACT_BLOCK_LISTS`, `CONTACT_PHOTO_TYPES` | The filters of the file list, the two workspace blocklists, and the image types a contact photo can be. |
| `BROADCAST_STATUSES`, `BROADCAST_RECIPIENT_FILTERS`, `SUPPRESSION_REASONS`, `WEBHOOK_REPLAY_ERROR_CODES` | Where a broadcast stands, which of its copies to list, why an address is suppressed, and why a webhook replay was refused. |
| `PROVIDER_IMPORT_RESOURCES`, `PROVIDER_IMPORT_STATUSES`, `PROVIDER_IMPORT_DOMAIN_STATES` | What a provider import can bring across, where a run stands, and where each domain it found stands. |
| `FILE_USAGES` | Why a file is kept rather than deletable: `received`, `sent`, `linked` or `scheduled`. |
| `CREDENTIAL_KINDS`, `STEP_UP_METHODS`, `STEP_UP_ERROR_CODES` | Which credential `me.get()` and `me.ping()` describe (`apiKey` or `oauth`), how a verification code is checked (`email` or `totp`), and the codes a verification can fail with. |
| `FORM_STATUSES`, `FORM_SUBMISSION_STATUSES`, `FORM_FIELD_TYPES`, `FORM_STARTER_SLUGS`, `FORM_*` | The values a form, its fields and its sign-ups take, in sixteen sets: statuses, field types, starters, fonts, widths, and the reasons an answer is refused. |
| `BILLING_*`, `BRAND_*`, `DNS_*`, `DOMAIN_*` and the other sets | The values of every other namespace, each set named after what it holds. |

## Types

Every request and response has one, a `TypedDict` in `openemail.types` with the same name as its TypeScript twin. `…Resource` is what the API returns, and `…Create`, `…Patch`, `…Input` and `…Send` are what you pass. Filters and per-call options are keyword arguments, so the TypeScript types that carry them, such as `EmailListOptions`, have no twin here.

**typed.py**

```
from openemail.types import EmailSend, Page, SentEmailResource, ThreadSummaryResource

message: EmailSend = {
    'from': 'Acme Billing <billing@acme.com>',
    'to': 'ada@example.com',
    'replyTo': 'billing-help@acme.com',
    'subject': 'Your September invoice',
    'text': 'Your invoice is attached.',
}

sent: SentEmailResource = client.emails.send(message)
inbox: Page[ThreadSummaryResource] = client.threads.list(folder='inbox')

print(sent['status'], sent['scheduledAt'], inbox['nextCursor'])
```

Keys are the API’s own camelCase field names, such as `'replyTo'`, `'scheduledAt'` and `'nextCursor'`, in what you send and in what comes back. Only the arguments of a method are snake_case (`idempotency_key=`, `label_ids=`), and an argument that would be called `from` is `from_=`, as on `emails.list` and `calendar.list_events`.

mypy and pyright both read them, so a misspelt key fails the type check instead of reaching the API. mypy reports `Extra key "replyto" for TypedDict "EmailSend"` for a body and `TypedDict "SentEmailResource" has no key "satus"` for a response, and pyright says the same in its own words. A value outside a set fails the same way, such as `status='sending-ish'` on `emails.list`.

> They exist for your type checker. At runtime each `TypedDict` is a plain `dict`, so importing one costs nothing and nothing is checked while the program runs.

- Client: `Page`, `ApiKeyMode`, `RawBody`. `openemail.types.client` adds `AccessTokenProvider`, `AsyncAccessTokenProvider`, `HeaderValue` and `QueryValue`.
- Errors: `ErrorType`, `FormFieldProblem`.
- Emails: `EmailSend`, `EmailTranslate`, `EmailResource`, `SentEmailResource`, `EmailRecipientResource`, `EmailEventResource`, `EmailStatus`, `EmailSource`, `EmailTransport`, `EmailTrackingSummary`, `EmailTranslationResource`, `TranslationResource`, `RecipientStatus`, `BatchItemResource`, `BatchResultResource`.
- Templates: `TemplateCreate`, `TemplatePatch`, `TemplateContent`, `TemplatePreviewInput`, `TemplateSend`, `TemplateResource`, `TemplateDetailResource`, `TemplateVersionResource`, `TemplatePreviewResource`, `TemplateSendsResource`, `SentTemplateEmailResource`, `DeletedTemplateResource`, `TemplateEngine`, `TemplateProp`, `TemplateSlot`, `TemplateStatus`, `TemplateValueKind`.
- Tracking: `TrackingResource`, `TrackingSummary`, `TrackingRecipientResource`, `TrackingLinkResource`, `TrackingOpenResource`, `TrackingClickResource`, `TrackingStatsResource`, `TrackingGrain`.
- Threads and drafts: `ThreadPatch`, `ThreadResource`, `ThreadSummaryResource`, `UpdatedThreadResource`, `TrashedThreadResource`, `SnoozedThreadResource`, `DraftInput`, `DraftResource`, `DraftSummaryResource`, `SavedDraftResource`, `DeletedDraftResource`.
- Labels, contacts, domains and addresses: `LabelInput`, `LabelColor`, `LabelResource`, `DeletedLabelResource`, `ContactCreate`, `ContactPatch`, `ContactSource`, `ContactResource`, `ContactDetailResource`, `ContactAudienceResource`, `ContactAudiencesSet`, `DeletedContactResource`, `PeoplePage`, `PersonResource`, `DomainPatch`, `DomainResource`, `DomainDetailResource`, `DomainSendingState`, `DomainTracking`, `DomainTrackingState`, `AddressBookPage`, `AddressBookResource`, `AddressResource`, `SendableDomainResource`.
- Audiences: `AudienceCreate`, `AudiencePatch`, `AudienceMemberSort`, `AudienceContactAdd`, `AudienceContactsBatch`, `AudienceImport`, `AudienceImportRow`, `AudienceResource`, `AudienceBuiltin`, `AudienceContactResource`, `AudienceMemberResource`, `RemovedAudienceContactResource`, `DeletedAudienceResource`, `EmptiedAudienceResource`, `AudienceBatchAddResource`, `AudienceBatchRemoveResource`, `AudienceImportResource`, `AudienceGrowthResource`, `AudienceGrowthTotals`, `AudienceGrowthSeries`, `AudienceGrowthBucket`.
- Broadcasts: `BroadcastCreate`, `BroadcastPreviewInput`, `BroadcastResource`, `BroadcastCounts`, `BroadcastStatus`, `BroadcastPreviewResource`, `BroadcastRecipientResource`, `BroadcastRecipientContentResource`, `BroadcastRecipientFilter`, `BroadcastStatsResource`, `BroadcastStatsTotals`, `BroadcastStatsBucket`.
- Rules: `RuleCreate`, `RulePatch`, `RuleTestInput`, `RuleResource`, `RuleRunResource`, `RuleTestResource`, `DeletedRuleResource`, `RuleCondition`, `RuleConditionInput`, `RuleAction`, `RuleActionType`, `RuleField`, `RuleOperator`.
- Webhooks: `WebhookCreate`, `WebhookPatch`, `WebhookResource`, `CreatedWebhookResource`, `DeletedWebhookResource`, `WebhookDeliveryResource`, `WebhookDeliveryDetailResource`, `WebhookDeliveryAttempt`, `WebhookReplayResource`, `WebhookReplayRefusal`, `WebhookReplayErrorCode`, `WebhookTestResource`, `WebhookEvent`, `WebhookPayload`, `EmailOpenedData`, `EmailClickedData`, `EmailDownloadedData`, `FileEventData`.
- Calendar and settings: `CalendarOccurrenceResource`, `CalendarEventResource`, `CalendarAttendeeResource`, `SettingsPatch`, `SettingsResource`.
- Roles, members and keys: `RoleCreate`, `RolePatch`, `RoleResource`, `DeletedRoleResource`, `PermissionResource`, `MemberAdd`, `MemberPatch`, `MemberAddressGrant`, `MemberResource`, `MemberAddressResource`, `RemovedMemberResource`, `MemberAccess`, `KeyResource`, `PingResource`.
- Disposable inboxes: `TempInboxCreate`, `TempInboxResource`, `CreatedTempInboxResource`, `DeletedTempInboxResource`, `TempDomainResource`, `TempMessageResource`, `TempMessagesResource`, `TempMessageDetailResource`, `DeletedTempMessageResource`.
- Shared: `RecipientInput`, `AttachmentInput`, `AttachmentResource`, `MessageResource`, `MessageEncryption`, `MessageEncryptionFormat`, `TrackingRequest`, `TranslateOptions`, `SendTranslateOptions`, `LanguageResource`, `ApiScope`, `Permission`, `BuiltinRole`, `HitKind`.
- Access tokens and verification codes: `CredentialKind`, `ApiKeySelfResource`, `OauthTokenSelfResource`, `ApiKeyPingResource`, `OauthTokenPingResource`, `StepUpBegin`, `StepUpVerify`, `StepUpMethod`, `StepUpErrorCode`, `StepUpStatusResource`, `StepUpChallengeResource`, `StepUpVerifiedResource`.
- Forms: `FormCreate`, `FormPatch`, `FormResource`, `FormDetailResource`, `FormDocument`, `FormField`, `FormCopy`, `FormStyle`, `FormSettings`, `FormSettingsInput`, `FormStats`, `FormAudience`, `FormStarterResource`, `FormStarterDetailResource`, `FormAnalyticsResource`, `FormSubmissionResource`, `FormAnswer`, `ResentFormConfirmationResource`, `FormSubscribeValues`, `FormSubscriptionResource`, `FormSubmittedEventData`, `FormConfirmedEventData`.
- Everything else the API returns, from billing to workspaces, has its types under the same names.

## String sets

The value sets are constants in `openemail.constants`, each named after what it holds, with an attribute for each value: `EMAIL_STATUSES.SENT` is `'sent'`. Iterate one for every value, check a value that came from outside with `in`, and count them with `len()`. Each member is typed `Final`, so mypy and pyright read `EMAIL_STATUSES.SENT` as the literal `'sent'` and accept it wherever an `EmailStatus` is expected.

**constants.py**

```
from openemail import PAGE_LIMITS, WEBHOOK_EVENTS
from openemail.constants import EMAIL_STATUSES

failed = client.emails.list(status=EMAIL_STATUSES.FAILED, limit=PAGE_LIMITS.MAX_LIMIT)

print(EMAIL_STATUSES.SENT, list(EMAIL_STATUSES), len(WEBHOOK_EVENTS))
print('email.opened' in WEBHOOK_EVENTS, len(failed['items']))
```

`openemail` itself exports 108 constants: `VERSION`, `LANGUAGES`, `PAGE_LIMITS`, `PAY_AS_YOU_GO_LIMITS_CENTS` and 104 of the sets, the ones an application reaches for most. Import the others, such as `EMAIL_STATUSES` and `TEMPLATE_STATUSES`, from `openemail.constants`, where every set lives.

## An endpoint this does not wrap yet

An SDK release should never be what stands between you and an endpoint that already works. `client.raw.request()` takes a path and keyword arguments and returns the parsed body, with the client’s credential, base URL, timeout and retry policy applied.

**escape_hatch.py**

```
result = client.raw.request(
    '/something-new',
    method='POST',
    query={'dryRun': True},
    body={'name': 'Invoices'},
    repeatable=True,
)

print(result)
```

> A GET is retried like any other read. Any other method is sent once unless you pass `repeatable=True`, which is your assertion that it may be sent twice. `query` skips values that are `None` or empty, and `api_key=` and `timeout=` work as they do on every other method. On `AsyncOpenEmail` the call is awaited.

> The path must begin with a single `/`. Anything else, and a path whose finished URL would leave the API origin, raises `ValueError` before a request is sent, so the credential never reaches another host.

## What it deliberately does not do

- It validates no request body. The server's schema is the only copy of the rules, and a second copy here would eventually refuse an address a newer server accepts, in a version somebody pinned two years ago.
- It depends on `httpx`, `anyio` and `typing-extensions`, and on nothing else.
- On the way out it converts only what JSON cannot carry as it is: `bytes` in an attachment’s `content` become base64, a `datetime` becomes an ISO 8601 instant in UTC, a `date` an ISO date and a `set` a list. A lone recipient in `to`, `cc` or `bcc` is wrapped in a list.
- It reshapes a response in one way only: a collection’s `data` array is lifted out of its envelope. A paged list hands it back as `items` beside `hasMore` and `nextCursor`, `contacts.list_people` as `items` beside `hasMore`, `nextCursor` and `seen`, `emails.send_batch` as `items` beside `sent` and `failed`, `templates.list_sends` as `items` beside `total`, `page` and `pageSize`, `temp_mail.list_messages` as `items` beside `hasMore`, `nextCursor` and `expiresAt`, and `addresses.list` as `addresses` beside `unrestricted`, `domains`, `hasMore` and `nextCursor`. `imports.list_failures` is the one list left as the API sends it, `{'object': ..., 'data': [...], 'nextCursor': ...}`. Everywhere else it is a plain list. Every resource inside keeps the documented HTTP shape.

> The package’s parity check keeps this honest. It runs every method beside its TypeScript twin, with the same arguments and with every option set, and fails when a method is missing, takes different options, sends a different request or returns a different value.
