---
title: "openemail.temp_mail"
description: "Every method in this namespace: its signature, its parameters, what it returns and an example."
url: "https://openemail.uk/docs/python/reference/temp-mail"
area: "Python"
category: "Reference"
---

# openemail.temp_mail

Every method in this namespace: its signature, its parameters, what it returns and an example.

## Methods

Short lived inboxes that need no account, authorised by the token they were created with. `create_temp_mail()` builds a client for them that needs no API key, and `create_temp_mail(inbox_token=...)` one that holds an inbox's token for the calls that need it. On the `OpenEmail` client, pass `inbox_token=` to every call that reads or changes an inbox.

### `temp_mail.list_domains()`

List the domains a disposable inbox can be created on

```python
def list_domains(
    *,
    inbox_token: str | None = None,
    timeout: float | None = None,
) -> builtins.list[TempDomainResource]
```

Returns the pool of domains `create` accepts, as a plain list in the order the operator wrote them in `TEMP_MAIL_DOMAINS`. It takes no credential at all: no API key and no inbox token are sent, even when the client holding this namespace has one.

Nothing checks that a listed domain is verified, so the list is only as good as the operator made it. An empty list is a normal answer meaning this install offers no disposable domains, and it is exactly the condition under which `create` fails with 503 `not_configured`.

Sends no credential.

**Parameters**

- `inbox_token` (`str`): Accepted for symmetry with the other methods and never sent, because this call is anonymous.
- `timeout` (`float`): Seconds this call may take, the response included, before it raises `OpenEmailNetworkError` with `is_timeout`. It overrides the client's `timeout` for this call, and `0` turns the limit off.

**Returns**

`list[TempDomainResource]`, each a dict with `object` set to `'temp_domain'` and a lowercased `domain` to pass back to `create`.

**Example**

```python
from openemail import openemail

domains = openemail.temp_mail.list_domains()

print([entry['domain'] for entry in domains])
```

**Notes**

- The pool is server configuration, so a domain appears when the operator adds it to `TEMP_MAIL_DOMAINS`, not when it is added to a workspace.
- Retried automatically on network failure and retryable statuses, like every GET.

Also available in: API [`GET /temp-mail/domains`](https://openemail.uk/docs/api/reference/temp-mail#get-temp-mail-domains); TypeScript [`tempMail.listDomains()`](https://openemail.uk/docs/sdk/reference/temp-mail#listDomains); Ruby [`temp_mail.list_domains`](https://openemail.uk/docs/ruby/reference/temp-mail#listDomains); CLI [`openemail temp-mail list-domains`](https://openemail.uk/docs/cli/reference/temp-mail#temp-mail-list-domains).

### `temp_mail.create()`

Create a disposable inbox and its access token

```python
def create(
    body: TempInboxCreate | None = None,
    *,
    inbox_token: str | None = None,
    timeout: float | None = None,
) -> CreatedTempInboxResource
```

Mints a disposable address and returns the inbox plus its `token`. It needs no credential, and only this call and `extend` return a token. The token is the lease itself, signed, and nothing about it is stored on the server, so a lost token cannot be recovered, and every other method except `list_domains` needs it. Store it before you show the address to anyone.

The body is optional and so is every field in it. With nothing, you get a 12 character generated local part on the first domain in the pool, leased for 60 minutes. A chosen `localPart` is lowercased and must be up to 64 letters, digits, dots, dashes or underscores, starting and ending with a letter or digit, or it is 422 `invalid_address`, and one longer than 64 characters is 422 `invalid_parameter`. Names such as `postmaster`, `abuse` and `support` are 422 `reserved_address`, and an install with no pooled domain answers 503 `not_configured`.

Nothing is rate limited and nothing reserves an address, so this never answers 429 or 409. A name you choose is issued to anyone who asks for it, and each of you reads the mail that reaches it from the start of your own lease. Leave `localPart` out when the mail should reach you alone.

Sends no credential.

**Parameters**

- `body['domain']` (`str`): A domain from `list_domains`. Omit it for the first one in the pool. Any other name is 422 `unknown_domain` rather than a silent substitute.
- `body['localPart']` (`str`): The part before the @. Omit it for a generated one, which nobody else is likely to be issued.
- `body['ttlMinutes']` (`int`): Lease length from now, a whole number from 1 to 1440. Defaults to 60. Out of range is 422 `invalid_parameter`, not clamped.
- `inbox_token` (`str`): Ignored and never sent. Creating an inbox is anonymous and hands you the token instead.
- `timeout` (`float`): Seconds this call may take, the response included, before it raises `OpenEmailNetworkError` with `is_timeout`. It overrides the client's `timeout` for this call, and `0` turns the limit off.

**Returns**

`CreatedTempInboxResource`: the `TempInboxResource` fields `id`, `address`, `domain`, `createdAt`, `expiresAt`, `extensionsLeft`, `messageCount`, `messageLimit` and `lastMessageAt`, plus the one time `token` beginning `oe_inbox_`.

**Example**

```python
from openemail import openemail

inbox = openemail.temp_mail.create({'ttlMinutes': 120})

print(inbox['address'], inbox['expiresAt'])
print('Keep this token, it is the only way back in:', inbox['token'])
```

**Notes**

- Not retried automatically. A retry would mint a second inbox, and the first would be unreachable because its only token was in the lost response.
- Nothing holds an address back after its lease ends or its inbox is deleted, so it can be issued again at once, to anybody.
- A lease of 1440 minutes reaches the 24 hour ceiling at once, yet the inbox still comes back with 23 in `extensionsLeft`, because that counts calls rather than time. None of them can add a minute.
- Unknown body keys are 422 `invalid_parameter`, while a body that is not valid JSON is treated as an empty one.

Also available in: API [`POST /temp-mail/inboxes`](https://openemail.uk/docs/api/reference/temp-mail#post-temp-mail-inboxes); TypeScript [`tempMail.create()`](https://openemail.uk/docs/sdk/reference/temp-mail#create); Ruby [`temp_mail.create`](https://openemail.uk/docs/ruby/reference/temp-mail#create); CLI [`openemail temp-mail create`](https://openemail.uk/docs/cli/reference/temp-mail#temp-mail-create).

### `temp_mail.get()`

Read the lease and counters of a disposable inbox

```python
def get(
    inbox_id: str,
    *,
    inbox_token: str | None = None,
    timeout: float | None = None,
) -> TempInboxResource
```

Returns the inbox with its expiry, remaining extensions and message counters, without any messages. To watch an inbox, poll `list_messages` instead: it returns `expiresAt` alongside the mail, so one request covers both.

This call is authorised by the inbox token, never by an API key. A workspace key sent in its place is refused with 401 `missing_inbox_token`, and no scope on any key reaches this resource. The token alone decides which inbox is read, and the id in the path is not checked against it.

Once the lease is over the token answers 401 `inbox_expired`, and a token this server did not sign answers 404 `resource_not_found`. Deleting an inbox does not end its lease, so its token still reads it. `messageCount` is counted by reading every page, and is 0 when the install cannot read the mailbox that runs the pool.

Authenticates with an inbox token.

**Parameters**

- `inbox_id` (`str`, required): The `tinb_` id `create` returned. It is not checked against the token, which alone decides the inbox.
- `inbox_token` (`str`): The `oe_inbox_` token `create` returned. Overrides the token given to `create_temp_mail` for this call, and is required on the `OpenEmail` client, which would otherwise send its API key.
- `timeout` (`float`): Seconds this call may take, the response included, before it raises `OpenEmailNetworkError` with `is_timeout`. It overrides the client's `timeout` for this call, and `0` turns the limit off.

**Returns**

`TempInboxResource` with `id`, `address`, `domain`, `createdAt`, `expiresAt`, `extensionsLeft`, `messageCount`, `messageLimit` and `lastMessageAt`.

**Example**

```python
from openemail import openemail

created = openemail.temp_mail.create()

inbox = openemail.temp_mail.get(created['id'], inbox_token=created['token'])

print(inbox['expiresAt'], inbox['messageCount'], inbox['messageLimit'])
```

**Notes**

- A token that does not start with `oe_inbox_` is 401 `missing_inbox_token`, the same as no token at all. One that starts with it but was not signed by this server is 404 `resource_not_found`.
- `messageCount` counts every message the inbox is showing, across every page, and goes down when one is deleted. `messageLimit`, which is 50, is the page size of `list_messages`, not a ceiling: nothing past it is dropped.

Also available in: API [`GET /temp-mail/inboxes/{id}`](https://openemail.uk/docs/api/reference/temp-mail#get-temp-mail-inboxes-id); TypeScript [`tempMail.get()`](https://openemail.uk/docs/sdk/reference/temp-mail#get); Ruby [`temp_mail.get`](https://openemail.uk/docs/ruby/reference/temp-mail#get); CLI [`openemail temp-mail get`](https://openemail.uk/docs/cli/reference/temp-mail#temp-mail-get).

### `temp_mail.extend()`

Push the expiry of an inbox an hour further out

```python
def extend(
    inbox_id: str,
    *,
    inbox_token: str | None = None,
    timeout: float | None = None,
) -> ExtendedTempInboxResource
```

Adds up to 60 minutes to `expiresAt` and returns the updated inbox and a new `token` that carries the later expiry. There is no body. The old token keeps its old expiry, so use the new one from here on, in every `inbox_token=` and in any client built with `create_temp_mail(inbox_token=...)`.

The new expiry is the earlier of one hour past the current expiry and 24 hours after `createdAt`, and a lease allows at most 23 extensions. The last extension can buy less than an hour, and on a lease that already reaches the 24 hours a call still succeeds, spends an extension and buys nothing. `extensionsLeft` counts only the 23 calls, so compare `expiresAt` with `createdAt` before offering more time.

When `extensionsLeft` is 0 this answers 422 `extension_limit` for good, and the only way on is a new inbox. The response reads no mail, so its `messageCount` is 0 and its `lastMessageAt` is `None`.

Authenticates with an inbox token.

**Parameters**

- `inbox_id` (`str`, required): The `tinb_` id `create` returned. It is not checked against the token, which alone decides the inbox.
- `inbox_token` (`str`): The `oe_inbox_` token `create` returned. Overrides the token given to `create_temp_mail` for this call, and is required on the `OpenEmail` client, which would otherwise send its API key.
- `timeout` (`float`): Seconds this call may take, the response included, before it raises `OpenEmailNetworkError` with `is_timeout`. It overrides the client's `timeout` for this call, and `0` turns the limit off.

**Returns**

`ExtendedTempInboxResource`: the `TempInboxResource` fields with the new `expiresAt` and the updated `extensionsLeft`, plus the new `token` beginning `oe_inbox_`.

**Example**

```python
import os

from openemail import openemail

inbox = openemail.temp_mail.extend(
    'tinb_k7m2q9xw4bdp', inbox_token=os.environ['OPENEMAIL_INBOX_TOKEN']
)

print(inbox['expiresAt'], inbox['extensionsLeft'])

page = openemail.temp_mail.list_messages(inbox['id'], inbox_token=inbox['token'])

print(len(page['items']), 'messages so far')
```

**Notes**

- Not retried automatically, because a replay would spend a second extension.
- An inbox created with a `ttlMinutes` of 1440 still reports 23 in `extensionsLeft`, and none of them can add a minute.

Also available in: API [`POST /temp-mail/inboxes/{id}/extend`](https://openemail.uk/docs/api/reference/temp-mail#post-temp-mail-inboxes-id-extend); TypeScript [`tempMail.extend()`](https://openemail.uk/docs/sdk/reference/temp-mail#extend); Ruby [`temp_mail.extend`](https://openemail.uk/docs/ruby/reference/temp-mail#extend); CLI [`openemail temp-mail extend`](https://openemail.uk/docs/cli/reference/temp-mail#temp-mail-extend).

### `temp_mail.delete()`

Move the mail in a disposable inbox to the bin now

```python
def delete(
    inbox_id: str,
    *,
    inbox_token: str | None = None,
    timeout: float | None = None,
) -> DeletedTempInboxResource
```

Moves every message the inbox shows to the bin of the mailbox that runs the pool, at once. It does not end the lease: nothing about a lease is stored, so there is nothing to revoke, and the token keeps opening the address until its expiry. Mail that arrives afterwards is listed as usual.

Nothing holds the address back either, so it can be issued again at once, to anybody. An install with no key to read the pool answers 503 `not_configured`.

The response is a tombstone rather than an empty body, so a log line can name what went.

Authenticates with an inbox token.

**Parameters**

- `inbox_id` (`str`, required): The `tinb_` id `create` returned. It is not checked against the token, which alone decides the inbox.
- `inbox_token` (`str`): The `oe_inbox_` token `create` returned. Overrides the token given to `create_temp_mail` for this call, and is required on the `OpenEmail` client, which would otherwise send its API key.
- `timeout` (`float`): Seconds this call may take, the response included, before it raises `OpenEmailNetworkError` with `is_timeout`. It overrides the client's `timeout` for this call, and `0` turns the limit off.

**Returns**

`DeletedTempInboxResource`, a dict with `object` set to `'temp_inbox'`, the `id` and `'destroyed': True`.

**Example**

```python
from openemail import openemail

inbox = openemail.temp_mail.create()

result = openemail.temp_mail.delete(inbox['id'], inbox_token=inbox['token'])

print(result['id'], result['destroyed'])
```

**Notes**

- The flag is `destroyed`, not `deleted` as on other tombstones.
- Not retried automatically. Repeating it is harmless: the lease still stands, so a second call answers 200 and moves whatever has arrived since.

Also available in: API [`DELETE /temp-mail/inboxes/{id}`](https://openemail.uk/docs/api/reference/temp-mail#delete-temp-mail-inboxes-id); TypeScript [`tempMail.delete()`](https://openemail.uk/docs/sdk/reference/temp-mail#delete); Ruby [`temp_mail.delete`](https://openemail.uk/docs/ruby/reference/temp-mail#delete); CLI [`openemail temp-mail delete`](https://openemail.uk/docs/cli/reference/temp-mail#temp-mail-delete).

### `temp_mail.list_messages()`

List one page of the messages in a disposable inbox

```python
def list_messages(
    inbox_id: str,
    *,
    limit: int | None = None,
    cursor: str | None = None,
    inbox_token: str | None = None,
    timeout: float | None = None,
) -> TempMessagesResource
```

Returns one page of the messages in the inbox newest first, by the time the server received them, together with the inbox `expiresAt`. Rows carry metadata only, and polling this is the way to wait for a confirmation email. Only mail delivered to this address since the lease began is listed.

A page holds up to 50 messages. When more have arrived, `hasMore` is `True` and `nextCursor` goes back as `cursor=` for the next page, so nothing that reached the inbox is hidden; `list_all_messages` and `iterate_messages` do that walk for you. A page can hold fewer than `limit=` rows, even none, while `hasMore` is `True`, because mail to other addresses on the pool is read and dropped. `snippet` is plain text capped at 400 characters, which is often enough to read a one time code without opening the message.

`spam` is a flag, never a filing decision. A machine sent confirmation from a sender with no reputation is exactly what a disposable inbox exists to receive, so flagged messages are still listed. `from` is whatever the message claimed and has not been authenticated.

Authenticates with an inbox token.

**Parameters**

- `inbox_id` (`str`, required): The `tinb_` id `create` returned. It is not checked against the token, which alone decides the inbox.
- `limit` (`int`): Messages per page, a whole number from 1 to 50, defaulting to 50. Out of range is 422 `invalid_parameter`.
- `cursor` (`str`): The `nextCursor` from the previous page. Never build one yourself.
- `inbox_token` (`str`): The `oe_inbox_` token `create` returned. Overrides the token given to `create_temp_mail` for this call, and is required on the `OpenEmail` client, which would otherwise send its API key.
- `timeout` (`float`): Seconds this call may take, the response included, before it raises `OpenEmailNetworkError` with `is_timeout`. It overrides the client's `timeout` for this call, and `0` turns the limit off.

**Returns**

`TempMessagesResource`, a dict with `items`, a list of `TempMessageResource` (`id`, `from`, `to`, `subject`, `snippet`, `spam`, `seen`, `attachmentCount`, `sizeBytes`, `receivedAt`), `hasMore`, `nextCursor` and the inbox `expiresAt`.

**Example**

```python
import re
import time

from openemail import openemail

inbox = openemail.temp_mail.create()

for _ in range(30):
    page = openemail.temp_mail.list_messages(inbox['id'], inbox_token=inbox['token'], limit=10)
    matches = [re.search(r'\b\d{6}\b', message['snippet']) for message in page['items']]
    code = next((match.group() for match in matches if match), None)

    if code:
        print(code, 'arrived, and the inbox lasts until', page['expiresAt'])
        break

    time.sleep(2)
```

**Notes**

- A message whose `Message-ID` header matches one already in the inbox is not stored twice.
- `to` is the inbox address. A `+tag` the sender added is folded back into the base address.
- Every message the inbox has received is listed, a page at a time. `messageLimit` on the inbox is the size the tool is built for, not a point past which mail is hidden.
- An install with no key to read the pool answers 503 `not_configured`.

Also available in: API [`GET /temp-mail/inboxes/{id}/messages`](https://openemail.uk/docs/api/reference/temp-mail#get-temp-mail-inboxes-id-messages); TypeScript [`tempMail.listMessages()`](https://openemail.uk/docs/sdk/reference/temp-mail#listMessages); Ruby [`temp_mail.list_messages`](https://openemail.uk/docs/ruby/reference/temp-mail#listMessages); CLI [`openemail temp-mail list-messages`](https://openemail.uk/docs/cli/reference/temp-mail#temp-mail-list-messages).

### `temp_mail.list_all_messages()`

Collect every message in a disposable inbox into one list

```python
def list_all_messages(
    inbox_id: str,
    *,
    limit: int | None = None,
    cursor: str | None = None,
    inbox_token: str | None = None,
    timeout: float | None = None,
) -> builtins.list[TempMessageResource]
```

Follows `nextCursor` from page to page and returns every message the inbox has received in one list, newest first. Rows carry metadata only, as on `list_messages`.

Authenticates with an inbox token.

**Parameters**

- `inbox_id` (`str`, required): The `tinb_` id `create` returned.
- `limit` (`int`): Page size per request, from 1 to 50, defaulting to 50.
- `cursor` (`str`): A cursor from an earlier page to start after.
- `inbox_token` (`str`): The `oe_inbox_` token `create` returned, sent with every page.
- `timeout` (`float`): Seconds this call may take, the response included, before it raises `OpenEmailNetworkError` with `is_timeout`. It overrides the client's `timeout` for this call, and `0` turns the limit off.

**Returns**

`list[TempMessageResource]` holding every message across all pages.

**Example**

```python
from openemail import openemail

inbox = openemail.temp_mail.create()

messages = openemail.temp_mail.list_all_messages(inbox['id'], inbox_token=inbox['token'])

print(len(messages), [message['subject'] for message in messages])
```

**Notes**

- A failure on any page raises, and the messages already fetched are discarded.

Also available in: API [`GET /temp-mail/inboxes/{id}/messages`](https://openemail.uk/docs/api/reference/temp-mail#get-temp-mail-inboxes-id-messages); TypeScript [`tempMail.listAllMessages()`](https://openemail.uk/docs/sdk/reference/temp-mail#listAllMessages); Ruby [`temp_mail.list_all_messages`](https://openemail.uk/docs/ruby/reference/temp-mail#listAllMessages).

### `temp_mail.iterate_messages()`

Stream the messages in a disposable inbox one at a time

```python
def iterate_messages(
    inbox_id: str,
    *,
    limit: int | None = None,
    cursor: str | None = None,
    inbox_token: str | None = None,
    timeout: float | None = None,
) -> Iterator[TempMessageResource]
```

Returns a generator that yields the inbox messages individually, newest first, and requests the next page only once the current one is drained. Nothing is requested until you start iterating, and breaking out of the loop stops the requests.

Authenticates with an inbox token.

**Parameters**

- `inbox_id` (`str`, required): The `tinb_` id `create` returned.
- `limit` (`int`): Page size per request, from 1 to 50, defaulting to 50.
- `cursor` (`str`): A cursor from an earlier page to start after.
- `inbox_token` (`str`): The `oe_inbox_` token `create` returned, sent with every page.
- `timeout` (`float`): Seconds this call may take, the response included, before it raises `OpenEmailNetworkError` with `is_timeout`. It overrides the client's `timeout` for this call, and `0` turns the limit off.

**Returns**

`Iterator[TempMessageResource]`, a generator yielding one message per step.

**Example**

```python
import os
import re

from openemail import openemail

for message in openemail.temp_mail.iterate_messages(
    'tinb_k7m2q9xw4bdp', inbox_token=os.environ['OPENEMAIL_INBOX_TOKEN']
):
    code = re.search(r'\b\d{6}\b', message['snippet'])

    if code:
        print(code.group(), 'from', message['from']['email'])
        break
```

**Notes**

- The generator is lazy, so an abandoned loop costs only the pages you consumed.

Also available in: API [`GET /temp-mail/inboxes/{id}/messages`](https://openemail.uk/docs/api/reference/temp-mail#get-temp-mail-inboxes-id-messages); TypeScript [`tempMail.iterateMessages()`](https://openemail.uk/docs/sdk/reference/temp-mail#iterateMessages); Ruby [`temp_mail.iterate_messages`](https://openemail.uk/docs/ruby/reference/temp-mail#iterateMessages).

### `temp_mail.get_message()`

Read one message with its stored body

```python
def get_message(
    inbox_id: str,
    message_id: str,
    *,
    inbox_token: str | None = None,
    timeout: float | None = None,
) -> TempMessageDetailResource
```

Returns the list row for one message plus the parsed message as stored. Reading it does not mark it seen: `seen` mirrors the unread state of the message in the mailbox that runs the pool, and nothing on these routes changes it.

Render `decodedBody` from `message`. Its `body` and `processedHtml` are empty strings for every message that can reach a disposable inbox, so a client reading either shows a blank page. The body is never cut, so `truncated` is always `False`.

The HTML came from a stranger to an address anyone could name. Treat it as hostile, and show it away from your own site's origin, for example in a sandboxed iframe.

Authenticates with an inbox token.

**Parameters**

- `inbox_id` (`str`, required): The `tinb_` id `create` returned. It is not checked against the token, which alone decides the inbox.
- `message_id` (`str`, required): An `id` from `list_messages`, such as `thr_` and 24 hex.
- `inbox_token` (`str`): The `oe_inbox_` token `create` returned. Overrides the token given to `create_temp_mail` for this call, and is required on the `OpenEmail` client, which would otherwise send its API key.
- `timeout` (`float`): Seconds this call may take, the response included, before it raises `OpenEmailNetworkError` with `is_timeout`. It overrides the client's `timeout` for this call, and `0` turns the limit off.

**Returns**

`TempMessageDetailResource`: every `TempMessageResource` field plus `message`, the stored parsed message, and `truncated`.

**Example**

```python
import os

from openemail import openemail

detail = openemail.temp_mail.get_message(
    'tinb_k7m2q9xw4bdp',
    'thr_9e3b7c1a5f2d8e40b6a9c3f1',
    inbox_token=os.environ['OPENEMAIL_INBOX_TOKEN'],
)
body = detail['message'].get('decodedBody')

print(detail['subject'], detail['from']['email'], detail['truncated'])

if isinstance(body, str):
    print(body)
```

**Notes**

- A message this lease cannot see, deleted ones included, is 404 `resource_not_found`. An expired lease is 401 `inbox_expired`, and an install with no key to read the pool answers 503 `not_configured`.
- `message` is a `MessageResource`, which is a plain `dict[str, Any]`, so check that `decodedBody` is a `str` before rendering it.

Also available in: API [`GET /temp-mail/inboxes/{id}/messages/{messageId}`](https://openemail.uk/docs/api/reference/temp-mail#get-temp-mail-inboxes-id-messages-messageid); TypeScript [`tempMail.getMessage()`](https://openemail.uk/docs/sdk/reference/temp-mail#getMessage); Ruby [`temp_mail.get_message`](https://openemail.uk/docs/ruby/reference/temp-mail#getMessage); CLI [`openemail temp-mail get-message`](https://openemail.uk/docs/cli/reference/temp-mail#temp-mail-get-message).

### `temp_mail.delete_message()`

Delete one message from a disposable inbox

```python
def delete_message(
    inbox_id: str,
    message_id: str,
    *,
    inbox_token: str | None = None,
    timeout: float | None = None,
) -> DeletedTempMessageResource
```

Moves the message, attachments and all, to the bin of the mailbox that runs the pool, and no lease lists or opens it again. Nothing in this SDK restores it.

`messageCount` goes down by one. There is never a slot to free: an inbox keeps every message that reaches it, and `list_messages` pages through all of them.

Authenticates with an inbox token.

**Parameters**

- `inbox_id` (`str`, required): The `tinb_` id `create` returned. It is not checked against the token, which alone decides the inbox.
- `message_id` (`str`, required): An `id` from `list_messages`, such as `thr_` and 24 hex.
- `inbox_token` (`str`): The `oe_inbox_` token `create` returned. Overrides the token given to `create_temp_mail` for this call, and is required on the `OpenEmail` client, which would otherwise send its API key.
- `timeout` (`float`): Seconds this call may take, the response included, before it raises `OpenEmailNetworkError` with `is_timeout`. It overrides the client's `timeout` for this call, and `0` turns the limit off.

**Returns**

`DeletedTempMessageResource`, a dict with `object` set to `'temp_message'`, the message `id` and `'deleted': True`.

**Example**

```python
import os

from openemail import openemail

deleted = openemail.temp_mail.delete_message(
    'tinb_k7m2q9xw4bdp',
    'thr_9e3b7c1a5f2d8e40b6a9c3f1',
    inbox_token=os.environ['OPENEMAIL_INBOX_TOKEN'],
)

print(deleted['id'], deleted['deleted'])
```

**Notes**

- An unknown or already deleted message id is 404 `resource_not_found`, and an install with no key to read the pool answers 503 `not_configured`.
- Not retried automatically. If you repeat it yourself after a lost response, that 404 means the first attempt already worked.

Also available in: API [`DELETE /temp-mail/inboxes/{id}/messages/{messageId}`](https://openemail.uk/docs/api/reference/temp-mail#delete-temp-mail-inboxes-id-messages-messageid); TypeScript [`tempMail.deleteMessage()`](https://openemail.uk/docs/sdk/reference/temp-mail#deleteMessage); Ruby [`temp_mail.delete_message`](https://openemail.uk/docs/ruby/reference/temp-mail#deleteMessage); CLI [`openemail temp-mail delete-message`](https://openemail.uk/docs/cli/reference/temp-mail#temp-mail-delete-message).

### `temp_mail.list_attachments()`

List the attachments of a message, metadata only

```python
def list_attachments(
    inbox_id: str,
    message_id: str,
    *,
    inbox_token: str | None = None,
    timeout: float | None = None,
) -> builtins.list[TempAttachmentResource]
```

Returns every attachment on a message as a plain list of metadata: `attachmentId`, `filename`, `mimeType` and `size` in decoded bytes, with `body` an empty string and `headers` empty. No route on a disposable inbox serves the bytes, and there is no per attachment fetch.

`filename` and `mimeType` are whatever the sender declared, and nothing here is scanned. A message this lease cannot see is 404 `resource_not_found`, and an install with no key to read the pool answers 503 `not_configured`.

Authenticates with an inbox token.

**Parameters**

- `inbox_id` (`str`, required): The `tinb_` id `create` returned. It is not checked against the token, which alone decides the inbox.
- `message_id` (`str`, required): An `id` from `list_messages`, such as `thr_` and 24 hex.
- `inbox_token` (`str`): The `oe_inbox_` token `create` returned. Overrides the token given to `create_temp_mail` for this call, and is required on the `OpenEmail` client, which would otherwise send its API key.
- `timeout` (`float`): Seconds this call may take, the response included, before it raises `OpenEmailNetworkError` with `is_timeout`. It overrides the client's `timeout` for this call, and `0` turns the limit off.

**Returns**

`list[TempAttachmentResource]`, each a dict with `attachmentId`, `filename`, `mimeType`, `size` in decoded bytes, `body` as an empty string and `headers` as an empty list.

**Example**

```python
import os

from openemail import openemail

attachments = openemail.temp_mail.list_attachments(
    'tinb_k7m2q9xw4bdp',
    'thr_9e3b7c1a5f2d8e40b6a9c3f1',
    inbox_token=os.environ['OPENEMAIL_INBOX_TOKEN'],
)

for attachment in attachments:
    print(attachment['filename'], attachment['mimeType'], attachment['size'])
```

**Notes**

- Listing attachments does not mark the message seen.
- Check `attachmentCount` from `list_messages` first to skip this call for messages with none.

Also available in: API [`GET /temp-mail/inboxes/{id}/messages/{messageId}/attachments`](https://openemail.uk/docs/api/reference/temp-mail#get-temp-mail-inboxes-id-messages-messageid-attachments); TypeScript [`tempMail.listAttachments()`](https://openemail.uk/docs/sdk/reference/temp-mail#listAttachments); Ruby [`temp_mail.list_attachments`](https://openemail.uk/docs/ruby/reference/temp-mail#listAttachments); CLI [`openemail temp-mail list-attachments`](https://openemail.uk/docs/cli/reference/temp-mail#temp-mail-list-attachments).
