Перейти к документации
PHP

Список и получение

`emails->list`, `emails->listAll`, `emails->iterate`, `emails->get` и `emails->listEvents`.

emails->list

list_emails.php
$filters = ['status' => ['queued', 'scheduled'], 'from' => '[email protected]']; $first = $client->emails->list(...$filters, limit: 50);$second = $first->hasMore ? $client->emails->list(...$filters, limit: 50, cursor: $first->nextCursor) : null; echo count($first), ' ', $second === null ? 0 : count($second), PHP_EOL;

Страница является OpenEmail\Result\Page с items, hasMore и nextCursor. Чтобы получить следующую страницу, передайте nextCursor обратно как cursor: с теми же фильтрами. Если распаковывать один массив фильтров в каждый вызов, как это делает ...$filters, фильтры останутся одинаковыми.

emails->iterate и emails->listAll

iterate_emails.php
foreach ($client->emails->iterate(status: 'failed') as $email) {    error_log($email['id'] . ' ' . ($email['lastError'] ?? ''));} $failures = $client->emails->listAll(status: 'failed', from: '[email protected]');echo count($failures), PHP_EOL;

Оба следуют за nextCursor за вас. iterate возвращает Generator, который запрашивает страницу только тогда, когда обход до неё доходит, поэтому break из foreach останавливает запросы, а listAll обходит все страницы, прежде чем вернуть один массив, поэтому дайте ему фильтр, у которого есть конец. В обоих случаях используется пагинация по ключу (keyset), поэтому сообщение, пришедшее посреди обхода, не может заставить пропустить строку, как это случилось бы со смещением.

emails->get и emails->listEvents

get_email.php
$email = $client->emails->get('msg_3f9a1c07d2b84e6a9c5b1f20');echo $email['status'], PHP_EOL;print_r($email['recipients']); $events = $client->emails->listAllEvents('msg_3f9a1c07d2b84e6a9c5b1f20'); foreach ($events as $event) {    echo $event['type'], ' ', $event['createdAt'], PHP_EOL;}

get является единственным вызовом, который возвращает recipients, по одному массиву на адрес с собственными status, error и deliveredAt. Список из пятидесяти сообщений, каждое со своими получателями, был бы страницей отчёта, о которой никто не просил.

listEvents читает журнал событий одной отправки, от старых к новым: email.accepted, email.queued, email.sent, email.delivered, email.bounced, email.opened и остальные, каждое с массивом data, форма которого зависит от его type. listAllEvents и iterateEvents обходят весь журнал за вас. Вебхуки доставляют подмножество тех же событий по мере их возникновения, поэтому если вебхук был пропущен, смотрите сюда.

Параметры

statusstring or array
Один статус или несколько (`queued`, `scheduled`, `sending`, `sent`, `partial`, `bounced`, `cancelled`, `failed`), совпадение с любым из заданных. `bounced` означает, что отказ пришёл от всех получателей сообщения, а сообщение, которое у одних вернулось с отказом, а до остальных дошло, имеет статус `partial`. Клиент отправляет массив как одно значение через запятую, потому что сервер разбивает по запятым, а значение вне набора даёт 422 с названием незнакомого значения.
broadcastIdstring
Только копии одной рассылки, идентификатор `brd_` из `broadcasts->send`. Каждый человек, до которого доходит рассылка, получает собственное сообщение, поэтому так видно, кому она ушла и что случилось с каждой копией. `broadcasts->listRecipients` перечисляет тех же людей с их открытиями, кликами и отписками.
fromstring
Точное совпадение с адресом отправителя в том виде, в каком он записан, то есть голым `addr@host` в нижнем регистре. Запись сохраняется без отображаемого имени, поэтому адрес в угловых скобках вроде `Acme <[email protected]>` ни с чем не совпадёт. Ваше значение приводится к нижнему регистру перед сравнением, и это проверка на равенство, а не на префикс или домен.
scheduledFromDateTimeInterface or string
Только сообщения, запланированные на этот момент или позже. Вместе с `scheduledTo:` и `status: ['scheduled', 'queued']` показывает, что ждёт отправки в определённом окне, как это делает календарь приложения. Сообщение без `scheduledAt` не попадает в выдачу. Передавайте `DateTimeInterface`, который отправляется как момент в UTC, или момент ISO 8601 со смещением: строку с датой без времени эти два фильтра отклоняют.
scheduledToDateTimeInterface or string
Только сообщения, запланированные на этот момент или раньше. `scheduledFrom:` позже `scheduledTo:` даёт 422 `invalid_parameter`.
limitint
Число строк на этой странице, от 1 до 100, по умолчанию 25. Значение вне этого диапазона отклоняется с 422, а не подрезается. В `listAll` и `iterate` это размер каждой запрашиваемой страницы.
cursorstring
Идентификатор сообщения (`msg_…`), с которого продолжать выдачу. По ключу, а не по смещению: возвращаются строки строго старше `createdAt` этого сообщения, поэтому отправки, пришедшие посреди страницы, не могут вытолкнуть строку мимо вас. Идентификатор, который не называет ни одного сообщения в этом рабочем пространстве, даёт 400 `invalid_cursor`.
apiKeystring
Запрашивает список с этим ключом вместо ключа клиента.

Ключ, суженный до некоторых адресов, читает только сообщения, отправленные с охваченных им адресов, а страница обрезается после этого фильтра, поэтому каждая страница, кроме последней, всё равно содержит limit строк. from:, который ключ не охватывает, возвращает пустую последнюю страницу, а не 403.

Ответ: OpenEmail\Result\Page

itemsarray
Одна страница сообщений, новые сверху по `createdAt`, извлечённая из конверта `data` у API. Строки списка никогда не несут разбивки `recipients` по адресам. Она есть в `get`.
hasMorebool
Есть ли за этой страницей ещё строки, подходящие под фильтр. Отвечается выборкой на одну строку больше, чем `limit`, а не вторым запросом с подсчётом.
nextCursorstring or null
Идентификатор, который нужно передать обратно как `cursor:`, и null на последней странице. `iterate` и `listAll` останавливаются, когда он null или `hasMore` равно false, поскольку страница, которая заявляет о продолжении, но не называет курсора, зациклилась бы навсегда.

Каждый элемент

objectstring
В строке этого списка всегда `email`.
idstring
Собственный идентификатор этого API, `msg_…`. Именно его принимает любой другой вызов emails и именно его называет курсор.
statusstring
Где сообщение находится в своей жизни. `partial` является самостоятельным состоянием, а не разновидностью failed: у части получателей оно уже есть и его нельзя «разотправить», так что повтор будет ошибкой. `bounced` значит, что после отправки письмо вернулось от каждого получателя, так что его нет ни у кого, а каждый получатель в `get` указывает причину.
modestring
`live` или `test`, берётся из ключа, которым отправлено. Тестовая отправка записывается здесь и никогда не передаётся.
fromstring
Адрес, под которым была авторизована отправка, сохранённый голым и в нижнем регистре, так что отображаемое имя, переданное в `from`, всё равно уходит по сети, но здесь не хранится. Обычная строка, а не массив, потому что это авторизованная идентичность: адрес вне области отправки ключа, не на его домене и не названный в нём, отклоняется с 403 и никогда молча не заменяется на разрешённый.
subjectstring or null
Тема в сохранённом виде. null у сообщения, записанного без темы.
messageIdstring or null
Message-ID по RFC 5322, а не наш идентификатор. null, пока не существует MIME, и переписывается сервисом отправки на выходе, поэтому более поздний отказ или DSN несёт другой идентификатор и сопоставляется по `id`.
threadIdstring or null
Цепочка, к которой относится это сообщение, если она была указана или назначена. Иначе null.
transportstring or null
Каким путём ушли байты. null до отправки. Сохранённые записи могут называть транспорты, которые больше не используются, поэтому считайте незнакомое значение информацией, а не ошибкой.
attemptsint
Сколько попыток отправки было у сообщения, 0 до первой.
lastErrorstring or null
Последняя ошибка отправки, написанная для человека. null, пока ничего не сломалось.
scheduledAtstring or null
Когда сообщение должно уйти, в виде момента ISO 8601. null только при немедленной отправке без окна отмены: окно является короткой задержкой и ничем больше, поэтому `cancellableForSeconds` тоже заполняет это поле, в строке, у которой `status` равен `queued`, а не `scheduled`.
cancellableUntilstring or null
Момент, когда сообщение должно уйти, несущий то же значение, что и `scheduledAt`, у любой отложенной отправки и null у неотложенной. Это отметка времени для показа, а не проверка, которую делает сервер: `cancel` ветвится по `status` и останавливает сообщение, только пока оно `queued` или `scheduled`.
sentAtstring or null
Когда оно ушло. null до завершения отправки, поэтому ветвиться нужно по `status`, а не по этому полю.
tagsarray
Метки, переданные при отправке, возвращаются как есть и никогда не интерпретируются. Всегда массив, пустой, если меток не задали, и никогда не null, и только возвращаются: этот список фильтрует по `status`, `from`, `broadcastId` и окну расписания, поэтому метку можно прочитать у сообщения, но не использовать для поиска.
broadcastIdstring or null
Рассылка `brd_`, копией которой является это письмо, или null для письма, отправленного отдельно.
sourcestring
Какая поверхность запросила отправку: `composer`, `api`, `mcp`, `ai` или `queue`. `api` означает данный клиент.
createdAtstring
Когда была записана запись об отправке, то есть до самой отправки. Именно по этому полю упорядочен список и именно с ним сравнивается курсор.
trackingarray
Сводка вовлечённости. Присутствует только в строке, сообщение которой отслеживалось, и отсутствует в остальных. Отсутствие отвечает на вопрос «отслеживалось ли это», тогда как `openCount`, равный 0, читался бы как «никто не открыл», поэтому читайте его через `?? null`, а не рассчитывайте на наличие ключа.
translationarray
Никогда не присутствует в строке списка: запись о переводе живёт в сохранённом запросе, который список намеренно не подтягивает. Её отсутствие здесь ничего не говорит о том, переводилось ли сообщение. Спросите `get`.

Трекинг элемента

opensbool
Ушло ли это сообщение с пикселем. Это то, что было применено к данному сообщению, а не то, что говорит настройка аккаунта сейчас.
clicksbool
Были ли переписаны ссылки этого сообщения. False, если в теле не было ссылок для переписывания, поскольку тогда ничего не менялось.
openedbool
Было ли записано хотя бы одно учтённое открытие. Выводится из `openCount` больше 0.
clickedbool
Был ли записан хотя бы один учтённый клик. Выводится из `clickCount` больше 0.
openCountint
Открытия, которые считаются вызванными человеком, просуммированные по всем копиям сообщения. Сканеры и прокси приватности фиксируются, но исключаются, а повторные загрузки в течение тридцати секунд схлопываются в одну.
clickCountint
Засчитанные клики, просуммированные по копиям. Дедуплицируются по ссылке, а не по сообщению, потому что переход по двум ссылкам с разницей в секунды считается двумя действиями, а не повтором.
firstOpenAtstring or null
Самое раннее засчитанное открытие среди копий, и null, пока его нет. Машинные обращения его не сдвигают.