تتبع الفتح والنقر
`emails.getTracking` ومورد `tracking` بأكمله.
رسالة واحدة
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)الرسالة التي لم تُتبّع قط ترمي OpenEmailApiError تكون isNotFound فيه صحيحة، لا تقريرًا فارغًا. فـ «لم نسجّل شيئًا» و«لم يفتحها أحد» جوابان مختلفان ويجب ألا يتقاسما استجابة واحدة.
عبر صندوق البريد
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 وlistClicks مصفوفات عادية. ويأخذ get وlistOpens وlistClicks إما معرّف الإرسال msg_… أو المعرّف الخاص بسجل التتبع tmsg_….
مورد قائم بذاته لا حقول على emails، والسبب هو التغطية: فـ emails يسرد سجلات الإرسال، وهي لا توجد إلا للبريد الذي تولّته هذه الواجهة. أما محرّر الرسائل وأدوات MCP والمساعد فكلها ترسل دون سجل كهذا، فتقرير مبني على emails كان سيكون تقريرًا عن حركة واجهتك لا عن صندوق البريد.
قراءة الأرقام بأمانة
| الزوج | ما الذي يعنيه |
|---|---|
| `opens` / `clicks` | ما طُبّق: أي ما إذا كانت الرسالة قد خرجت ببكسل أو بروابط مُعاد كتابتها. |
| `opened` / `clicked` | ما الذي حدث. |
| `openCount` | الزيارات المحتسَبة. تُستبعَد أدوات الفحص ووكلاء الخصوصية. |
| `openCountRaw` | كل زيارة. الاستشهاد بهذا الرقم كمقياس للتفاعل هو ما يجعل معدل الفتح يتجاوز 100%. |
| `attributable` | ما إذا كان بالإمكان أصلًا نسب عملية قراءة إلى مستلم بعينه. |
النسب الواردة من tracking.getStats محسوبة على الرسائل المتتبَّعة، لا على كل ما أُرسل. ولولا ذلك لبدا صندوق بريد يتتبّع رسالة واحدة من كل عشر وكأنه انهار.
المعاملات: tracking.list
openedboolean- تختار القيمة `true` الرسائل التي سُجّلت لها عملية فتح محتسَبة واحدة على الأقل، وتختار `false` الرسائل المتتبَّعة التي لم تُسجَّل لها أي عملية. ولا يُعدّ أيٌّ منهما قيمة افتراضية، كما أن `false` لا تعني قط البريد غير المتتبَّع، فهو لا يظهر في هذه القائمة إطلاقًا.
clickedboolean- المرشّح نفسه لكن للنقرات المحتسَبة، ويُطبَّق باستقلال عن `opened`. ويمكن تمرير كليهما معًا، وعندئذٍ يجب أن تستوفي الرسائل الشرطين معًا.
daysnumber- عدد الأيام التي يُنظر فيها إلى الوراء اعتبارًا من الآن، من 1 إلى 365 وقيمته الافتراضية 30؛ وأي قيمة خارج هذا المدى تُعيد 422. تُقاس النافذة بوقت إنشاء سجل التتبّع، ولا تُدرج إلا السجلات التي خرج إرسالها فعليًا.
limitnumber- هذا العدد من الرسائل كحدّ أقصى، من 1 إلى 200 وقيمته الافتراضية 50، من الأحدث إلى الأقدم. ولا يوجد cursor هنا: فهذا تقرير على نافذة زمنية لا تدفّق مستمر، ولذلك يحدّه `days` و`limit` ويُقرأ كاملًا.
الاستجابة: TrackingResource
object'tracking'- تساوي دائمًا `'tracking'` في التقرير الذي يُجلب بذاته، عبر `tracking.get` أو `tracking.list` أو `emails.getTracking`. أما التقرير نفسه حين يأتي مضمَّنًا باسم `email.tracking` داخل رسالة مُسترجَعة فيصل دون هذا المفتاح، لأنه هناك جزء من ذلك الكائن لا شيء جرى جلبه.
idstring- معرّف سجل التتبّع نفسه، بالصيغة `tmsg_…`. وهو المفتاح الذي يعتمد عليه الاستدعاءان `listOpens` و`listClicks` الخاصان بكل زيارة؛ وأي `msg_…` يُمرَّر إليهما يُحوَّل إلى هذا المعرّف أولًا.
sendIdstring | null- عملية الإرسال `msg_…` التي يرتبط بها هذا السجل، وقيمته null حيث لم يُكتب أي سجل إرسال. فالمحرِّر و`sendEmail` في MCP والمساعد جميعها ترسل بدون سجل. التتبع يشمل صندوق البريد، لا حركة API وحدها.
threadIdstring | null- يُملأ بعد الإرسال كي تتمكن واجهة القراءة من العثور على الرسالة مجددًا، وقيمته null حيث لم يُبلِّغ المشغّل بشيء. وهو ليس حاملًا للبنية: السجل الذي يحمله بقيمة null يظل محتسبًا.
messageIdstring | null- معرّف Message-ID وفق RFC 5322، لا معرّفنا نحن. ويُملأ هو أيضًا بعد الإرسال، وقيمته null حيث لم يُعِد النقل شيئًا يملؤه به.
subjectstring | null- الموضوع كما كان وقت الإرسال. ويكون null في رسالة سُجّلت بلا موضوع.
fromstring- عنوان الإرسال، منسوخًا على السجل بدل ضمّه من عملية الإرسال. فالتقارير تُقرأ بعد وقت طويل، وعنوان صُحّح أو أُزيل منذ ذلك الحين كان سيعيد كتابة التاريخ لولا ذلك.
sourceEmailSource | (string & {})- الواجهة التي أرسلتها: `composer` أو `api` أو `mcp` أو `ai` أو `queue`. والنوع مفتوح كي لا تكون واجهة لم يسمّها هذا SDK بعدُ تغييرًا كاسرًا.
sentAtstring | null- وقت ذهاب الرسالة، كلحظة بصيغة ISO-8601. ويكون null في سجل لم تكتمل عملية إرساله. و`tracking.list` يستبعد تلك السجلات، بينما `get` لا يستبعدها.
opensboolean- ما إذا كانت بكسل قد طُبِّقت على هذه الرسالة. هذا ما جرى فعلًا، لا ما يقوله إعداد الحساب الآن.
clicksboolean- ما إذا كانت روابط هذه الرسالة قد أُعيدت كتابتها. تكون `false` عندما لا يحمل متن الرسالة أي رابط، إذ لم يُغيَّر حينها شيء، وسجلٌّ يدّعي خلاف ذلك لا يمكن التوفيق بينه وبين البايتات الفعلية.
openedboolean- ما إذا كانت قد سُجّلت أي عملية فتح محتسَبة عبر النسخ. اقرأها مقابل `opens`: فغياب البيانات لأنه لم يُجمع منها شيء حقيقةٌ مختلفة عن ألا يكون أحد قد قرأ الرسالة.
clickedboolean- ما إذا كانت قد سُجّلت أي نقرة محتسَبة. وهي دليل أقوى من عملية الفتح، لأن حجب الصور أكثر شيوعًا بكثير من ترك الروابط دون اتّباع.
attributableboolean- ما إذا كان بالإمكان نسب كل عملية قراءة هنا إلى مستلم بعينه. تصبح `false` في اللحظة التي تُظهر فيها نسخة غير منسوبة نشاطًا محتسَبًا، وهي حالة تعدّد المستلمين حيث يذهب متن واحد إلى القائمة كلها برمز واحد، فتحقّق منها قبل أن تكتب «لم يفتح Bob هذه الرسالة».
openCountnumber- عمليات الفتح التي يُرجَّح أن إنسانًا هو من تسبّب بها، مجموعةً عبر النسخ. تُستبعَد زيارات الآلات، وتُدمج التكرارات خلال ثلاثين ثانية في واحدة، ولذلك فهذا هو الرقم الذي يُعرض على القارئ.
clickCountnumber- النقرات المحتسَبة، مجموعةً عبر النسخ. وتُزال التكرارات لكل رابط لا لكل رسالة، فاتّباع رابطين مختلفين بفارق ثوانٍ يُعدّ نقرتين.
openCountRawnumber- كل جلب للبكسل، بما في ذلك أدوات الفحص ووكلاء الخصوصية. والفرق `openCountRaw - openCount` هو عدد ما نحّاه المصنِّف جانبًا، وهو الدليل الوحيد المتاح على أن الترشيح جرى أصلًا.
clickCountRawnumber- كل زيارة لرابط أُعيدت كتابته، بما في ذلك زيارات الآلات والتكرارات.
firstOpenAtstring | null- أقدم فتح محتسب عبر النسخ، وقيمته null ما دام لا يوجد أي فتح. الزيارات الآلية لا تحركه أبدًا.
lastOpenAtstring | null- أحدث فتح محتسب عبر النسخ، وقيمته null ما دام لا يوجد أي فتح.
firstClickAtstring | null- أقدم نقرة محتسبة عبر النسخ، وقيمتها null ما دام لا توجد أي نقرة.
lastClickAtstring | null- أحدث نقرة محتسبة عبر النسخ، وقيمتها null ما دام لا توجد أي نقرة.
recipientsTrackingRecipientResource[]- مدخل واحد لكل نسخة متتبَّعة: مدخل لكل مستلم حيث يسمح النقل باختلاف البايتات من شخص لآخر، ومدخل واحد مشترك حيث لا يسمح بذلك. ويُسقَط المدخل المشترك ما لم تصله فعليًا أي إصابة، فلا يجلس صف “شخص ما” الذي لم يُمس قط إلى جانب أسماء حقيقية.
recipients[].emailstring | null- الجهة التي ذهبت إليها هذه النسخة، بأحرف صغيرة وكما كانت وقت الإرسال. تكون null تمامًا عندما تكون `attributed` بقيمة false.
recipients[].kind'to' | 'cc' | 'bcc' | null- الترويسة التي ظهر عليها العنوان، كي يُقرأ التقرير كما قُرئت الرسالة. تكون null على النسخة المشتركة التي لا تعود إلى عنوان بعينه.
recipients[].attributedboolean- ما إذا كان هذا الصف يسمّي شخصًا. اقرأه قبل `email`: القيمة false تعني النسخة المشتركة، وتُدرَج فور وصول أي إصابة إليها، وإسناد اسم إلى تلك الإصابة، حتى في رسالة ذات مستلم واحد، يختلق الحقيقة الوحيدة التي تعجز الآلية عن توفيرها.
recipients[].openCountnumber- الفتحات المحتسبة على هذه النسخة وحدها، وفق الاستثناءات نفسها المطبَّقة على إجمالي الرسالة: تُسقَط الزيارات الآلية، وتُدمَج التكرارات خلال ثلاثين ثانية في واحدة.
recipients[].clickCountnumber- النقرات المحتسبة على هذه النسخة وحدها، بعد إزالة التكرار لكل رابط لا لكل نسخة.
recipients[].firstOpenAtstring | null- أقدم فتح محتسب على هذه النسخة، وقيمته null ما دام لا يوجد أي فتح.
recipients[].lastOpenAtstring | null- أحدث فتح محتسب على هذه النسخة، وقيمته null ما دام لا يوجد أي فتح.
recipients[].firstClickAtstring | null- أقدم نقرة محتسبة على هذه النسخة، وقيمتها null ما دام لا توجد أي نقرة.
recipients[].lastClickAtstring | null- أحدث نقرة محتسبة على هذه النسخة، وقيمتها null ما دام لا توجد أي نقرة.
linksTrackingLinkResource[]- كل رابط أُعيدت كتابته في هذه الرسالة، مرتَّبًا بحسب موضعه في المتن. وتكون فارغة حيث لم يُعَد كتابة أي رابط: رسالة أُرسلت و`clicks` مُعطّلة، أو رسالة لم يحمل متنها أي رابط أصلًا.
links[].idstring- معرّف الرابط نفسه، `lnk_…`. وهو القيمة التي يسمّيها الحقل `linkId` في صف النقرة، فيمكن مطابقة إصابة واردة من `listClicks` بالمدخل هنا.
links[].urlstring- الوجهة الفعلية للرابط، كما كانت في الرسالة قبل إعادة الكتابة. ويحوّل المُوجِّه المعرّف إلى هذه القيمة ثم يرسل الزائر إليها.
links[].labelstring | null- نص الارتباط كما ظهر في الرسالة، أو null حيث لم يكن للرابط نص، كصورة أو عنوان URL مجرد. وهو موجود كي يقول التقرير “رابط التسعير” بدل اقتباس عنوان URL يحمل ثلاثة معاملات تتبع، وهو لا يحل محل `url` أبدًا.
links[].clickCountnumber- الزيارات المحتسبة لهذا الرابط، مجموعةً عبر النسخ. وهي نافذة الثلاثين ثانية نفسها لكل رابط المطبَّقة على `clickCount` في الرسالة.
links[].clickCountRawnumber- كل زيارة لهذا الرابط، بما فيها الزيارات الآلية والتكرارات.