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

Отслеживание открытий и переходов

`emails->getTracking` и всё пространство имён `tracking`.

Одно сообщение

tracking.php
$report = $client->emails->getTracking('msg_3f9a1c07d2b84e6a9c5b1f20'); echo $report['openCount'], ' opens from ', count($report['recipients']), ' recipients', PHP_EOL; foreach ($report['links'] as $link) {    echo $link['url'], ' ', $link['clickCount'], PHP_EOL;}

Для сообщения, которое никогда не отслеживалось, выбрасывается NotFoundException, у которого isNotFound() равно true, а не возвращается пустой отчёт. «Мы ничего не записали» и «никто не открыл» являются разными ответами и не должны выглядеть одинаково. Сообщение, отправленное с тестовым ключом, никогда не отслеживается, поэтому для него это исключение выбрасывается всегда.

По всему почтовому ящику

tracking_report.php
$unopened = $client->tracking->list(opened: false, days: 7, limit: 100);$stats = $client->tracking->getStats(days: 30, offsetMinutes: intdiv((int) date('Z'), 60));$report = $client->tracking->get('msg_3f9a1c07d2b84e6a9c5b1f20');$opens = $client->tracking->listOpens('msg_3f9a1c07d2b84e6a9c5b1f20', includeMachine: true);$clicks = $client->tracking->listClicks('msg_3f9a1c07d2b84e6a9c5b1f20'); echo count($unopened), ' unopened, ', $stats['openRate'], '% opened', PHP_EOL;echo count($opens), ' opens and ', count($clicks), ' clicks on ', $report['id'], PHP_EOL;

list, listOpens и listClicks возвращают одну OpenEmail\Result\Page, а listAll, iterate, listAllOpens, iterateOpens, listAllClicks и iterateClicks обходят все страницы за вас. get, listOpens и listClicks принимают либо идентификатор отправки msg_…, либо собственный tmsg_… записи трекинга.

Отдельное пространство имён, а не методы в emails, и причина в охвате: emails перечисляет записи об отправке, которые существуют только для почты, обработанной этим API. Композер, инструменты MCP и ассистент отправляют без таких записей, поэтому отчёт на основе emails был бы отчётом о вашем API-трафике, а не о почтовом ящике.

Как читать цифры честно

ПараЧто означает
opens и clicksЧто было ПРИМЕНЕНО: ушло ли сообщение с пикселем или с переписанными ссылками.
opened и clickedЧто произошло.
openCountЗасчитанные обращения. Сканеры и прокси приватности исключены.
openCountRawВсе обращения. Именно так, выдавая это за вовлечённость, получают процент открытий выше 100%.
attributableМожно ли вообще привязать прочтение к конкретному получателю.

Доли из tracking->getStats считаются по ОТСЛЕЖИВАЕМЫМ сообщениям, а не по всему отправленному. Иначе почтовый ящик, который отслеживает одно сообщение из десяти, выглядел бы так, будто показатели обрушились. openRate и clickRate являются процентами, округлёнными до одного знака после запятой, например 42.5, а не долями от 0 до 1.

Параметры: tracking->list

openedbool
`true` выбирает сообщения хотя бы с одним засчитанным открытием, а `false` выбирает отслеживаемые сообщения без единого. Ни то ни другое не является значением по умолчанию, и `false` никогда не означает неотслеживаемую почту, которой в этом списке нет вовсе.
clickedbool
Тот же фильтр для засчитанных кликов, применяемый независимо от `opened`. Можно задать оба, и сообщения должны удовлетворять обоим.
daysint
На сколько дней назад от текущего момента смотреть, от 1 до 365, по умолчанию 30, а вне этого диапазона даёт 422. Окно отсчитывается по времени создания записи трекинга, и в список попадают только записи, отправка которых действительно состоялась.
minutesint
Окно в минутах вместо дней, от 1 до 527040. Если заданы оба, оно имеет приоритет над `days`. Окну короче суток нужен более мелкий `grain`.
grainstring
`minute`, `hour` или `day`, по умолчанию `day`. Он только округляет вниз начало окна, чтобы этот список совпадал с `getStats`, прочитанным с той же гранулярностью, и ничего не меняет в форме ответа.
limitint
Число отчётов на странице, от 1 до 200, по умолчанию 50, сначала новые. Для следующей страницы передайте `nextCursor` страницы обратно как `cursor:` с теми же фильтрами или позвольте `listAll` и `iterate` обойти всё окно.
cursorstring
`nextCursor` предыдущей страницы, идентификатор `tmsg_`.
apiKeystring
Запрашивает список с этим ключом вместо ключа клиента.

Ответ: отчёт о трекинге

emails->getTracking и tracking->get возвращают один отчёт как массив с ключами в camelCase, а tracking->list возвращает страницу таких отчётов.

objectstring
Всегда `tracking` у отчёта, полученного самостоятельно, через `tracking->get`, `tracking->list` или `emails->getTracking`. Тот же отчёт, вложенный как `tracking` в сообщение из `emails->get`, приходит без этого ключа, потому что там он является частью сообщения, а не отдельно полученным объектом.
idstring
Собственный идентификатор записи трекинга, `tmsg_…`. Именно по нему работают `listOpens` и `listClicks`, а `msg_…`, переданный им, сначала сопоставляется с этим идентификатором.
sendIdstring or null
Отправка `msg_…`, которой соответствует этот отчёт, и null, если запись об отправке не создавалась. Композер, `sendEmail` из MCP и ассистент отправляют без такой записи. Трекинг охватывает почтовый ящик, а не только API-трафик.
threadIdstring or null
Заполняется после передачи, чтобы интерфейс чтения мог снова найти письмо; null там, где драйвер ничего не сообщил. Не несёт нагрузки: запись с null здесь всё равно учитывается.
messageIdstring or null
Message-ID по RFC 5322, а не наш идентификатор. Тоже заполняется после передачи; null там, где транспорт не вернул ничего, чем его заполнить.
subjectstring or null
Тема в том виде, в каком она была при отправке. null у сообщения, записанного без темы.
fromstring
Адрес отправителя, скопированный в запись, а не подтянутый из отправки. Отчёты читают спустя долгое время, и адрес, с тех пор исправленный или удалённый, иначе переписал бы историю.
sourcestring
Какая поверхность его отправила: `composer`, `api`, `mcp`, `ai` или `queue`. Может появиться поверхность, которую этот пакет пока не называет, поэтому считайте незнакомое значение информацией, а не ошибкой.
sentAtstring or null
Когда сообщение ушло, в виде момента ISO 8601. null у записи, отправка которой так и не завершилась. `tracking->list` такие записи не показывает, а `get` показывает.
opensbool
Был ли к этому письму ПРИМЕНЁН пиксель. Это то, что было сделано, а не то, что говорит настройка аккаунта сейчас.
clicksbool
Были ли переписаны ссылки этого сообщения. False, если в теле не было ссылок, потому что тогда ничего не менялось, а запись, утверждающую обратное, нельзя было бы сверить с байтами.
openedbool
Было ли зафиксировано хоть одно засчитанное открытие среди копий. Читайте его вместе с `opens`: отсутствие данных из-за того, что их не собирали, говорит совсем не о том, что сообщение никто не прочитал.
clickedbool
Был ли зафиксирован хоть один засчитанный клик. Более веское свидетельство, чем открытие, поскольку изображения блокируют гораздо чаще, чем не переходят по ссылкам.
attributablebool
Можно ли каждое прочтение здесь привязать к конкретному получателю. False в тот момент, когда непривязанная копия показывает засчитанную активность: это случай нескольких получателей, когда одно тело уходит всему списку под одним токеном, так что проверьте его, прежде чем писать «Боб это не открывал».
openCountint
Открытия, которые считаются вызванными человеком, просуммированные по копиям. Машинные обращения исключены, а повторы в пределах тридцати секунд схлопываются в одно, так что именно эту цифру стоит показывать читателю.
clickCountint
Засчитанные клики, просуммированные по копиям. Дедуплицируются по ссылке, а не по сообщению, так что две разные ссылки, пройденные с разницей в секунды, дают два клика.
openCountRawint
Каждая загрузка пикселя, включая сканеры и прокси конфиденциальности. `openCountRaw` минус `openCount` показывает, сколько обращений было отсеяно (машинные загрузки и повторы в пределах тридцати секунд вместе), и это единственное доступное свидетельство того, что фильтрация вообще происходила.
clickCountRawint
Каждое посещение переписанной ссылки, включая машинные обращения и повторы.
firstOpenAtstring or null
Самое раннее засчитанное открытие среди копий, и null, пока его нет. Машинные обращения его не сдвигают.
lastOpenAtstring or null
Самое последнее засчитанное открытие среди копий; null, пока его нет.
firstClickAtstring or null
Самый ранний засчитанный клик среди копий; null, пока его нет.
lastClickAtstring or null
Самый последний засчитанный клик среди копий; null, пока его нет.
recipientsarray
По одной записи на каждую отслеживаемую копию: по одной на получателя там, где транспорт позволяет байтам различаться для каждого человека, и одна общая запись там, где не позволяет. Общая запись отбрасывается, если на неё в действительности ничего не попало, поэтому нетронутая строка «кто-то» никогда не стоит рядом с настоящими именами.
linksarray
Все ссылки, переписанные в этом письме, в порядке их расположения в теле. Пусто там, где переписывать было нечего: письмо отправлено с выключенным `clicks` или в его теле вообще не было ссылок.

Каждая запись в recipients

emailstring or null
Кому ушла эта копия, в нижнем регистре и в том виде, в каком адрес был при отправке. null ровно тогда, когда `attributed` равно false.
kindstring or null
`to`, `cc` или `bcc`: в каком заголовке стоял адрес, чтобы отчёт читался так же, как сообщение. null у общей копии, которая не принадлежит ни одному адресу.
attributedbool
Называет ли эта строка конкретного человека. Читайте её раньше `email`: false означает общую копию, которая попадает в список, как только на неё приходит хотя бы одно обращение, и приписать этому обращению имя, даже в письме с единственным получателем, значило бы выдумать тот единственный факт, которого механизм дать не может.
openCountint
Засчитанные открытия только по этой копии, с теми же исключениями, что и в итоге по письму: машинные обращения отброшены, а повторы в пределах тридцати секунд схлопнуты в одно.
clickCountint
Засчитанные клики только по этой копии, с дедупликацией по ссылке, а не по копии.
firstOpenAtstring or null
Самое раннее засчитанное открытие этой копии; null, пока его нет.
lastOpenAtstring or null
Самое последнее засчитанное открытие этой копии; null, пока его нет.
firstClickAtstring or null
Самый ранний засчитанный клик по этой копии; null, пока его нет.
lastClickAtstring or null
Самый последний засчитанный клик по этой копии; null, пока его нет.

Каждая запись в links

idstring
Собственный идентификатор ссылки, `lnk_…`. Именно это значение называет `linkId` в строке клика, поэтому обращение из `listClicks` можно сопоставить с записью здесь.
urlstring
Куда на самом деле ведёт ссылка, в том виде, в каком она была в сообщении до переписывания. Редиректор находит по идентификатору этот адрес и отправляет посетителя дальше.
labelstring or null
Текст ссылки в том виде, в каком он был в сообщении, или null, если его не было, например у изображения или голого URL. Он нужен, чтобы отчёт мог сказать «ссылка на цены», а не цитировать URL с тремя параметрами трекинга, и он никогда не заменяет `url`.
clickCountint
Засчитанные переходы по этой ссылке, просуммированные по копиям. То же тридцатисекундное окно на ссылку, что и у `clickCount` письма.
clickCountRawint
Все переходы по этой ссылке, включая машинные обращения и повторы.