ページネーション
ページ分割されるすべての一覧で、1 ページ、全ページ、または 1 アイテムずつ。
list、listAll、iterate
ページ分割されるすべての一覧には 3 つのメソッドがあります。list は 1 ページを取得して OpenEmail\Result\Page を返します。listAll はすべてのページでカーソルをたどり、1 つの配列を返します。iterate は同じページを 1 アイテムずつたどって Generator を返し、次のページはそこに到達したときに初めて取得します。3 つとも一覧のフィルター、limit:、cursor:、apiKey: を受け取ります。
$page = $client->emails->list(status: 'failed', limit: 50); foreach ($page as $email) { echo $email['id'], ' ', $email['lastError'] ?? '', PHP_EOL;} $failures = $client->emails->listAll(status: 'failed'); foreach ($client->emails->iterate(status: 'failed') as $email) { echo $email['id'], PHP_EOL;} echo count($failures), ' ', $page->hasMore ? 'more to come' : 'that is all', PHP_EOL;名前空間に複数の一覧がある場合は、どこでも同じ 3 つの名前が、たどる一覧の名前を付けて繰り返されます。emails の listEvents、listAllEvents、iterateEvents、webhooks の listDeliveries、listAllDeliveries、iterateDeliveries などです。
OpenEmail\Result\Page
itemsarray- このページの行。API の `data` エンベロープから取り出したもので、それぞれ連想配列です。ページに何もなければ空です。
hasMorebool- 次のページがあるかどうか。API が `hasMore` を送らない場合は、`nextCursor` があるときにちょうど true になります。
nextCursorstring or null- 次のページのために `cursor:` として渡し返す値。最後のページでは null。
ページは不変で、プロパティはすべて readonly です。IteratorAggregate と Countable も実装しているため、foreach ($page as $item) で行をたどり、count($page) で行数を数えられます。
Generator
iterate は走査を始めるまで何も要求せず、現在のページのアイテムがすべて yield されて初めて次のページを要求します。そのため、早く止まる処理はリクエストも止めます。break で走査が終わり、ループを含む関数から return しても同じです。
$latest = []; foreach ($client->emails->iterate(status: 'failed', limit: 100) as $email) { $latest[] = $email; if (count($latest) === 10) { break; }} $invoice = null; foreach ($client->emails->iterate(status: 'failed') as $email) { if (($email['tags']['invoice'] ?? null) === 'inv_2026_09_4192') { $invoice = $email; break; }} echo count($latest), ' ', $invoice['id'] ?? 'not found', PHP_EOL;Generator に対して呼ぶ iterator_to_array() のように、すべてのアイテムを必要とする処理は、listAll と同様に、戻る前にすべてのページを読みます。
Generator は 1 回しか走査できません。2 回目の走査は例外をスローするため、アイテムがもう一度必要なときは iterate を再度呼ぶか、Generator ではなくアイテムを保持してください。
カーソルからの再開
カーソルは不透明な値です。最後に読んだページの nextCursor を保持し、cursor: として渡し返せば、後のリクエストや別のプロセスでもそこから続けられます。listAll と iterate も cursor: を受け取り、その後から走査を始めます。
$firstPage = $client->emails->list(status: 'failed', limit: 25);$saved = $firstPage->nextCursor; if ($saved !== null) { $rest = $client->emails->listAll(status: 'failed', cursor: $saved); echo count($rest), PHP_EOL;}カーソルはそれを返した一覧とフィルターに属するため、同じフィルターと一緒に送ってください。一覧が位置を特定できないカーソルは invalid_cursor で拒否され、その場合はカーソルなしで最初からやり直します。
limit:
limit: は合計ではなく各ページのサイズです。list では返ってくる行数です。listAll と iterate では各リクエストが要求する件数なので、大きな値にすれば同じ行数を少ない往復で取得できます。各一覧には独自の範囲と既定値があり、多くは 1〜100 で、指定しなければ 25 です。範囲外の値は丸められるのではなく拒否されます。各一覧のリファレンスにその範囲が書かれています。
走査が止まるとき
- ページの
hasMoreが false のとき。 - ページに
nextCursorがないとき。続きがあると言いながらカーソルを示さないページは、永遠にループしてしまうからです。 - API が、すでにたどったカーソルを返してきたとき。理由は同じです。
各ページは GET なので、例外がスローされる前に他の読み取りと同様に個別にリトライされます。リトライ後も残った失敗は listAll からスローされ、それまでに取得したアイテムは破棄されます。iterate ではその時点で前のページのアイテムはすでに yield されているため、ループの処理を 2 回実行しても安全にするか、list でページを取得して各 nextCursor を保持し、2 回目の試行が 1 回目の止まった所から始められるようにしてください。
スレッドと下書き
threads->list と drafts->list、およびそれぞれの listAll と iterate は、カーソルではなく API の pageToken と nextPageToken でページ分割します。クライアントはこの違いを隠します。トークンは cursor: として渡し、nextCursor から読み取ってください。
$page = $client->threads->list(folder: 'inbox', limit: 50);$later = $page->hasMore ? $client->threads->list(folder: 'inbox', limit: 50, cursor: $page->nextCursor) : null; echo count($page), ' ', $later === null ? 0 : count($later), PHP_EOL;サーバーはページが満杯で返ってくるたびにトークンを出すため、結果的に最後だったページでも hasMore が true になることがあり、その場合は次の呼び出しがアイテムを返しません。
追加の情報を持つページ
いくつかの一覧は行以外の情報も返し、Page の代わりに OpenEmail\Result の独自のオブジェクトを返します。いずれも不変で、行に対する IteratorAggregate であり、Countable でもあります。
| メソッド | 返すもの | 追加されるもの |
|---|---|---|
| addresses->list | AddressBookPage | items の代わりに addresses、さらに unrestricted と domains、および hasMore と nextCursor。 |
| addresses->listAll | AddressBook | addresses にすべてのアドレスが入り、unrestricted と domains は最後のページが報告した値になります。配列ではなくアドレス帳全体を返す唯一の listAll です。addresses->iterate はアドレスだけを yield します。 |
| contacts->listPeople | PeoplePage | seen。キーがメールに現れたアドレスを読めない場合は false です。listAllPeople と iteratePeople は人だけを返します。 |
| tempMail->listMessages | TempMessagesPage | expiresAt。受信箱の期限が切れる時刻です。listAllMessages と iterateMessages はメッセージだけを返します。 |
| templates->listSends | TemplateSends | カーソルではなくページ番号でページ分割します:items、total、page、pageSize。次のページは page: で要求します。 |
| emails->sendBatch | BatchResult | ページではありません:送信した各メッセージに 1 つずつの items と、sent と failed の件数。 |
API の配列を返す一覧
一部の一覧はオフセット、ページ番号、または独自の数値カーソルでページ分割し、Page ではなく、デコード済みのボディを受け取ったまま、つまり data を持つ配列として返します。listAll や iterate はないため、ページ分割は自分で行います。
| メソッド | ページ分割の方法 | 返ってくるもの |
|---|---|---|
| exports->list | limit: と offset: | data、total、hasMore。 |
| imports->listFailures | after: と limit: | data と、after: として渡し返す整数の nextCursor。最後のページでは null です。 |
| subscriptions->list と subscriptions->listDomains | limit: と offset: | data、total、counts、hasMore。 |
| billing->listInvoices | page: と limit: | data、total、page、limit、hasMore、metered。 |
$offset = 0; do { $batch = $client->subscriptions->list(status: 'active', limit: 50, offset: $offset); foreach ($batch['data'] as $row) { echo $row['senderEmail'], ' ', $row['total'], PHP_EOL; } $offset += count($batch['data']);} while ($batch['hasMore'] && $batch['data'] !== []);languages->list、labels->listColors、roles->listPermissions のように、ページ分割されない一覧は、行をそのまま通常のリストとして返します。