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