Список и получение
`emails.list`, `emails.list_all`, `emails.iterate`, `emails.get` и `emails.list_events`.
emails.list
filters = {status: ["queued", "scheduled"], from: "[email protected]"} first = client.emails.list(**filters, limit: 50)second = client.emails.list(**filters, limit: 50, cursor: first.next_cursor) if first.next_cursor p first.items.size, second&.items&.sizeСтраница является OpenEmail::Page с items, has_more? и next_cursor. Чтобы получить следующую страницу, передайте next_cursor обратно как cursor: с теми же фильтрами.
emails.iterate и emails.list_all
client.emails.iterate(status: "failed") do |email| warn "#{email[:id]} #{email[:lastError]}"end failures = client.emails.list_all(status: "failed", from: "[email protected]")puts failures.sizeОба следуют за next_cursor за вас. iterate запрашивает страницу только тогда, когда обход до неё доходит, поэтому break в блоке или first либо find на Enumerator, который он возвращает без блока, останавливают запросы, а list_all обходит все страницы, прежде чем вернуть один Array, поэтому дайте ему фильтр, у которого есть конец. В обоих случаях используется пагинация по ключу (keyset), поэтому сообщение, пришедшее посреди обхода, не может заставить пропустить строку, как это случилось бы со смещением.
emails.get и emails.list_events
email = client.emails.get("msg_3f9a1c07d2b84e6a9c5b1f20")puts email[:status]p email[:recipients] events = client.emails.list_all_events("msg_3f9a1c07d2b84e6a9c5b1f20")events.each { |event| puts "#{event[:type]} #{event[:createdAt]}" }get является единственным вызовом, который возвращает recipients, по одному Hash на адрес с собственными status, error и deliveredAt. Список из пятидесяти сообщений, каждое со своими получателями, был бы страницей отчёта, о которой никто не просил.
list_events читает журнал событий одной отправки, от старых к новым: email.accepted, email.queued, email.sent, email.delivered, email.bounced, email.opened и остальные, каждое с Hash data, форма которого зависит от его type. list_all_events и iterate_events обходят весь журнал за вас. Вебхуки доставляют подмножество тех же событий по мере их возникновения, поэтому если вебхук был пропущен, смотрите сюда.
Параметры
statusString or Array<String>- Один статус или несколько (`queued`, `scheduled`, `sending`, `sent`, `partial`, `bounced`, `cancelled`, `failed`), совпадение с любым из заданных. `bounced` означает, что отказ пришёл от всех получателей сообщения, а сообщение, которое у одних вернулось с отказом, а до остальных дошло, имеет статус `partial`. Гем отправляет Array как одно значение через запятую, потому что сервер разбивает по запятым, а значение вне набора даёт 422 с названием незнакомого значения.
broadcast_idString- Только копии одной рассылки, идентификатор `brd_` из `broadcasts.send`. Каждый человек, до которого доходит рассылка, получает собственное сообщение, поэтому так видно, кому она ушла и что случилось с каждой копией. `broadcasts.list_recipients` перечисляет тех же людей с их открытиями, кликами и отписками.
fromString- Точное совпадение с адресом отправителя в том виде, в каком он записан, то есть голым `addr@host` в нижнем регистре. Запись сохраняется без отображаемого имени, поэтому адрес в угловых скобках вроде `Acme <[email protected]>` ни с чем не совпадёт. Ваше значение приводится к нижнему регистру перед сравнением, и это проверка на равенство, а не на префикс или домен.
scheduled_fromTime, DateTime or String- Только сообщения, запланированные на этот момент или позже. Вместе с `scheduled_to:` и `status: ["scheduled", "queued"]` показывает, что ждёт отправки в определённом окне, как это делает календарь приложения. Сообщение без `scheduledAt` не попадает в выдачу. Передавайте Time, DateTime или момент ISO 8601 со смещением: Date из Ruby отправляется как голая дата, которую эти два фильтра отклоняют.
scheduled_toTime, DateTime or String- Только сообщения, запланированные на этот момент или раньше. `scheduled_from:` позже `scheduled_to:` даёт 422 `invalid_parameter`.
limitInteger- Число строк на этой странице, от 1 до 100, по умолчанию 25. Значение вне этого диапазона отклоняется с 422, а не подрезается. В `list_all` и `iterate` это размер каждой запрашиваемой страницы.
cursorString- Идентификатор сообщения (`msg_…`), с которого продолжать выдачу. По ключу, а не по смещению: возвращаются строки строго старше `createdAt` этого сообщения, поэтому отправки, пришедшие посреди страницы, не могут вытолкнуть строку мимо вас. Идентификатор, который не называет ни одного сообщения в этом рабочем пространстве, даёт 400 `invalid_cursor`.
api_keyString- Запрашивает список с этим ключом вместо ключа клиента.
Ключ, суженный до некоторых адресов, читает только сообщения, отправленные с охваченных им адресов, а страница обрезается после этого фильтра, поэтому каждая страница, кроме последней, всё равно содержит limit строк. from:, который ключ не охватывает, возвращает пустую последнюю страницу, а не 403.
Ответ: OpenEmail::Page
itemsArray<Hash>- Одна страница сообщений, новые сверху по `createdAt`, извлечённая из конверта `data` у API. Строки списка никогда не несут разбивки `recipients` по адресам. Она есть в `get`.
has_more?Boolean- Есть ли за этой страницей ещё строки, подходящие под фильтр. Отвечается выборкой на одну строку больше, чем `limit`, а не вторым запросом с подсчётом.
next_cursorString or nil- Идентификатор, который нужно передать обратно как `cursor:`, и nil на последней странице. `iterate` и `list_all` останавливаются, когда он nil или `has_more?` равно false, поскольку страница, которая заявляет о продолжении, но не называет курсора, зациклилась бы навсегда.
Каждый элемент
objectString- В строке этого списка всегда `email`.
idString- Собственный идентификатор этого API, `msg_…`. Именно его принимает любой другой вызов emails и именно его называет курсор.
statusString- Где сообщение находится в своей жизни. `partial` является самостоятельным состоянием, а не разновидностью failed: у части получателей оно уже есть и его нельзя «разотправить», так что повтор будет ошибкой. `bounced` значит, что после отправки письмо вернулось от каждого получателя, так что его нет ни у кого, а каждый получатель в `get` указывает причину.
modeString- `live` или `test`, берётся из ключа, которым отправлено. Тестовая отправка записывается здесь и никогда не передаётся.
fromString- Адрес, под которым была авторизована отправка, сохранённый голым и в нижнем регистре, так что отображаемое имя, переданное в `from`, всё равно уходит по сети, но здесь не хранится. Обычная String, а не Hash, потому что это авторизованная идентичность: адрес вне области отправки ключа, не на его домене и не названный в нём, отклоняется с 403 и никогда молча не заменяется на разрешённый.
subjectString or nil- Тема в сохранённом виде. nil у сообщения, записанного без темы.
messageIdString or nil- Message-ID по RFC 5322, а не наш идентификатор. nil, пока не существует MIME, и переписывается сервисом отправки на выходе, поэтому более поздний отказ или DSN несёт другой идентификатор и сопоставляется по `id`.
threadIdString or nil- Цепочка, к которой относится это сообщение, если она была указана или назначена. Иначе nil.
transportString or nil- Каким путём ушли байты. nil до отправки. Сохранённые записи могут называть транспорты, которые больше не используются, поэтому считайте незнакомое значение информацией, а не ошибкой.
attemptsInteger- Сколько попыток отправки было у сообщения, 0 до первой.
lastErrorString or nil- Последняя ошибка отправки, написанная для человека. nil, пока ничего не сломалось.
scheduledAtString or nil- Когда сообщение должно уйти, в виде момента ISO 8601. nil только при немедленной отправке без окна отмены: окно является короткой задержкой и ничем больше, поэтому `cancellableForSeconds` тоже заполняет это поле, в строке, у которой `status` равен `queued`, а не `scheduled`.
cancellableUntilString or nil- Момент, когда сообщение должно уйти: то же значение, что и `scheduledAt`, у любой отложенной отправки и nil у неотложенной. Это метка времени для показа, а не проверка, которую делает сервер: `cancel` ветвится по `status` и останавливает сообщение, только пока оно ещё `queued` или `scheduled`.
sentAtString or nil- Когда оно ушло. nil до завершения отправки, поэтому ветвиться нужно по `status`, а не по этому полю.
tagsHash- Метки, переданные при отправке, возвращаются как есть и никогда не интерпретируются. Всегда Hash, пустой, если меток не задали, и никогда nil, и только возвращаются: этот список фильтрует по `status`, `from`, `broadcast_id` и окну расписания, поэтому метку можно прочитать у сообщения, но не использовать для поиска.
broadcastIdString or nil- Рассылка `brd_`, копией которой является это сообщение, или nil для сообщения, отправленного само по себе.
sourceString- Какая поверхность запросила отправку: `composer`, `api`, `mcp`, `ai` или `queue`. `api` означает данный клиент.
createdAtString- Когда была записана запись об отправке, то есть до самой отправки. Именно по этому полю упорядочен список и именно с ним сравнивается курсор.
trackingHash- Сводка вовлечённости. Присутствует только в строке, сообщение которой отслеживалось, и отсутствует в остальных. Отсутствие отвечает на вопрос «отслеживалось ли это», тогда как `openCount`, равный 0, читался бы как «никто не открыл».
translationHash- Никогда не присутствует в строке списка: запись о переводе живёт в сохранённом запросе, который список намеренно не подтягивает. Её отсутствие здесь ничего не говорит о том, переводилось ли сообщение. Спросите `get`.
Трекинг элемента
opensBoolean- Ушло ли это сообщение с пикселем. Это то, что было применено к данному сообщению, а не то, что говорит настройка аккаунта сейчас.
clicksBoolean- Были ли переписаны ссылки этого сообщения. False, если в теле не было ссылок для переписывания, поскольку тогда ничего не менялось.
openedBoolean- Было ли записано хотя бы одно учтённое открытие. Выводится из `openCount` больше 0.
clickedBoolean- Был ли записан хотя бы один учтённый клик. Выводится из `clickCount` больше 0.
openCountInteger- Открытия, которые считаются вызванными человеком, просуммированные по всем копиям сообщения. Сканеры и прокси приватности фиксируются, но исключаются, а повторные загрузки в течение тридцати секунд схлопываются в одну.
clickCountInteger- Засчитанные клики, просуммированные по копиям. Дедуплицируются по ссылке, а не по сообщению, потому что переход по двум ссылкам с разницей в секунды считается двумя действиями, а не повтором.
firstOpenAtString or nil- Самое раннее учтённое открытие по всем копиям, nil, пока его нет. Машинные обращения никогда его не сдвигают.