تتبع الفتح والنقر
`emails.get_tracking` ومساحة الأسماء `tracking` كلها.
رسالة واحدة
report = client.emails.get_tracking("msg_3f9a1c07d2b84e6a9c5b1f20") puts "#{report[:openCount]} opens from #{report[:recipients].size} recipients"report[:links].each { |link| puts "#{link[:url]} #{link[:clickCount]}" }الرسالة التي لم تُتتبّع قط ترفع OpenEmail::NotFoundError تكون قيمة not_found? فيه true، لا تقريرًا فارغًا. فـ «لم نسجّل شيئًا» و«لم يفتحها أحد» جوابان مختلفان ويجب ألا يتقاسما استجابة واحدة. والرسالة المرسلة بمفتاح اختبار لا تُتتبّع أبدًا، فهي ترفعه دائمًا.
عبر صندوق البريد
client.tracking.list(opened: false, days: 7, limit: 100)client.tracking.get_stats(days: 30, offset_minutes: Time.now.utc_offset / 60)client.tracking.get("msg_3f9a1c07d2b84e6a9c5b1f20")client.tracking.list_opens("msg_3f9a1c07d2b84e6a9c5b1f20", include_machine: true)client.tracking.list_clicks("msg_3f9a1c07d2b84e6a9c5b1f20")يعيد list وlist_opens وlist_clicks صفحة OpenEmail::Page واحدة، ويمر list_all وiterate وlist_all_opens وiterate_opens وlist_all_clicks وiterate_clicks على كل الصفحات نيابةً عنك. ويأخذ get وlist_opens وlist_clicks إما معرّف الإرسال msg_… وإما معرّف سجل التتبّع نفسه tmsg_….
مساحة أسماء مستقلة لا توابع على emails، والسبب هو التغطية: فـ emails يسرد سجلات الإرسال، وهي لا توجد إلا للبريد الذي عالجته هذه الواجهة. والمحرِّر وأدوات MCP والمساعد جميعها ترسل دون سجل، فالتقرير المبني على emails سيكون تقريرًا عن حركة API الخاصة بك لا عن صندوق البريد.
قراءة الأرقام بأمانة
| الزوج | ما الذي يعنيه |
|---|---|
| opens وclicks | ما طُبّق: أي ما إذا كانت الرسالة قد خرجت ببكسل أو بروابط مُعاد كتابتها. |
| opened وclicked | ما الذي حدث. |
| openCount | الزيارات المحتسَبة. تُستبعَد أدوات الفحص ووكلاء الخصوصية. |
| openCountRaw | كل زيارة. الاستشهاد بهذا الرقم كمقياس للتفاعل هو ما يجعل معدل الفتح يتجاوز 100%. |
| attributable | ما إذا كان بالإمكان أصلًا نسب عملية قراءة إلى مستلم بعينه. |
النسب الواردة من tracking.get_stats محسوبة على الرسائل المتتبَّعة، لا على كل ما أُرسل. ولولا ذلك لبدا صندوق بريد يتتبّع رسالة واحدة من كل عشر وكأنه انهار. وopenRate وclickRate نسب مئوية مقرّبة إلى منزلة عشرية واحدة، مثل 42.5، لا كسور بين 0 و1.
المعاملات: tracking.list
openedBoolean- تختار القيمة `true` الرسائل التي سُجّلت لها عملية فتح محتسَبة واحدة على الأقل، وتختار `false` الرسائل المتتبَّعة التي لم تُسجَّل لها أي عملية. ولا يُعدّ أيٌّ منهما قيمة افتراضية، كما أن `false` لا تعني قط البريد غير المتتبَّع، فهو لا يظهر في هذه القائمة إطلاقًا.
clickedBoolean- المرشّح نفسه لكن للنقرات المحتسَبة، ويُطبَّق باستقلال عن `opened`. ويمكن تمرير كليهما معًا، وعندئذٍ يجب أن تستوفي الرسائل الشرطين معًا.
daysInteger- عدد الأيام التي يُنظر فيها إلى الوراء اعتبارًا من الآن، من 1 إلى 365 وقيمته الافتراضية 30، وأي قيمة خارج هذا المدى تعطي 422. تُقاس النافذة بوقت إنشاء سجل التتبّع، ولا تُدرج إلا السجلات التي خرج إرسالها فعليًا.
minutesInteger- النافذة بالدقائق بدلًا من ذلك، من 1 إلى 527040، وتغلب على `days` حين يُضبط الاثنان. والنافذة الأقصر من يوم تحتاج إلى `grain` أدق.
grainString- `minute` أو `hour` أو `day`، والافتراضي `day`. لا يفعل سوى تقريب بداية النافذة إلى الأدنى، كي تطابق هذه القائمة `get_stats` المقروء بالدقة نفسها، ولا يغيّر شيئًا في شكل الاستجابة.
limitInteger- عدد التقارير في الصفحة، من 1 إلى 200 وقيمته الافتراضية 50، من الأحدث إلى الأقدم. أعد `next_cursor` الخاص بالصفحة بوصفه `cursor:`، مع المرشِّحات نفسها، للصفحة التالية، أو دع `list_all` و`iterate` يمرّان على النافذة كلها.
cursorString- `next_cursor` من الصفحة السابقة، وهو معرّف `tmsg_`.
api_keyString- يسرد بهذا المفتاح بدل مفتاح العميل.
الاستجابة: تقرير التتبّع
يعيد emails.get_tracking وtracking.get تقريرًا واحدًا في صورة Hash بمفاتيح من نوع Symbol، ويعيد tracking.list صفحة منها.
objectString- دائمًا `tracking` على تقرير جُلب بذاته، عبر `tracking.get` أو `tracking.list` أو `emails.get_tracking`. والتقرير نفسه حين يأتي متداخلًا بوصفه `tracking` على رسالة من `emails.get` يصل دون هذا المفتاح، لأنه هناك جزء من تلك الرسالة لا شيء جُلب بذاته.
idString- معرّف سجل التتبّع نفسه، `tmsg_…`. وهو ما يعتمد عليه `list_opens` و`list_clicks` كمفتاح، والمعرّف `msg_…` الممرَّر إليهما يُبحث عنه أولًا على هذا الأساس.
sendIdString or nil- عملية الإرسال `msg_…` التي يرتبط بها هذا التقرير، وnil حيث لم يُكتب أي سجل إرسال. فالمحرِّر و`sendEmail` في MCP والمساعد جميعها ترسل دون سجل. والتتبّع يشمل صندوق البريد، لا حركة API وحدها.
threadIdString or nil- يُملأ بعد البث كي تتمكن واجهة القراءة من العثور على الرسالة مجددًا، ويكون nil حيث لم يبلّغ المُشغِّل عن قيمة. وليس أساسيًا: فالسجل الذي تكون فيه هذه القيمة nil يُحتسب مع ذلك.
messageIdString or nil- ترويسة Message-ID بحسب RFC 5322، لا معرّفنا. تُملأ أيضًا بعد البث، وتكون nil حيث لم يُعِد النقل شيئًا تُملأ به.
subjectString or nil- الموضوع كما كان وقت الإرسال. nil على رسالة سُجّلت دون موضوع.
fromString- عنوان الإرسال، منسوخًا على السجل بدل ضمّه من عملية الإرسال. فالتقارير تُقرأ بعد وقت طويل، وعنوان صُحّح أو أُزيل منذ ذلك الحين كان سيعيد كتابة التاريخ لولا ذلك.
sourceString- الواجهة التي أرسلتها: `composer` أو `api` أو `mcp` أو `ai` أو `queue`. وقد تظهر واجهة لا يسمّيها هذا الـ gem بعد، فعامل القيمة المجهولة كمعلومة لا كخطأ.
sentAtString or nil- متى انطلقت الرسالة، كلحظة ISO 8601. nil على سجل لم يكتمل إرساله قط. ويستبعد `tracking.list` هذه السجلات، أما `get` فلا.
opensBoolean- ما إذا كانت بكسل قد طُبِّقت على هذه الرسالة. هذا ما جرى فعلًا، لا ما يقوله إعداد الحساب الآن.
clicksBoolean- ما إذا كانت روابط هذه الرسالة قد أُعيدت كتابتها. false حين لا يحمل المتن روابط، لأنه لم يتغيّر شيء عندئذ، وسجل يدّعي خلاف ذلك لا يمكن التوفيق بينه وبين البايتات.
openedBoolean- ما إذا كانت قد سُجّلت أي عملية فتح محتسَبة عبر النسخ. اقرأها مقابل `opens`: فغياب البيانات لأنه لم يُجمع منها شيء حقيقةٌ مختلفة عن ألا يكون أحد قد قرأ الرسالة.
clickedBoolean- ما إذا كانت قد سُجّلت أي نقرة محتسَبة. وهي دليل أقوى من عملية الفتح، لأن حجب الصور أكثر شيوعًا بكثير من ترك الروابط دون اتّباع.
attributableBoolean- ما إذا كان بالإمكان نسب كل عملية قراءة هنا إلى مستلم بعينه. تصبح `false` في اللحظة التي تُظهر فيها نسخة غير منسوبة نشاطًا محتسَبًا، وهي حالة تعدّد المستلمين حيث يذهب متن واحد إلى القائمة كلها برمز واحد، فتحقّق منها قبل أن تكتب «لم يفتح Bob هذه الرسالة».
openCountInteger- عمليات الفتح التي يُرجَّح أن إنسانًا هو من تسبّب بها، مجموعةً عبر النسخ. تُستبعَد زيارات الآلات، وتُدمج التكرارات خلال ثلاثين ثانية في واحدة، ولذلك فهذا هو الرقم الذي يُعرض على القارئ.
clickCountInteger- النقرات المحتسَبة، مجموعةً عبر النسخ. وتُزال التكرارات لكل رابط لا لكل رسالة، فاتّباع رابطين مختلفين بفارق ثوانٍ يُعدّ نقرتين.
openCountRawInteger- كل جلب للبكسل، بما في ذلك أدوات الفحص ووكلاء الخصوصية. و`openCountRaw` ناقص `openCount` هو عدد ما نُحّي جانبًا، أي عمليات الجلب الآلية والتكرارات خلال ثلاثين ثانية معًا، وهو الدليل الوحيد المتاح على أن الترشيح جرى أصلًا.
clickCountRawInteger- كل زيارة لرابط أُعيدت كتابته، بما في ذلك زيارات الآلات والتكرارات.
firstOpenAtString or nil- أول فتح محسوب عبر النسخ، وnil ما دام لا يوجد أي منها. والزيارات الآلية لا تحرّكه أبدًا.
lastOpenAtString or nil- أحدث فتح محسوب عبر النسخ، وnil ما دام لا يوجد أي منها.
firstClickAtString or nil- أول نقرة محسوبة عبر النسخ، وnil ما دام لا يوجد أي منها.
lastClickAtString or nil- أحدث نقرة محسوبة عبر النسخ، وnil ما دام لا يوجد أي منها.
recipientsArray<Hash>- مدخل واحد لكل نسخة متتبَّعة: مدخل لكل مستلم حيث يسمح النقل باختلاف البايتات من شخص لآخر، ومدخل واحد مشترك حيث لا يسمح بذلك. ويُسقَط المدخل المشترك ما لم تصله فعليًا أي إصابة، فلا يجلس صف “شخص ما” الذي لم يُمس قط إلى جانب أسماء حقيقية.
linksArray<Hash>- كل رابط أُعيدت كتابته في هذه الرسالة، مرتَّبًا بحسب موضعه في المتن. وتكون فارغة حيث لم يُعَد كتابة أي رابط: رسالة أُرسلت و`clicks` مُعطّلة، أو رسالة لم يحمل متنها أي رابط أصلًا.
كل عنصر في recipients
emailString or nil- الجهة التي ذهبت إليها هذه النسخة، بأحرف صغيرة وكما كانت وقت الإرسال. تكون nil تمامًا عندما تكون `attributed` بقيمة false.
kindString or nil- `to` أو `cc` أو `bcc`: الترويسة التي ظهر فيها العنوان، كي يُقرأ التقرير كما قُرئت الرسالة. nil على النسخة المشتركة، التي لا تخص عنوانًا بعينه.
attributedBoolean- ما إذا كان هذا الصف يسمّي شخصًا. اقرأه قبل `email`: القيمة false تعني النسخة المشتركة، وتُدرَج فور وصول أي إصابة إليها، وإسناد اسم إلى تلك الإصابة، حتى في رسالة ذات مستلم واحد، يختلق الحقيقة الوحيدة التي تعجز الآلية عن توفيرها.
openCountInteger- الفتحات المحتسبة على هذه النسخة وحدها، وفق الاستثناءات نفسها المطبَّقة على إجمالي الرسالة: تُسقَط الزيارات الآلية، وتُدمَج التكرارات خلال ثلاثين ثانية في واحدة.
clickCountInteger- النقرات المحتسبة على هذه النسخة وحدها، بعد إزالة التكرار لكل رابط لا لكل نسخة.
firstOpenAtString or nil- أول فتح محسوب على هذه النسخة، وnil ما دام لا يوجد أي منها.
lastOpenAtString or nil- أحدث فتح محسوب على هذه النسخة، وnil ما دام لا يوجد أي منها.
firstClickAtString or nil- أول نقرة محسوبة على هذه النسخة، وnil ما دام لا يوجد أي منها.
lastClickAtString or nil- أحدث نقرة محسوبة على هذه النسخة، وnil ما دام لا يوجد أي منها.
كل عنصر في links
idString- معرّف الرابط نفسه، `lnk_…`. وهو القيمة التي يسمّيها `linkId` في صف النقرة، فيمكن مطابقة زيارة من `list_clicks` بالعنصر المقابل هنا.
urlString- الوجهة الفعلية للرابط، كما كانت في الرسالة قبل إعادة الكتابة. ويحوّل المُوجِّه المعرّف إلى هذه القيمة ثم يرسل الزائر إليها.
labelString or nil- نص الارتباط كما ظهر في الرسالة، أو nil حيث لم يكن للرابط نص، كصورة أو عنوان URL مجرد. وهو موجود كي يقول التقرير «رابط التسعير» بدل اقتباس عنوان URL يحمل ثلاثة معاملات تتبّع، وهو لا يحل محل `url` أبدًا.
clickCountInteger- الزيارات المحتسبة لهذا الرابط، مجموعةً عبر النسخ. وهي نافذة الثلاثين ثانية نفسها لكل رابط المطبَّقة على `clickCount` في الرسالة.
clickCountRawInteger- كل زيارة لهذا الرابط، بما فيها الزيارات الآلية والتكرارات.