Перейти к документации
Python

Пагинация

`list` для одной страницы, `list_all` для всех страниц и `iterate` для обхода по одному элементу.

Одна страница: list

list_page.py
cursor: str | None = None while True:    page = client.emails.list(status='failed', limit=50, cursor=cursor)     for email in page['items']:        print(email['id'], email['lastError'])     if not page['hasMore'] or page['nextCursor'] is None:        break     cursor = page['nextCursor']

Страница имеет вид {'items': [...], 'hasMore': ..., 'nextCursor': ...}. Передайте nextCursor обратно как cursor=, с теми же фильтрами, чтобы получить следующую страницу.

nextCursor равен None на последней странице, а hasMore говорит, есть ли за этой страницей ещё подходящие строки. В openemail.types страница имеет тип Page[T], так что emails.list возвращает Page[EmailResource], и средство проверки типов знает, что содержит каждый элемент.

API листает цепочки и черновики с помощью pageToken. Клиент отдаёт его вам как nextCursor и принимает обратно как cursor=, как и в любом другом списке, а list_all и iterate следуют за ним сами. Он непрозрачен: передавайте обратно то, что получили, и никогда не составляйте его сами.

Все страницы: list_all

list_all.py
complaints = client.suppressions.list_all(reason='complaint')print(len(complaints), [row['email'] for row in complaints]) book = client.addresses.list_all()print(book['unrestricted'], len(book['addresses']), len(book['domains']))

list_all следует за nextCursor до последней страницы и возвращает один list. Все страницы запрашиваются до того, как он вернёт результат, поэтому дайте ему фильтр, у которого есть конец.

addresses.list_all единственный возвращает нечто иное: всю адресную книгу, {'unrestricted': ..., 'addresses': [...], 'domains': [...]}, с адресами всех страниц внутри.

По одному: iterate

iterate.py
from itertools import islice for email in client.emails.iterate(status='bounced'):    if email['createdAt'] < '2026-09-01':        break     print(email['id'], email['lastError']) first_ten = list(islice(client.threads.iterate(folder='inbox'), 10))print([thread['id'] for thread in first_ten])

iterate возвращает генератор. Сам вызов ничего не отправляет: первая страница запрашивается, когда цикл просит первый элемент, а каждая следующая только тогда, когда цикл доходит до конца предыдущей. Выход из цикла или срез через itertools.islice прекращает запросы.

limit= у list_all и iterate задаёт размер каждой запрашиваемой страницы, а не предел числа получаемых элементов, так что больший limit означает меньше запросов. cursor= начинает обход со страницы, которая у вас уже есть. Оба останавливаются, когда hasMore ложно или nextCursor равен None, а также когда страница называет тот же курсор, которым её получили, так что сбойная страница не может зациклить обход навсегда.

Списки внутри пространства имён

list_all и iterate листают тот же эндпоинт, что и стоящий рядом list, как и другие пары, названные по списку, который они проходят. Каждая пара принимает те же фильтры, что и её список.

Пространство имёнОдна страницаВсе страницыПо одному
emailslist_eventslist_all_eventsiterate_events
calendarlist_eventslist_all_eventsiterate_events
templateslist_versionslist_all_versionsiterate_versions
templateslist_imageslist_all_imagesiterate_images
trackinglist_openslist_all_opensiterate_opens
trackinglist_clickslist_all_clicksiterate_clicks
ruleslist_runslist_all_runsiterate_runs
audienceslist_contactslist_all_contactsiterate_contacts
broadcastslist_recipientslist_all_recipientsiterate_recipients
contactslist_peoplelist_all_peopleiterate_people
contactslist_threadslist_all_threadsiterate_threads
domainslist_addresseslist_all_addressesiterate_addresses
formslist_submissionslist_all_submissionsiterate_submissions
memberslist_invitationslist_all_invitationsiterate_invitations
fileslist_linkslist_all_linksiterate_links
temp_maillist_messageslist_all_messagesiterate_messages
webhookslist_deliverieslist_all_deliveriesiterate_deliveries
webhookslist_workspace_deliverieslist_all_workspace_deliveriesiterate_workspace_deliveries
webhookslist_activitylist_all_activityiterate_activity
webhookslist_workspace_activitylist_all_workspace_activityiterate_workspace_activity
keyslist_requestslist_all_requestsiterate_requests
keyslist_activitylist_all_activityiterate_activity
keyslist_workspace_requestslist_all_workspace_requestsiterate_workspace_requests
keyslist_workspace_activitylist_all_workspace_activityiterate_workspace_activity

Страницы с дополнительными полями

other_pages.py
people = client.contacts.list_people(sort='recent', limit=50)print(len(people['items']), people['seen'], people['nextCursor']) sends = client.templates.list_sends('order-shipped', page=2, page_size=50)print(sends['total'], sends['page'], sends['pageSize'], len(sends['items']))

Несколько списков несут больше, чем страницу. contacts.list_people добавляет seen рядом с items, hasMore и nextCursor, temp_mail.list_messages добавляет expiresAt, а addresses.list возвращает addresses вместо items, рядом с unrestricted, domains, hasMore и nextCursor. Каждый из них по-прежнему продолжается через cursor= и обходится своими list_all и iterate.

Два списка листаются иначе. templates.list_sends считает страницы: передайте page= и page_size= и читайте total, page и pageSize рядом с items. imports.list_failures оставлен в том виде, в каком его присылает API, {'object': 'list', 'data': [...], 'nextCursor': ...}, и продолжается через after=, число из nextCursor. Ни у одного из них нет list_all или iterate.

Размеры страниц

Большинство списков принимают limit= от 1 до 100, по умолчанию 25: это два числа из PAGE_LIMITS (PAGE_LIMITS.MAX_LIMIT и PAGE_LIMITS.DEFAULT_LIMIT). contacts.list, audiences.list_contacts, broadcasts.list_recipients и списки tracking принимают до 200, по умолчанию 50, а temp_mail.list_messages до 50. Значение вне диапазона отклоняется с 422, а не подрезается до границы.

В AsyncOpenEmail

Асинхронный клиент листает так же. list и list_all вызываются через await, а iterate возвращает асинхронный итератор, который вы обходите через async for, без await перед вызовом.

async_pages.py
import asyncio from openemail import AsyncOpenEmail  async def main() -> None:    async with AsyncOpenEmail() as client:        page = await client.emails.list(status='failed', limit=50)        print(len(page['items']), page['nextCursor'])         everyone = await client.members.list_all()        print(len(everyone))         async for delivery in client.webhooks.iterate_deliveries('whe_…', status='failed'):            print(delivery['eventType'], delivery['responseCode'])  asyncio.run(main())