---
title: "Files"
description: "`files.list`, `list_all`, `iterate`, `get`, `download`, `list_links`, `list_all_links`, `iterate_links`, `create_link`, `revoke_link`, `stats`, `upload`, `delete` and `delete_many`."
url: "https://openemail.uk/docs/python/files"
area: "Python"
category: "Mailbox"
---

# Files

`files.list`, `list_all`, `iterate`, `get`, `download`, `list_links`, `list_all_links`, `iterate_links`, `create_link`, `revoke_link`, `stats`, `upload`, `delete` and `delete_many`.

## Every method

**files.py**

```
from pathlib import Path

from openemail import openemail

page = openemail.files.list(kind='pdf', sort='largest')
file = page['items'][0]

Path(file['filename']).write_bytes(openemail.files.download(file['id']))

links = openemail.files.list_all_links(file['id'])
print([(link['url'], link['downloads']) for link in links])

stats = openemail.files.stats()
print(stats['totals']['files'], stats['uploaded']['bytes'])
```

Every file the mailbox holds, attachments sent and received and the files uploaded to it, the Files page of the app. `download` returns the whole file as `bytes`, the links are the download links a file went out as, with how often each was fetched, and `stats` is the Analytics tab.

`list`, `list_all` and `iterate` take `q`, `kind` and `sort`, and also `direction` (`inbound`, `outbound` or `uploaded`), `address`, the files of one address compared without regard to case, and `since` and `until`, a `datetime` or an ISO 8601 string. `since` includes its moment and `until` stops before it.

> Reading needs `files:read`, and uploading, deleting and publishing or revoking links need `files:write`, which includes `files:read`. A key made before files had scopes of their own was given the matching ones. A key limited to particular addresses or domains sees only the files on them.

## Public links

**links.py**

```
from openemail import openemail

uploads = openemail.files.list_all(direction='uploaded', since='2026-09-01')

file = uploads[0]

link = openemail.files.create_link(file['id'], domain='acme.com')
print(link['url'])

openemail.files.revoke_link(file['id'], link['id'])
```

`create_link` publishes a file at a public download link that opens with no sign-in and returns it. The link lives on the files host of `domain` when that domain has one, such as `files.acme.com`, else on the files host of the address the file belongs to, else on the API address. A file that came in or went out on a message is copied to public storage first, and a program or a script is refused with 422 `file_unshareable`.

> Each `create_link` makes a new link, so it is never retried after a lost answer: look for the link with `list_links` first. `revoke_link` stops a link for good, including in mail that already went out, and returns it, `revokedAt` set. Revoking one twice is safe, and an unknown link is a 404.

## Upload and delete

**upload.py**

```
from pathlib import Path

from openemail import openemail

upload = openemail.files.upload(
    Path('price-list.pdf').read_bytes(),
    filename='price-list.pdf',
    content_type='application/pdf',
)

if upload['deletable']:
    openemail.files.delete(upload['id'])

result = openemail.files.delete_many([
    'file_0c4e7a91d2b84f63a5e19b7d',
    'file_6bb640f5b99e47deb758f1f5',
])
for kept in result['kept']:
    print(kept['filename'], kept['reason'])
```

`upload` stores the bytes as they are, up to 100 MB, under `filename`, and returns the file, whose id a send attaches as `{'fileId': upload['id']}`. Pass `content_type`, or the bytes are stored as `application/octet-stream`. It is never retried, because a second attempt would store a second copy.

> Only an upload that nothing depends on can be deleted, and `deletable` and `usage` on each file say so ahead of time. `delete` refuses any other file with a 409 `file_in_use`. `delete_many` takes up to 100 ids, deletes what it can, and reports the rest in `kept`, each with its reason, and in `missing`.

> `upload` takes `bytes`, `bytearray` or `memoryview`. It waits at least 600 seconds for an answer, however short the client’s `timeout`, unless you pass `timeout=` to the call, and a blank `filename` raises `ValueError` before anything is sent.

## Reference

- [`files.list()`](https://openemail.uk/docs/python/reference/files#list): full reference
- [`files.list_all()`](https://openemail.uk/docs/python/reference/files#listAll): full reference
- [`files.iterate()`](https://openemail.uk/docs/python/reference/files#iterate): full reference
- [`files.get()`](https://openemail.uk/docs/python/reference/files#get): full reference
- [`files.download()`](https://openemail.uk/docs/python/reference/files#download): full reference
- [`files.list_links()`](https://openemail.uk/docs/python/reference/files#listLinks): full reference
- [`files.list_all_links()`](https://openemail.uk/docs/python/reference/files#listAllLinks): full reference
- [`files.iterate_links()`](https://openemail.uk/docs/python/reference/files#iterateLinks): full reference
- [`files.create_link()`](https://openemail.uk/docs/python/reference/files#createLink): full reference
- [`files.revoke_link()`](https://openemail.uk/docs/python/reference/files#revokeLink): full reference
- [`files.stats()`](https://openemail.uk/docs/python/reference/files#stats): full reference
- [`files.upload()`](https://openemail.uk/docs/python/reference/files#upload): full reference
- [`files.delete()`](https://openemail.uk/docs/python/reference/files#delete): full reference
- [`files.delete_many()`](https://openemail.uk/docs/python/reference/files#deleteMany): full reference
