Ir a la documentación
Python

Paginación

`list` para una página, `list_all` para todas las páginas e `iterate` para un elemento cada vez.

Una página: 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']

Una página es {'items': [...], 'hasMore': ..., 'nextCursor': ...}. Devuelve nextCursor como cursor=, con los mismos filtros, para obtener la página siguiente.

nextCursor es None en la última página, y hasMore indica si hay más filas que coinciden después de esta. En openemail.types una página es Page[T], así que emails.list devuelve un Page[EmailResource] y un comprobador de tipos sabe qué contiene cada elemento.

La API pagina los hilos y los borradores con un pageToken. El cliente te lo entrega como nextCursor y lo recibe de vuelta como cursor=, igual que cualquier otra lista, y list_all e iterate lo siguen por ti. Es opaco: devuelve lo que te dieron y nunca construyas uno.

Todas las páginas: 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 sigue nextCursor hasta la última página y devuelve una única list. Obtiene todas las páginas antes de devolver el resultado, así que dale un filtro que termine.

addresses.list_all es el único que devuelve otra cosa: la libreta de direcciones completa, {'unrestricted': ..., 'addresses': [...], 'domains': [...]}, con las direcciones de todas las páginas dentro.

Uno a uno: 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 devuelve un generador. Llamarlo no envía nada: la primera página se obtiene cuando el bucle pide su primer elemento, y cada página siguiente solo cuando el bucle llega al final de la anterior. Salir del bucle, o tomar un fragmento con itertools.islice, detiene las solicitudes.

limit= en list_all e iterate es el tamaño de cada página que obtienen, no un tope de cuántos elementos recibes, así que un limit mayor significa menos solicitudes. cursor= empieza el recorrido desde una página que ya tienes. Ambos se detienen cuando hasMore es falso o nextCursor es None, y también cuando una página nombra el cursor con el que se obtuvo, así que una página defectuosa no puede provocar un bucle infinito.

Listas dentro de un espacio de nombres

list_all e iterate paginan el mismo endpoint que el list que tienen al lado, y lo mismo hacen las demás parejas que llevan el nombre de la lista que recorren. Cada pareja acepta los mismos filtros que su lista.

Espacio de nombresUna páginaTodas las páginasUno a uno
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

Páginas que traen más

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']))

Algunas listas traen algo más que una página. contacts.list_people añade seen junto a items, hasMore y nextCursor, temp_mail.list_messages añade expiresAt, y addresses.list devuelve addresses en lugar de items, junto a unrestricted, domains, hasMore y nextCursor. Aun así, cada una continúa con cursor= y se recorre con su list_all y su iterate.

Dos listas paginan de otra forma. templates.list_sends cuenta páginas: pasa page= y page_size=, y lee total, page y pageSize junto a items. imports.list_failures se deja tal como la envía la API, {'object': 'list', 'data': [...], 'nextCursor': ...}, y continúa con after=, el número que hay en nextCursor. Ninguna de las dos tiene list_all ni iterate.

Tamaños de página

La mayoría de las listas aceptan un limit= de 1 a 100, con 25 por defecto, los dos números de PAGE_LIMITS (PAGE_LIMITS.MAX_LIMIT y PAGE_LIMITS.DEFAULT_LIMIT). contacts.list, audiences.list_contacts, broadcasts.list_recipients y las listas de tracking aceptan hasta 200 con un valor predeterminado de 50, y temp_mail.list_messages acepta hasta 50. Un valor fuera del rango se rechaza con un 422 en lugar de ajustarse al límite.

En AsyncOpenEmail

El cliente asíncrono pagina de la misma forma. list y list_all se llaman con await, e iterate devuelve un iterador asíncrono que recorres con async for, sin await delante de la llamada.

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())