Śledzenie otwarć i kliknięć
`emails.getTracking` i cały zasób `tracking`.
Jedna wiadomość
const report = await openemail.emails.getTracking('msg_…') console.log(report.openCount, 'opens from', report.recipients.length, 'recipients')for (const link of report.links) console.log(link.url, link.clickCount)Wiadomość, która nigdy nie była śledzona, rzuca OpenEmailApiError, którego isNotFound jest true, a nie pusty raport. „Nic nie zarejestrowaliśmy” i „nikt tego nie otworzył” to różne odpowiedzi i nie mogą mieć wspólnej odpowiedzi.
W całej skrzynce
await openemail.tracking.list({ opened: false, days: 7, limit: 100 })await openemail.tracking.getStats({ days: 30, offsetMinutes: -new Date().getTimezoneOffset() })await openemail.tracking.get('msg_…')await openemail.tracking.listOpens('msg_…', { includeMachine: true })await openemail.tracking.listClicks('msg_…')list, listOpens i listClicks rozwiązują się do zwykłych tablic. get, listOpens i listClicks przyjmują albo identyfikator wysyłki msg_…, albo własny tmsg_… rekordu śledzenia.
Osobny zasób, a nie pola na emails, i powodem jest pokrycie: emails wymienia rekordy wysyłek, które istnieją tylko dla poczty obsłużonej przez to API. Kompozytor, narzędzia MCP i asystent wysyłają bez takiego rekordu, więc raport zbudowany na emails byłby raportem o Twoim ruchu w API, a nie o skrzynce.
Uczciwe czytanie liczb
| Para | Co oznacza |
|---|---|
| `opens` / `clicks` | Co ZASTOSOWANO: czy wiadomość wyszła z pikselem albo z przepisanymi linkami. |
| `opened` / `clicked` | Co się wydarzyło. |
| `openCount` | Liczone trafienia. Skanery i proxy prywatności wyłączone. |
| `openCountRaw` | Wszystkie trafienia. Podawanie tego jako zaangażowania to sposób, w jaki wskaźnik otwarć przekracza 100%. |
| `attributable` | Czy odczyt da się w ogóle przypisać do konkretnego, nazwanego odbiorcy. |
Wskaźniki z tracking.getStats liczą się względem wiadomości ŚLEDZONYCH, nigdy względem wszystkiego wysłanego. Inaczej skrzynka śledząca jedną wiadomość na dziesięć wyglądałaby, jakby się załamała.
Parametry: tracking.list
openedboolean- `true` wybiera wiadomości z co najmniej jednym liczonym otwarciem, `false` wybiera wiadomości śledzone bez żadnego. Żadna z tych wartości nie jest domyślna, a `false` nigdy nie oznacza poczty nieśledzonej, która na tej liście w ogóle się nie pojawia.
clickedboolean- Ten sam filtr dla liczonych kliknięć, stosowany niezależnie od `opened`. Można podać oba, a wiadomości muszą spełnić oba.
daysnumber- Ile dni wstecz od teraz przeszukać, od 1 do 365, domyślnie 30; poza tym zakresem to 422. Okno mierzy się na czasie utworzenia rekordu śledzenia, a wymieniane są tylko rekordy, których wysyłka faktycznie wyszła.
limitnumber- Najwyżej tyle wiadomości, od 1 do 200, domyślnie 50, od najnowszych. Nie ma kursora: to raport w oknie czasowym, a nie strumień, więc jest ograniczony przez `days` i `limit` i czyta się go w całości.
Odpowiedź: TrackingResource
object'tracking'- Zawsze `'tracking'` na raporcie pobranym samodzielnie, przez `tracking.get`, `tracking.list` albo `emails.getTracking`. Ten sam raport zagnieżdżony jako `email.tracking` na pobranej wiadomości przychodzi bez tego klucza, bo tam jest częścią tamtego obiektu, a nie czymś, co pobrano.
idstring- Własny identyfikator rekordu śledzenia, `tmsg_…`. To na nim kluczowane są wywołania per trafienie, `listOpens` i `listClicks`; przekazany im `msg_…` jest najpierw rozwiązywany do niego.
sendIdstring | null- Wysyłka `msg_…`, z którą to koreluje, i null tam, gdzie nie zapisano rekordu wysyłki. Kompozytor, `sendEmail` z MCP i asystent wysyłają bez niego. Śledzenie obejmuje skrzynkę, a nie tylko ruch API.
threadIdstring | null- Wypełniane po transmisji, żeby interfejs do czytania mógł odnaleźć wiadomość, i null tam, gdzie sterownik nic nie zgłosił. Nie jest nośne: rekord z nullem tutaj i tak się liczy.
messageIdstring | null- Message-ID z RFC 5322, a nie nasz identyfikator. Także wypełniany po transmisji i null tam, gdzie transport nie zwrócił niczego, czym można by go wypełnić.
subjectstring | null- Temat w postaci z chwili wysyłki. Null na wiadomości zapisanej bez niego.
fromstring- Adres nadawczy, skopiowany na rekord, a nie dołączany z wysyłki. Raporty czyta się długo po fakcie, a adres od tego czasu poprawiony albo usunięty inaczej przepisywałby historię.
sourceEmailSource | (string & {})- Która powierzchnia ją wysłała: `composer`, `api`, `mcp`, `ai` albo `queue`. Typowane otwarcie, żeby powierzchnia, której ten SDK jeszcze nie nazywa, nie była zmianą łamiącą.
sentAtstring | null- Kiedy wiadomość poszła, jako instant ISO-8601. Null na rekordzie, którego wysyłka nigdy się nie zakończyła. `tracking.list` takie pomija, `get` nie.
opensboolean- Czy do tej wiadomości ZASTOSOWANO piksel. To, co zrobiono, a nie to, co mówi dziś ustawienie konta.
clicksboolean- Czy linki w tej wiadomości zostały przepisane. False, gdy treść nie niosła żadnych linków, bo wtedy nic nie zmieniono, a rekord twierdzący inaczej nie dałby się pogodzić z bajtami.
openedboolean- Czy zarejestrowano jakiekolwiek liczone otwarcie we wszystkich kopiach. Czytaj to razem z `opens`: brak danych, bo żadnych nie zbierano, to inny fakt niż to, że nikt wiadomości nie przeczytał.
clickedboolean- Czy zarejestrowano jakiekolwiek liczone kliknięcie. Mocniejszy dowód niż otwarcie, bo obrazy są blokowane o wiele częściej, niż linki pozostają nieodwiedzone.
attributableboolean- Czy każdy odczyt tutaj da się przypisać do nazwanego odbiorcy. False w chwili, gdy nieprzypisana kopia wykaże liczoną aktywność, czyli w przypadku wielu odbiorców, gdzie jedna treść idzie do całej listy pod jednym tokenem, więc sprawdź to, zanim napiszesz „Bob tego nie otworzył”.
openCountnumber- Otwarcia uznane za spowodowane przez człowieka, zsumowane po kopiach. Trafienia maszynowe są wyłączone, a powtórzenia w ciągu trzydziestu sekund zwijają się w jedno, więc to jest liczba do pokazania czytelnikowi.
clickCountnumber- Liczone kliknięcia, zsumowane po kopiach. Deduplikowane per link, a nie per wiadomość, więc dwa różne linki odwiedzone w odstępie sekund to dwa kliknięcia.
openCountRawnumber- Każde pobranie piksela, wraz ze skanerami i proxy prywatności. `openCountRaw - openCount` mówi, ile klasyfikator odłożył na bok, i jest jedynym dostępnym dowodem, że filtrowanie w ogóle się odbyło.
clickCountRawnumber- Każda wizyta na przepisanym linku, wraz z trafieniami maszynowymi i powtórzeniami.
firstOpenAtstring | null- Najwcześniejsze liczone otwarcie spośród kopii, null, dopóki go nie ma. Trafienia maszynowe nigdy nim nie ruszają.
lastOpenAtstring | null- Najnowsze liczone otwarcie spośród kopii, null, dopóki go nie ma.
firstClickAtstring | null- Najwcześniejsze liczone kliknięcie spośród kopii, null, dopóki go nie ma.
lastClickAtstring | null- Najnowsze liczone kliknięcie spośród kopii, null, dopóki go nie ma.
recipientsTrackingRecipientResource[]- Po jednym wpisie na każdą śledzoną kopię: per odbiorca tam, gdzie transport pozwala, by bajty różniły się dla każdej osoby, i jeden wspólny wpis tam, gdzie nie pozwala. Wspólny wpis jest pomijany, o ile faktycznie nic na nim nie wylądowało, więc nietknięty wiersz „ktoś” nigdy nie siedzi obok prawdziwych nazwisk.
recipients[].emailstring | null- Do kogo poszła ta kopia, małymi literami i w postaci z chwili wysyłki. Null dokładnie wtedy, gdy `attributed` jest false.
recipients[].kind'to' | 'cc' | 'bcc' | null- W którym nagłówku pojawił się adres, żeby raport czytał się tak, jak czytała się wiadomość. Null na kopii wspólnej, która nie należy do żadnego adresu.
recipients[].attributedboolean- Czy ten wiersz nazywa osobę. Czytaj go przed `email`: false to kopia wspólna, wymieniana, gdy tylko wyląduje na niej jakiekolwiek trafienie, a przypisanie nazwiska do tego trafienia, nawet w wiadomości z jednym odbiorcą, wymyśliłoby jedyny fakt, którego mechanizm nie potrafi dostarczyć.
recipients[].openCountnumber- Liczone otwarcia wyłącznie na tej kopii, przy tych samych wyłączeniach co suma dla wiadomości: trafienia maszynowe odrzucone, a powtórzenia w ciągu trzydziestu sekund zwinięte w jedno.
recipients[].clickCountnumber- Liczone kliknięcia wyłącznie na tej kopii, deduplikowane per link, a nie per kopia.
recipients[].firstOpenAtstring | null- Najwcześniejsze liczone otwarcie na tej kopii, null, dopóki go nie ma.
recipients[].lastOpenAtstring | null- Najnowsze liczone otwarcie na tej kopii, null, dopóki go nie ma.
recipients[].firstClickAtstring | null- Najwcześniejsze liczone kliknięcie na tej kopii, null, dopóki go nie ma.
recipients[].lastClickAtstring | null- Najnowsze liczone kliknięcie na tej kopii, null, dopóki go nie ma.
linksTrackingLinkResource[]- Każdy link przepisany w tej wiadomości, w kolejności, w jakiej stał w treści. Pusta lista tam, gdzie nie było żadnych: wiadomość wysłana z wyłączonym `clicks` albo taka, której treść nie zawierała w ogóle linku.
links[].idstring- Własny identyfikator linku, `lnk_…`. To wartość, którą nazywa `linkId` w wierszu kliknięcia, więc trafienie z `listClicks` da się dopasować z powrotem do wpisu tutaj.
links[].urlstring- Dokąd link faktycznie prowadzi, w postaci sprzed przepisania, taki jak był w wiadomości. Przekierowujący rozwiązuje identyfikator z powrotem do tego adresu i odsyła tam odwiedzającego.
links[].labelstring | null- Tekst odnośnika w postaci, w jakiej pojawił się w wiadomości, albo null, gdy link go nie miał, na przykład przy obrazie albo gołym adresie URL. Jest po to, by raport mógł napisać „link do cennika”, zamiast cytować URL z trzema parametrami śledzącymi, i nigdy nie zastępuje `url`.
links[].clickCountnumber- Liczone wizyty na tym linku, zsumowane po kopiach. To samo trzydziestosekundowe okno per link co przy `clickCount` na wiadomości.
links[].clickCountRawnumber- Każda wizyta na tym linku, wraz z trafieniami maszynowymi i powtórzeniami.