Paginierung
Eine Seite, alle Seiten oder ein Eintrag nach dem anderen, bei jeder Liste mit Seiten.
list, listAll und iterate
Jede Liste mit Seiten hat drei Methoden. list holt eine Seite und gibt eine OpenEmail\Result\Page zurück. listAll folgt dem Cursor durch alle Seiten und gibt ein einziges Array zurück. iterate durchläuft dieselben Seiten Eintrag für Eintrag und gibt einen Generator zurück, der die nächste Seite erst holt, wenn Sie dort ankommen. Alle drei nehmen die Filter der Liste, limit:, cursor: und apiKey: entgegen.
$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;Dieselben drei Namen wiederholen sich überall, wo ein Namespace mehr als eine Liste hat, benannt nach der Liste, die sie durchlaufen: listEvents, listAllEvents und iterateEvents bei emails, listDeliveries, listAllDeliveries und iterateDeliveries bei webhooks und so weiter.
OpenEmail\Result\Page
itemsarray- Die Zeilen dieser Seite, aus dem `data`-Umschlag der API herausgelöst, jede ein assoziatives Array. Leer, wenn die Seite nichts enthält.
hasMorebool- Ob eine weitere Seite folgt. Sendet die API kein `hasMore`, ist es genau dann true, wenn es einen `nextCursor` gibt.
nextCursorstring or null- Was Sie für die nächste Seite als `cursor:` zurückgeben, und null auf der letzten.
Eine Seite ist unveränderlich: Ihre Eigenschaften sind readonly. Sie ist außerdem IteratorAggregate und Countable, foreach ($page as $item) durchläuft also ihre Zeilen, und count($page) zählt sie.
Ein Generator
iterate fordert nichts an, bis Sie mit dem Durchlauf beginnen, und es fordert die nächste Seite erst an, wenn jeder Eintrag der aktuellen geliefert wurde. Alles, was früh aufhört, stoppt also auch die Anfragen: break beendet den Durchlauf, und ebenso die Rückkehr aus der Funktion, die die Schleife enthält.
$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;Alles, was jeden Eintrag braucht, etwa iterator_to_array() auf dem Generator aufgerufen, liest jede Seite, bevor es zurückkehrt, so wie listAll.
Ein Generator lässt sich nur einmal durchlaufen. Ein zweiter Durchlauf wirft, rufen Sie also iterate erneut auf, wenn Sie die Einträge noch einmal brauchen, oder behalten Sie die Einträge statt des Generators.
Von einem Cursor aus fortsetzen
Ein Cursor ist opak. Behalten Sie den nextCursor der zuletzt gelesenen Seite und übergeben Sie ihn als cursor:, um dort weiterzumachen, in einer späteren Anfrage oder in einem anderen Prozess. listAll und iterate nehmen ebenfalls cursor: entgegen und beginnen ihren Durchlauf danach.
$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;}Ein Cursor gehört zu der Liste und den Filtern, aus denen er stammt, senden Sie also dieselben Filter mit. Einen Cursor, den die Liste nicht zuordnen kann, lehnt sie mit invalid_cursor ab, und dann hilft nur, ohne Cursor neu zu beginnen.
limit:
limit: ist die Größe jeder Seite, keine Gesamtzahl. Bei list ist es die Anzahl der zurückgegebenen Zeilen. Bei listAll und iterate ist es die Anzahl, die jede Anfrage anfordert, ein größerer Wert bedeutet also weniger Roundtrips für dieselben Zeilen. Jede Liste hat ihren eigenen Bereich und Standardwert, meist 1 bis 100 mit 25, wenn Sie nichts senden, und ein Wert außerhalb des Bereichs wird abgelehnt statt begrenzt. Die Referenz jeder Liste nennt ihren Bereich.
Wann ein Durchlauf endet
- Wenn eine Seite meldet, dass
hasMorefalse ist. - Wenn eine Seite keinen
nextCursorträgt, denn eine Seite, die mehr behauptet und dabei keinen Cursor nennt, würde endlos kreisen. - Wenn die API einen Cursor zurückgibt, dem der Durchlauf schon gefolgt ist, aus demselben Grund.
Jede Seite ist ein GET und wird daher wie jeder Lesevorgang für sich wiederholt, bevor etwas geworfen wird. Ein Fehlschlag, der die Wiederholungen übersteht, wird aus listAll heraus geworfen, und die bereits geholten Einträge werden verworfen. Bei iterate wurden die Einträge der früheren Seiten zu diesem Zeitpunkt schon geliefert. Sorgen Sie also dafür, dass die Schleife gefahrlos zweimal laufen kann, oder blättern Sie mit list und behalten Sie jeden nextCursor, damit ein zweiter Versuch dort beginnen kann, wo der erste aufgehört hat.
Threads und Entwürfe
threads->list und drafts->list blättern samt ihren listAll und iterate mit pageToken und nextPageToken der API statt mit einem Cursor. Der Client verbirgt den Unterschied: Übergeben Sie das Token als cursor: und lesen Sie es aus 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;Der Server bietet ein Token an, wann immer eine Seite voll zurückkommt. hasMore kann also auf einer Seite true sein, die sich als die letzte herausstellt, und der nächste Aufruf gibt dann keine Einträge zurück.
Seiten mit zusätzlichen Feldern
Einige Listen antworten mit mehr als nur Zeilen und geben statt Page ein eigenes Objekt aus OpenEmail\Result zurück. Jedes ist unveränderlich, IteratorAggregate über seine Zeilen und Countable.
| Methode | Gibt zurück | Was sie ergänzt |
|---|---|---|
| addresses->list | AddressBookPage | addresses statt items, dazu unrestricted und domains, mit hasMore und nextCursor. |
| addresses->listAll | AddressBook | Jede Adresse in addresses, mit unrestricted und domains so, wie die letzte Seite sie gemeldet hat. Es ist das einzige listAll, das das ganze Adressbuch statt eines Arrays zurückgibt. addresses->iterate übergibt nur die Adressen. |
| contacts->listPeople | PeoplePage | seen, false, wenn der Schlüssel die in Mails gesehenen Adressen nicht lesen kann. listAllPeople und iteratePeople geben nur die Personen zurück. |
| tempMail->listMessages | TempMessagesPage | expiresAt, wann der Posteingang abläuft. listAllMessages und iterateMessages geben nur die Nachrichten zurück. |
| templates->listSends | TemplateSends | Nach Seitennummer statt nach Cursor geblättert: items, total, page und pageSize. Fordern Sie die nächste Seite mit page: an. |
| emails->sendBatch | BatchResult | Keine Seite: items, ein Eintrag für jede gesendete Nachricht, mit den Zählern sent und failed. |
Listen, die das Array der API zurückgeben
Einige Listen blättern per Offset, per Seitennummer oder mit einem eigenen numerischen Cursor und geben den dekodierten Body so zurück, wie er kam, als Array mit data statt als Page. Sie haben kein listAll und kein iterate, Sie blättern sie also selbst.
| Methode | Blättert mit | Was zurückkommt |
|---|---|---|
| exports->list | limit: und offset: | data, total und hasMore. |
| imports->listFailures | after: und limit: | data und nextCursor, ein Integer, den Sie als after: zurückgeben und der auf der letzten Seite null ist. |
| subscriptions->list und subscriptions->listDomains | limit: und offset: | data, total, counts und hasMore. |
| billing->listInvoices | page: und limit: | data, total, page, limit, hasMore und 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'] !== []);Eine Liste ganz ohne Seiten, etwa languages->list, labels->listColors oder roles->listPermissions, gibt ihre Zeilen direkt als einfache Liste zurück.