صفحهبندی
`list` برای یک صفحه، `list_all` برای همهٔ صفحهها، و `iterate` برای هر بار یک آیتم.
یک صفحه: list
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
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
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 برابر false یا nextCursor برابر None باشد، و همچنین وقتی صفحهای همان cursorی را نام ببرد که آن را آورده است، تا صفحهای که بد رفتار میکند نتواند تا ابد حلقه بزند.
فهرستهای درون یک فضای نام
list_all و iterate همان اندپوینتی را صفحهبهصفحه میپیمایند که list کنارشان میپیماید، و همینطور جفتهای دیگری که به نام فهرستی که میپیمایند نامگذاری شدهاند. هر جفت همان فیلترهای فهرست خودش را میگیرد.
| فضای نام | یک صفحه | همهٔ صفحهها | یکییکی |
|---|---|---|---|
| emails | list_events | list_all_events | iterate_events |
| calendar | list_events | list_all_events | iterate_events |
| templates | list_versions | list_all_versions | iterate_versions |
| templates | list_images | list_all_images | iterate_images |
| tracking | list_opens | list_all_opens | iterate_opens |
| tracking | list_clicks | list_all_clicks | iterate_clicks |
| rules | list_runs | list_all_runs | iterate_runs |
| audiences | list_contacts | list_all_contacts | iterate_contacts |
| broadcasts | list_recipients | list_all_recipients | iterate_recipients |
| contacts | list_people | list_all_people | iterate_people |
| contacts | list_threads | list_all_threads | iterate_threads |
| domains | list_addresses | list_all_addresses | iterate_addresses |
| forms | list_submissions | list_all_submissions | iterate_submissions |
| members | list_invitations | list_all_invitations | iterate_invitations |
| files | list_links | list_all_links | iterate_links |
| temp_mail | list_messages | list_all_messages | iterate_messages |
| webhooks | list_deliveries | list_all_deliveries | iterate_deliveries |
| webhooks | list_workspace_deliveries | list_all_workspace_deliveries | iterate_workspace_deliveries |
| webhooks | list_activity | list_all_activity | iterate_activity |
| webhooks | list_workspace_activity | list_all_workspace_activity | iterate_workspace_activity |
| keys | list_requests | list_all_requests | iterate_requests |
| keys | list_activity | list_all_activity | iterate_activity |
| keys | list_workspace_requests | list_all_workspace_requests | iterate_workspace_requests |
| keys | list_workspace_activity | list_all_workspace_activity | iterate_workspace_activity |
صفحههایی که چیزهای بیشتری دارند
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 در کنار items، hasMore و nextCursor فیلد seen را میافزاید، temp_mail.list_messages فیلد expiresAt را میافزاید، و addresses.list بهجای items، addresses را برمیگرداند، در کنار 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 یک iterator ناهمگام برمیگرداند که با async for روی آن حلقه میزنید، بیآنکه جلوی فراخوانی await بگذارید.
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())