تخطَّ إلى المستندات
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 مولِّدًا (generator). واستدعاؤه لا يرسل شيئًا: تُجلب الصفحة الأولى حين تطلب الحلقة عنصرها الأول، وكل صفحة بعدها فقط حين تبلغ الحلقة نهاية الصفحة السابقة. والخروج من الحلقة، أو أخذ شريحة بـ itertools.islice، يوقف الطلبات.

limit= في list_all وiterate هو حجم كل صفحة يجلبانها، لا سقف لعدد العناصر التي تحصل عليها، فقيمة limit أكبر تعني طلبات أقل. ويبدأ cursor= المرور من صفحة تملكها بالفعل. ويتوقف كلاهما حين تكون hasMore بقيمة false أو تكون 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())