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

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

`emails.list`, `emails.list_all`, `emails.iterate`, `emails.get` и `emails.list_events`.

emails.list

list_emails.rb
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

iterate_emails.rb
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

get_email.rb
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, пока его нет. Машинные обращения никогда его не сдвигают.