تخطّ إلى المحتوى الرئيسي

إدارة الاشتراكات

يشرح هذا المستند نظام Joryio المتكامل لإدارة الاشتراكات والموافقة: اشتراكات القنوات، والقوائم والموضوعات، ورؤوس RFC 8058 الخاصة بإلغاء الاشتراك، ومعالجة الارتدادات وميزات الامتثال.

المحتويات

  1. نظرة عامة
  2. نماذج البيانات
  3. اشتراكات القنوات
  4. تكامل Web SDK
  5. قوائم الاشتراك
  6. مجموعات الاشتراك لكل رقم
  7. رأس List-Unsubscribe
  8. صفحة التفضيلات
  9. معالجة الارتدادات
  10. متغيرات Liquid
  11. فلاتر الشرائح
  12. مرجع API
  13. الإعداد
  14. الامتثال

نظرة عامة

يوفر نظام إدارة الاشتراكات في Joryio ما يلي:

  • اشتراكات على مستوى القناة: تتبع حالة الموافقة أو إلغاء الموافقة لـ Email وSMS وWhatsApp وPush وViber.
  • اشتراكات قائمة على القوائم: يختار المستخدم موضوعات أو قوائم بريدية محددة.
  • امتثال RFC 8058: رؤوس إلغاء اشتراك بنقرة واحدة لتحسين قابلية تسليم Email.
  • معالجة الارتدادات: تعامل تلقائي مع الارتدادات المؤقتة والدائمة.
  • سجل تدقيق: تاريخ كامل لتغييرات الاشتراك لأغراض الامتثال.
  • تصفية الشرائح: استهداف المستخدمين حسب حالة اشتراكهم.

نماذج البيانات

اشتراك القناة، لكل مستخدم

لكل مستخدم حالة اشتراك لكل قناة تواصل:

interface ChannelSubscription {
status: 'optedIn' | 'subscribed' | 'unsubscribed';
optInDate?: Date;
optOutDate?: Date;
optInSource?: string; // 'api', 'web_form', 'import', 'manual'
consentText?: string; // Consent text shown at opt-in
}

interface EmailSubscription extends ChannelSubscription {
bounceType?: 'soft' | 'hard' | null;
bounceCount?: number;
lastBounceAt?: Date;
isValid?: boolean; // false if hard bounced
}

interface UserSubscriptions {
email?: EmailSubscription;
sms?: ChannelSubscription;
whatsapp?: ChannelSubscription;
push?: ChannelSubscription;
viber?: ChannelSubscription;
}

قائمة الاشتراك

القوائم هي موضوعات أو فئات يستطيع المستخدم الاشتراك فيها:

interface SubscriptionList {
id: string;
organizationId: string;
workspaceId: string;
name: string;
description?: string;
channels: ('email' | 'sms' | 'whatsapp' | 'push' | 'viber')[];
isPublic: boolean; // Show in preference center
type: 'marketing' | 'transactional';
requireDoubleOptIn: boolean;
archivedAt?: Date;
createdAt: Date;
updatedAt: Date;
}

عضوية القائمة

تتبع المستخدمين المشتركين في كل قائمة:

interface ListSubscription {
contactId: string;
listId: string;
channel: 'email' | 'sms' | 'whatsapp' | 'push' | 'viber';
status: 'optedIn' | 'subscribed' | 'unsubscribed';
subscribedAt?: Date;
unsubscribedAt?: Date;
optInSource?: string;
}

اشتراكات القنوات

أنواع الحالة

الحالةالوصف
optedInأكمل المستخدم تأكيد الموافقة المزدوجة
subscribedالمستخدم مشترك عبر موافقة مفردة
unsubscribedألغى المستخدم الاشتراك

تحديث حالة قناة

// Via API
await subscriptionsApi.updateChannelSubscription(userId, 'email', {
status: 'unsubscribed',
source: 'preference_center',
reason: 'User requested via preference center'
});

أفضل الممارسات

  • سجّل مصدر كل تغيير في الاشتراك دائماً.
  • خزّن نص الموافقة عند اشتراك المستخدم.
  • استخدم الموافقة المزدوجة للمستخدمين الأوروبيين امتثالاً لـ GDPR.

تكامل Web SDK

يتيح لك Joryio Web SDK إدارة تفضيلات اشتراك المستخدم من موقعك أو تطبيق الويب مباشرة.

التثبيت

<!-- Via script tag (served from the Joryio API) -->
<script src="https://api-eu1.joryio.com/sdk/web/latest/joryio.min.js"></script>

<!-- Or via npm -->
npm install @joryio/web-sdk

حالات الاشتراك في SDK

الحالةالوصف
SubscriptionStatus.OPTED_INوافق المستخدم صراحة، مثل تأكيد الموافقة المزدوجة
SubscriptionStatus.SUBSCRIBEDالمستخدم مشترك لكنه لم يقدّم موافقة صريحة
SubscriptionStatus.UNSUBSCRIBEDألغى المستخدم الاشتراك

ضبط اشتراكات القنوات

import { JoryioSDK, SubscriptionStatus } from '@joryio/web-sdk';

const sdk = new JoryioSDK({ sdkKey: 'jry_sdk_web_...' });

// Set subscription for a single channel (write-only for security - no getters)
sdk.user.setSubscription('email', SubscriptionStatus.OPTED_IN);
sdk.user.setSubscription('sms', SubscriptionStatus.SUBSCRIBED);
sdk.user.setSubscription('push', SubscriptionStatus.UNSUBSCRIBED);
sdk.user.setSubscription('whatsapp', SubscriptionStatus.SUBSCRIBED);

// Set multiple channels at once
sdk.user.setSubscriptions({
email: SubscriptionStatus.OPTED_IN,
sms: SubscriptionStatus.UNSUBSCRIBED,
whatsapp: SubscriptionStatus.SUBSCRIBED,
push: SubscriptionStatus.OPTED_IN
});

إدارة مجموعات الاشتراك، القوائم

// Add user to a subscription group/list
sdk.user.addToSubscriptionGroup('newsletter-list-id', 'email');
sdk.user.addToSubscriptionGroup('product-updates-id', 'push');

// Remove user from a subscription group/list
sdk.user.removeFromSubscriptionGroup('newsletter-list-id', 'email');

// The channel parameter is optional, defaults to 'email'
sdk.user.addToSubscriptionGroup('weekly-digest-id');

ملاحظات أمنية

كائن المستخدم في SDK للكتابة فقط لأسباب أمنية:

  • لا توجد دالة getSubscriptions() كي لا تستطيع المواقع أو البرامج الأخرى قراءة اشتراكات المستخدم.
  • لا توجد دوال قراءة؛ جميع العمليات تكتب باتجاه واحد إلى الخلفية.
  • تصادق كل الطلبات بمفتاح SDK الخاص بك.
  • يتصرف SDK دائماً بصفته «المستخدم الحالي». لا تأخذ setSubscription وaddToSubscriptionGroup معرّف مستخدم مستهدفاً؛ بل تطبّقان على من عرّفه SDK حالياً، سواء زائراً مجهولاً أو مستخدماً مرّرته إلى identify(). لا يمكن لزائر تغيير اشتراكات زائر آخر عبر SDK.
  • عند تفعيل مصادقة SDK، تتطلب تغييرات الاشتراك مستخدماً معرّفاً. لا يمكن ربط anonymousId المولد في العميل تشفيرياً برمزك الموقّع، ولذلك يُرفض تغيير اشتراك لزائر مجهول فقط. استدعِ identify(userId) أولاً ليصبح التغيير مرتبطاً بالرمز. عند إيقاف مصادقة SDK، تبقى موافقة أو إلغاء اشتراك الزائر المجهول مقبولة كما كانت.

دعم TypeScript

import {
JoryioSDK,
SubscriptionStatus,
SubscriptionChannel,
SubscriptionPreferences
} from '@joryio/web-sdk';

const sdk = new JoryioSDK({ sdkKey: 'jry_sdk_web_...' });

const preferences: SubscriptionPreferences = {
email: SubscriptionStatus.OPTED_IN,
sms: SubscriptionStatus.UNSUBSCRIBED,
};

sdk.user.setSubscriptions(preferences);

const channel: SubscriptionChannel = 'email';
sdk.user.setSubscription(channel, SubscriptionStatus.OPTED_IN);

مثال: صفحة إعدادات التفضيلات

// On your settings page
function handleSubscriptionToggle(channel, isEnabled) {
sdk.user.setSubscription(
channel,
isEnabled ? SubscriptionStatus.SUBSCRIBED : SubscriptionStatus.UNSUBSCRIBED
);
}

// Usage
handleSubscriptionToggle('email', true); // Subscribe to email
handleSubscriptionToggle('sms', false); // Unsubscribe from SMS

مثال: الاشتراك في النشرة

function subscribeToNewsletter(email) {
// First identify the user
sdk.identify(email);
sdk.setAttributes({ email: email });

// Then subscribe to the newsletter list
sdk.user.setSubscription('email', SubscriptionStatus.OPTED_IN);
sdk.user.addToSubscriptionGroup('newsletter-list-id', 'email');
}

قوائم الاشتراك

إنشاء قائمة

const list = await listsApi.create({
name: 'Weekly Newsletter',
description: 'Our weekly digest of product updates',
channels: ['email'],
isPublic: true, // Show in preference center
type: 'marketing',
requireDoubleOptIn: false
});

إدارة الأعضاء

// Subscribe a user to a list
await subscriptionsApi.subscribeToList(userId, listId, 'email', {
source: 'api',
consentText: 'Weekly newsletter signup'
});

// Unsubscribe a user
await subscriptionsApi.unsubscribeFromList(userId, listId, 'email');

// Bulk operations (never re-subscribe contacts who opted out)
await listsApi.bulkAddMembers(listId, contactIds, 'email');
await listsApi.bulkRemoveMembers(listId, contactIds, 'email');

قوائم عامة أو خاصة

  • العامة، isPublic: true: تظهر في مركز التفضيلات ويمكن للمستخدم إدارتها بنفسه.
  • الخاصة، isPublic: false: يديرها المشرفون فقط ولا تظهر للمستخدمين.

مجموعات الاشتراك لكل رقم، SMS وWhatsApp

تعمل قائمة اشتراك مرتبطة بمرسل محدد، أي تحمل senderId، كمجموعة اشتراك لكل رقم. في SMS تكون لكل رقم؛ وفي WhatsApp تكون لكل WABA، أي WhatsApp Business Account. يتيح ذلك لجهة الاتصال إلغاء رسائل رقم أو WABA واحد مع بقائها مشتركة في الآخرين.

نطاق تخزين إلغاء الاشتراك

  • يخزّن إلغاء الاشتراك لكل مجموعة. تحتفظ كل مجموعة لكل رقم بحالتها، منفصلة عن موافقة جهة الاتصال العامة للقناة وعن الأرقام أو WABA الأخرى.
  • تحترم الإرسالات من الحملات والرحلات كليهما الإلغاء. قبل الإرسال يفحص النظام حالة إلغاء المستلم لمجموعة رقم الإرسال أو WABA. إن ألغى هذه المجموعة، يُتخطى الإرسال. وفي الرحلة، ينتقل الشخص إلى الخطوة التالية؛ تتخطى الرسالة فقط لا الرحلة.
  • رقم SMS الافتراضي. عند الإرسال من رقم مساحة العمل الافتراضي، يُنسب إلغاء الاشتراك إلى مجموعة هذا الرقم الافتراضي.

نطاق STOP وSTART الواردين

تطبق كلمة الرد على الرقم المحدد في SMS أو WABA المحدد في WhatsApp الذي استقبل الرسالة:

  • STOP وكل كلمة إلغاء أخرى عدا STOPALL تخص مجموعة الرقم أو WABA فقط.
  • STOPALL يخص القناة كلها، فيلغي كل أرقامها أو WABA فيها.
  • START يعيد الاشتراك في مجموعة الرقم أو WABA نفسها.
عنوان webhook الوارد مرتبط بمساحة عمل واحدة

مساحات العمل علامات تجارية منفصلة، لذا فإن STOP يلغي اشتراك جهة الاتصال من تلك العلامة التجارية - لا من الحساب بأكمله. هذا النطاق يأتي من عنوان webhook الوارد، الذي يحمل مساحة عمل واحدة.

لا يستطيع Joryio استنتاج العلامة التجارية من الرسالة نفسها. يُعرَّف المرسلون بـالاسم (مثل Acme)، بينما يصل الرد إلى رقم هاتف - فلا يوجد ما يربط بينهما.

لذلك تُسجَّل كل ردّ وكل إلغاء اشتراك يصل إلى عنوان وارد معيّن في مساحة عمل ذلك العنوان. إذا كان حساب مزوّد واحد يخدم أكثر من علامة تجارية، فاضبط عنوانًا واردًا منفصلًا لكل رقم في بوابة المزوّد، أو امنح كل علامة تجارية حساب مزوّد خاصًا بها. وإلا فإن STOP الموجّه للعلامة (ب) سيُسجَّل على العلامة (أ)، وستستمر العلامة (ب) في الإرسال.

الكلمات المفتاحية

تعالج كلمات SMS الواردة ثلاث طبقات تُدمج وقت المطابقة: أساس إنجليزي دائم، وافتراضيات مترجمة مفعلة، وإضافاتك المخصصة.

الأساس الإنجليزي، مفعل دائماً ولا يمكن إزالته

النوعالكلمات
إلغاء الاشتراكSTOP, STOPALL, UNSUBSCRIBE, CANCEL, END, QUIT, REVOKE, OPTOUT
الاشتراكSTART, YES, UNSTOP, SUBSCRIBE, OPTIN
المساعدةHELP, INFO
أساس FCC لشهر أبريل 2025

REVOKE وOPTOUT جزء من أساس إلغاء الاشتراك، وفق قاعدة FCC لشهر أبريل 2025 بشأن إبطال موافقة SMS. يُحترمان دائماً، ولا تحتاج إلى إضافتهما أو تفعيلهـما.

الافتراضيات المحلية، مفعلة وتُضاف إلى الأساس

يتعرف النظام تلقائياً على كلمات الإلغاء والاشتراك والمساعدة الشائعة بلغات أخرى، ليتمكن الشخص من الإلغاء بلغته:

اللغةإلغاء الاشتراكالاشتراكالمساعدة
العبريةהסר, הסרה, עצור, ביטול, הפסקהתחל, הצטרף, כןעזרה, מידע
الإسبانيةPARE, BASTA, CANCELAR, ALTOSI, ALTAAYUDA
الفرنسيةARRET, ARRÊT, DESABONNEROUIAIDE
الألمانيةSTOPP, ABBESTELLENJAHILFE
البرتغاليةPARAR, SAIR--

إضافات مخصصة، لكل منظمة

من الإعدادات ← SMS / الاشتراكات يمكنك إضافة كلمات الإلغاء والاشتراك والمساعدة الخاصة بك، وكذلك كلمات إلغاء للقناة كلها. تظهر الطبقة الثابتة والافتراضيات المحلية للقراءة فقط بجانب قائمتك القابلة للتعديل، لذا تدير إضافاتك فقط. تضبط كلمات SMS على مستوى المنظمة.

WhatsApp

النوعالكلمات
إلغاء الاشتراكSTOP, STOPALL, UNSUBSCRIBE, CANCEL, END, QUIT, OPTOUT, OPT-OUT
الاشتراكSTART, UNSTOP, SUBSCRIBE, YES, OPTIN, OPT-IN

STOPALL وحدها على مستوى القناة؛ وكل كلمة إلغاء أخرى تخص مجموعة الرقم أو WABA. وتنطبق القاعدة نفسها على أي كلمات إلغاء عامة للقناة تضيفها لـ SMS.

مطابقة متسامحة مع الفروق البسيطة

المطابقة الواردة غير حساسة لحالة الأحرف وعلامات الترقيم والمسافات، امتثالاً لإرشادات CTIA التي تتطلب احترام الفروق البسيطة. قبل المطابقة، يطبّع النظام الكلمة الأولى ونص الرسالة كله: يزيل علامات الترقيم والمسافات المحيطة ويحّول حروف ASCII إلى كبيرة. لذلك تعد Stop وSTOP! و" stop " وSTOP. جميعاً STOP.

التطبيع آمن للنصوص غير ASCII: لا تملك العبرية والعربية وغيرهما حالة أحرف، فتمر كما هي؛ ولا يُزال إلا الترقيم أو المسافات المحيطة.

إعادة الاشتراك بعد الإلغاء

تعتمد العودة على طريقة الإلغاء:

  • أرسل الشخص STOP أو كلمة إلغاء عبر SMS: يجب أن يرسل START. يضع الناقل، مثل Twilio، حظراً على مستوى الناقل على هذا الرقم، ولا توجد API لمسحه. السبيل الوحيد هو أن يرسل الشخص نفسه START أو كلمة اشتراك أخرى من الهاتف نفسه. لا يعيد Joryio اشتراك من أرسل STOP قسراً؛ إعادة الاشتراك بمبادرة جهة الاتصال دائماً.
  • ألغى عبر صفحة مستضافة أو مركز التفضيلات: يمكنه إعادة الموافقة من الموقع. يمكن لمن ألغى عبر رابط أو مركز تفضيلات، لا برسالة نصية، أن يشترك من جديد بالطريقة ذاتها، مثل {{ resubscribe_url }} أو تفعيل SMS مجدداً في مركز التفضيلات.

الأسبقية والإجراء الآمن

  • إلغاء القناة العامة يتغلب على المجموعات. إلغاء SMS أو WhatsApp بالكامل هو مفتاح إيقاف حاسم؛ لا تعيد أي مجموعة لكل رقم تفعيل الإرسال إلى جهة الاتصال.
  • الإخفاق الآمن إلى القناة كلها. إذا تعذر حل مجموعة الرقم أو WABA، يطبق النظام الإلغاء على القناة كلها بدلاً من المخاطرة بمواصلة الرسائل.

أمن الرسائل الواردة

  • تتحقق توقيعات webhooks الواردة؛ وتُرفض رسائل STOP وSTART المزورة.
  • يُرفض مزود لا يدعم التحقق من توقيع الوارد للكلمات الواردة.
أسماء المرسلين الأبجدية الرقمية لا تتلقى STOP

تعمل مجموعة لكل رقم فقط مع مرسل يستطيع تلقي الردود. رقم الهاتف ثنائي الاتجاه ويمكن للمستلم الرد، فتعمل STOP وكلمات الإلغاء. أما الاسم الأبجدي الرقمي فأحادي الاتجاه ولا يستطيع المستلم الرد عليه؛ لذلك لا تعمل كلمات الإلغاء عليه. يعتمد توفر هذه الأسماء على إعداد مزود SMS لديك.

نطاق رابط إلغاء الاشتراك في عقد SMS وViber للرحلات

تحمل خطوة رسالة SMS أو Viber في رحلة رابط إلغاء اشتراك تستطيع اختيار نطاقه لكل عقدة. يحدد مرسل From قائمة الاشتراك؛ ولذلك يزيل الرابط، وSTOP الوارد، جهة الاتصال من قائمة هذا المرسل فقط افتراضياً، وتبقى قابلة للوصول من مرسلين آخرين.

الاختيارالسلوك
قائمة هذا المرسل، الافتراضييخرج الرابط جهة الاتصال من قائمة الرقم أو المرسل فقط، تماماً كنطاق STOP.
كل SMS / كل Viber، عاميخرج الرابط جهة الاتصال من القناة كلها، وهو مكافئ لـ STOPALL.

الخيار الافتراضي هو الأدق والأقل مفاجأة. وسّعه إلى العام فقط إن كانت العقدة تمثل إلغاءً على مستوى القناة. ويعكس ذلك نطاق List-Unsubscribe في Email، global مقابل list، كنموذج عالمي مقابل قائمة يطبق لكل عقدة في SMS وViber.


إلغاء Email يتبع العنوان، جهات اتصال مكررة

يمكن أن يخص عنوان Email نفسه أكثر من جهة اتصال في مساحة عمل واحدة، كأن يُستورد شخص مرتين أو ينشأ من مصادر مختلفة. تُسجل إلغاءات Email والارتدادات الدائمة على عنوان Email ضمن مساحة العمل، لا على سجل جهة الاتصال المستلمة وحده. لذلك يُحترم الإلغاء للشخص ولا يضيع لأن سجلاً مكرراً ما زال يبدو مشتركاً.

ما يعنيه ذلك

  • الإلغاء يغطي كل التكرارات. عند الإلغاء من رابطك أو رأس List-Unsubscribe أو صفحة التفضيلات أو شكوى الرسائل المزعجة، تُمنع كل جهات الاتصال في المساحة ذات العنوان نفسه، لا التي وصلتها الرسالة فقط.
  • عام مقابل قائمة. الإلغاء العام يمنع العنوان في القناة كلها، بكل الحملات والرحلات. إلغاء قائمة أو موضوع يمنعه من تلك القائمة فقط ويبقى متاحاً للقوائم الأخرى.
  • الارتداد الدائم يتبع العنوان أيضاً. يمنع العنوان في المساحة كلها، فلا يستطيع سجل مكرر إرسال البريد إلى صندوق ميت. لا تزيل إعادة الاشتراك اللاحقة منع قابلية التسليم؛ لا يعيده إلا تغيير Email حقيقي أو مسح يدوي، لحماية سمعة المرسل.
  • محدود بمساحة العمل. يرتبط المنع بالمساحة التي أرسلت البريد. لا يصمت العنوان في مساحة عمل أخرى للحساب نفسه.
  • تجاوز المعاملات. إرسال المعاملات أو all الذي يصل إلى كل جهات الاتصال يتجاوز إلغاء الموافقة، لكن لا يرسل أبداً إلى عنوان ارتد دائماً.

يفحص إرسال الحملات والرحلات ذلك وقت الإرسال، لذلك يبقى سجل مكرر أُنشئ بعد الإلغاء ممنوعاً أيضاً.


رأس List-Unsubscribe، RFC 8058

نظرة عامة

يعرف RFC 8058 طريقة قياسية لعملاء البريد لتقديم إلغاء بنقرة واحدة. يضيف Joryio هذه الرؤوس تلقائياً إلى البريد الصادر.

الرؤوس المضافة

List-Unsubscribe: <https://api-eu1.joryio.com/u/{token}>
List-Unsubscribe-Post: List-Unsubscribe=One-Click

الإعداد

فعّل الميزة في إعدادات مساحة العمل:

subscriptionSettings: {
listUnsubscribe: {
enabled: true,
includeMailto: true, // Include mailto: link (recommended for Gmail)
scope: 'global' // 'global' or 'list'
}
}

خيارات النطاق

النطاقالسلوك
globalيلغي الاشتراك بنقرة واحدة من جميع اتصالات Email
listيلغي الاشتراك من القائمة المحددة التي أُرسل منها Email فقط

تحكم على مستوى الحملة

في حملة Email، تحتوي خطوة الإنشاء على اختيار إلغاء الاشتراك يتحكم في وجود الرابط والرأس بنقرة واحدة وفي ما يزيله:

  • إلغاء عام، الافتراضي: يُضاف الرأس ويزيل الإلغاء المستلم من Email كله في مساحة العمل. وهو الخيار المعتاد للبريد التسويقي.
  • إلغاء الاشتراك من: <topic>، يظهر فقط مع قوائم اشتراك: يُضاف الرأس ويزيل المستلم من هذا الموضوع فقط، مع بقاء المواضيع الأخرى. ويؤدي اختيار الموضوع أيضاً إلى تخطي من ألغوه بالفعل.
  • لا إلغاء اشتراك، للمعاملات فقط: يلغي رأس List-Unsubscribe لهذه الرسالة، مثل الإيصالات وإعادات تعيين كلمة المرور والرموز لمرة واحدة، وهي معفاة من متطلبات إلغاء الاشتراك.

الاستهداف مقابل نطاق الإلغاء. هذا التحكم يتعلق بالرابط أو الرأس فقط ولا يصفّي المستلمين. للإرسال إلى مشتركي موضوع فقط، أضف فلتر عضو في قائمة في خطوة الجمهور؛ فهو يستثني من ألغوا القائمة ويقيّم عند الإرسال.

لا تملك SMS وWhatsApp رأس RFC 8058، لذا تعرضان بدلاً منه اختيار موضوع إلغاء الاشتراك، عام أو موضوع محدد، بالمعنى نفسه. لا يوجد خيار «لا إلغاء» لأن STOP يُحترم دائماً.

عند الإرسال، يتقدم اختيار الحملة على سياسة مساحة العمل. الشكل المخزن:

campaign.channelConfig = {
// omit listUnsubscribe entirely to inherit the workspace policy (= Global)
listUnsubscribe: {
enabled: false, // "No unsubscribe": suppress the header for this campaign
},
};
// Topic scope is stored separately as the campaign's subscriptionCategoryId.

الامتثال: اختر «لا إلغاء» فقط لرسائل معاملات أو علاقة حقيقية. يتطلب البريد الجماعي والتسويقي رأس List-Unsubscribe وفق قواعد المرسلين الجماعيين في Gmail وYahoo.


صفحة التفضيلات بتصميم مخصص

يرى المستلمون افتراضياً مركز تفضيلات Joryio المدمج عند النقر على إلغاء الاشتراك أو إدارة التفضيلات. يمكنك استبداله بصفحتك ذات العلامة التجارية.

المكان: الإعدادات ← الاشتراكات ← صفحة التفضيلات.

الصفحة لكل مساحة عمل ولها ثلاثة أوضاع:

  • افتراضي مدمج: مركز تفضيلات Joryio القياسي، بمفاتيح القنوات والقوائم؛ يعمل دائماً ولا يحتاج إعداداً.
  • HTML مخصص: محرر HTML/Liquid كامل مع معاينة مباشرة ببيانات تجريبية.
  • إعادة التوجيه إلى URL: تجاوز الصفحة كلياً وإرسال المستلم إلى صفحتك. يسجل رابط الإلغاء الإلغاء أولاً ثم يعيد التوجيه إلى URL مع ?email=…&status=unsubscribed. أما رابط إدارة التفضيلات فيعيد التوجيه مع ?token=… لتستخدمه صفحتك في قراءة التفضيلات وكتابتها عبر API العام. يظل الامتثال محفوظاً في الحالتين.

كيف تعمل

  • اكتب جسم الصفحة في HTML، ويمكنه استخدام Liquid: التخصيص مثل {{ firstName }} و{{ email }}، وكتل المحتوى مثل {{ blocks.<slug> }}، ووسوم الاشتراك أدناه.
  • ضع الوسم {{ preferences_form }} حيث يجب أن تظهر أدوات الاشتراك الفعلية، مفاتيح القنوات والقوائم وحفظ وإلغاء الاشتراك من الكل. يعرض Joryio النموذج العامل في هذا الموضع.
  • إذا حذفت الوسم، تُلحق الأدوات تلقائياً في النهاية، ليتمكن المستلم دائماً من الإلغاء، وينبهك المحرر إلى غيابه.
  • تُعرض الصفحة من الخادم لكل مستلم، فتكون روابط الإلغاء والتخصيص حقيقية، ثم تُنقح قبل وصولها إلى المتصفح: يبقى التخطيط والصور والأنماط المضمنة وكتلة <style> محددة النطاق، وتزال البرامج ومعالجات الأحداث وiframes وعناصر <form> وCSS الذي يحمل برامج.

الوسوم المتاحة

الوسمالوصف
{{ preferences_form }}أدوات الاشتراك الفعلية، ضعها مرة واحدة
{{ unsubscribe_url }}رابط الإلغاء العام
{{ preferences_url }}رابط العودة إلى الصفحة
{{ resubscribe_url }}رابط إعادة الاشتراك
{{ firstName }} / {{ email }}تخصيص المستلم
{{ blocks.<slug> }}كتلة محتوى قابلة لإعادة الاستخدام

ملاحظات

  • يقبل الترميز الكامل للصفحة، <html> و<head> و<body>؛ فالصفحة شاشة مستقلة، ويُعرض محتوى الجسم وأنماطه.
  • تخدم الصفحة نفسها رابط الإلغاء بنقرة واحدة، /u/:token، ورابط إدارة التفضيلات، /preferences/:token.
  • تقدم الصفحة المدمجة اختيارياً سبباً لإلغاء الاشتراك، يسجل في سجل التدقيق وحدث message.unsubscribed، وإجراء إعادة الاشتراك في الكل. ويعيد {{ resubscribe_url }}، الذي يضيف ?action=resubscribe، الاشتراك عند فتحه.

معالجة الارتدادات

أنواع الارتداد

النوعالوصفالإجراء
ارتداد مؤقتفشل تسليم مؤقت، مثل امتلاء الصندوق أو توقف الخادميُعد خلال نافذة، ثم يتحول إلى ارتداد دائم إن زاد عن الحد
ارتداد دائمفشل تسليم دائم، مثل عنوان غير صالح أو نطاق غير موجوديُعلّم Email بأنه غير صالح ويمنع الإرسال إليه

يعلّم الارتداد الدائم العنوان غير صالح ويوقف الإرسال، لكنه لا يلغي اشتراك جهة الاتصال، لأنها لم تطلب الإلغاء وتبقى موافقتها كما هي. إزالة حالة الارتداد، مثلاً بعد تغيير Email، تجعله قابلاً للإرسال مجدداً. يتبع المنع عنوان Email عبر كل جهات الاتصال المكررة في مساحة العمل. يتحمل النظام الارتداد المؤقت حتى softBounceMaxRetries مرة ضمن softBounceRetryHours، وبعدها يعامله كارتداد دائم.

الإعداد

subscriptionSettings: {
bounceHandling: {
softBounceRetryHours: 24, // Window in which soft bounces are counted
softBounceMaxRetries: 5, // Soft bounces in-window before escalating to a hard bounce
resubscribeOnEmailChange: true // Clear the invalid flag when the email changes
}
}

تكامل webhook

يعالج Joryio تلقائياً webhooks الارتداد من:

  • Amazon SES عبر إشعارات SNS.
  • SendGrid عبر Event webhooks.
  • Mailgun عبر Webhooks.

تُضبط webhooks الأحداث والارتداد من الموفر أثناء التهيئة، ثم تتدفق الأحداث تلقائياً.

مسح الارتداد يدوياً

يمكن للمشرفين مسح حالة الارتداد من الواجهة أو API:

await subscriptionsApi.clearBounceStatus(userId, 'Email confirmed valid by user');

متغيرات قوالب Liquid

المتغيرات المتاحة

استخدم هذه في قوالب Email:

المتغيرالوصف
{{ unsubscribe_url }}رابط الإلغاء العام
{{ unsubscribe_url_list }}رابط إلغاء خاص بالقائمة
{{ category_unsubscribe_url }}إلغاء من قائمة اشتراك Email، وهو اسم بديل لرابط القائمة ويرجع إلى العام عند غيابه
{{ preferences_url }}رابط مركز التفضيلات
{{ resubscribe_url }}رابط إعادة الاشتراك لحملات الاستعادة

مثال للاستخدام

<p>Don't want to receive these emails?</p>
<p>
<a href="{{ unsubscribe_url_list }}">Unsubscribe from this list</a>
or
<a href="{{ preferences_url }}">Manage your preferences</a>
</p>

فلاتر الشرائح

أنواع الفلاتر

توجد ثلاثة فلاتر جديدة للتقسيم.

فلتر اشتراك القناة

استهدف المستخدمين بحالة اشتراك القناة:

{
type: 'channel_subscription',
operator: 'subscribed_to_channel', // or 'not_subscribed_to_channel'
channel: 'email',
subscriptionStatus: 'opted_in' // optional: specific status
}

فلتر عضوية القائمة

استهدف المستخدمين بعضوية القائمة:

{
type: 'list_membership',
operator: 'member_of_list', // or 'not_member_of_list'
listId: 'list-uuid',
channel: 'email' // optional: specific channel
}

فلتر حالة الارتداد

استهدف المستخدمين حسب صلاحية Email:

{
type: 'bounce_status',
operator: 'email_valid' // 'email_valid', 'email_bounced',
// 'email_hard_bounced', 'email_soft_bounced'
}

حالات الاستخدام

  1. الإرسال إلى من وافقوا فقط:
    { type: 'channel_subscription', operator: 'subscribed_to_channel',
    channel: 'email', subscriptionStatus: 'opted_in' }
  2. استبعاد عناوين Email المرتدة:
    { type: 'bounce_status', operator: 'email_valid' }
  3. استهداف مشتركي النشرة:
    { type: 'list_membership', operator: 'member_of_list',
    listId: 'newsletter-list-id' }

مرجع API

يوجد مرجع REST الكامل لإدارة موافقة القنوات وقوائم الاشتراك وعضوية القوائم، بكل نقاط النهاية وأمثلة الطلب والاستجابة والنطاقات المطلوبة، في صفحة Subscriptions API.

نقطتان مهمتان قبل الاستدعاء:

  • يمكنك الاشتراك وقت الإنشاء. يقبل POST /users مصفوفة subscriptions اختيارية تطبق في الطلب نفسه. راجع Users API. لا تعيد اشتراكات الإنشاء إحياء إلغاء قائم؛ تحتاج إعادة الموافقة لجهة اتصال ألغت إلى نقطة نهاية الاشتراك المخصصة.
  • :userId في هذه المسارات هو id الداخلي لجهة الاتصال في Joryio، كما يعيده Users API، لا معرّف المستخدم الخارجي لديك.

مثال لموافقة اعتيادية: اشتراك جهة اتصال في قائمة على قناة Email:

curl -X POST https://api-eu1.joryio.com/subscriptions/contacts/665f1c2ab3d4e5f6a7b8c9d0/lists/3f6c1a2e-9d4b-4f0a-8c7e-1b2d3e4f5a6b \
-H "Authorization: Bearer jry_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "channel": "email", "source": "api", "consentText": "Weekly newsletter signup" }'

نقاط نهاية عامة، بلا مصادقة

// One-click unsubscribe (RFC 8058)
POST /u/:token

// Get preferences
GET /preferences/:token

// Save preferences
POST /preferences/:token
Body: { channels: [...], lists: [...] }

نقاط نهاية SDK، مصادقة مفتاح SDK

تستخدم Web SDK هذه النقاط وتصادق عبر رأس X-SDK-Key:

// Update channel subscription
POST /v1/subscriptions/channel
Headers: { 'X-SDK-Key': 'jry_sdk_web_...' }
Body: {
channel: 'email' | 'sms' | 'whatsapp' | 'push' | 'viber',
status: 'optedIn' | 'subscribed' | 'unsubscribed',
userId?: string, // Use if user is identified
anonymousId?: string // Use if user is anonymous
}

// Update subscription group (list) membership
POST /v1/subscriptions/group
Headers: { 'X-SDK-Key': 'jry_sdk_web_...' }
Body: {
groupId: string, // List ID
channel: 'email' | 'sms' | 'whatsapp' | 'push' | 'viber',
action: 'subscribe' | 'unsubscribe',
userId?: string,
anonymousId?: string
}

الإعداد

إعدادات مساحة العمل

اضبط إعدادات الاشتراك في الإعدادات > الاشتراكات:

interface SubscriptionSettings {
listUnsubscribe?: {
enabled: boolean;
includeMailto: boolean;
scope: 'global' | 'list';
};
bounceHandling?: {
softBounceRetryHours: number; // Window for counting soft bounces
softBounceMaxRetries?: number; // Soft bounces in-window before escalating to hard
resubscribeOnEmailChange: boolean; // Clear the invalid flag when the email changes
};
doubleOptIn?: {
defaultEnabled: boolean;
confirmationEmailTemplateId?: string;
};
bccEmail?: string; // For compliance archiving
}

الامتثال

ضمان تذييل إلغاء الاشتراك

حتى لا يخرج Email تسويقي من دون وسيلة للإلغاء:

  • كتلة تذييل الامتثال: كتلة محتوى compliance_footer، تُنشأ تلقائياً بافتراض منطقي عند تفعيل الإلحاق التلقائي للمرة الأولى، وتحمل عنوانك وروابط الإلغاء والتفضيلات. أشر إليها في أي مكان بـ {{ blocks.compliance_footer }} أو عدلها ضمن Content Blocks.
  • مفتاح الإلحاق التلقائي: الإعدادات ← الاشتراكات ← «إلحاق تذييل إلغاء اشتراك تلقائياً عند غيابه». عند تفعيله، يلحق مسار إرسال Email التذييل بكل Email تسويقي يحمل رأس List-Unsubscribe ولا يحتوي نصه على رابط إلغاء أو تفضيلات. لا يمنع الإرسال أبداً.
  • تحذير أداة الإنشاء: يعرض منشئ حملة Email تحذيراً إذا لم يحمل النص رابط إلغاء، كي تكتشف ذلك قبل الإرسال. يقدم اختصارين: إضافة رابط لفتح المحرر، وتفعيل الإلحاق التلقائي للتذييل للانتقال إلى هذه الصفحة. يمكن تجاهله للجلسة؛ وعند تشغيل الإلحاق يصبح ملاحظة هادئة لأن التذييل يضاف لك.

يمكن أيضاً اختيار قوائم الاشتراك في عقد رحلات SMS وWhatsApp وViber، لا Email فقط؛ فتتخطى بوابة الإرسال في كل عقدة جهات الاتصال التي ألغت تلك القائمة في أي قناة.

GDPR، أوروبا

  • استخدم موافقة مزدوجة لمستخدمي الاتحاد الأوروبي.
  • خزّن نص الموافقة وطابعها الزمني.
  • وفّر وصولاً سهلاً إلى مركز التفضيلات.
  • احترم طلبات الإلغاء فوراً.
  • احتفظ بسجل تدقيق لكل تغييرات الاشتراك.

CAN-SPAM، الولايات المتحدة

  • ضمّن عنواناً بريدياً فعلياً في Email.
  • احترم طلبات الإلغاء خلال 10 أيام عمل، ويطبقها Joryio فوراً.
  • عرّف Email التجاري بوضوح.
  • لا تستخدم سطور موضوع مضللة.

TCPA، الولايات المتحدة وSMS

  • احصل على موافقة كتابية صريحة قبل إرسال SMS.
  • احترم كلمات STOP فوراً.
  • قدّم تعليمات إلغاء في الرسائل.
  • يعالج Joryio تلقائياً: STOP وSTOPALL وUNSUBSCRIBE وCANCEL وEND وQUIT وREVOKE وOPTOUT، أي الأساس الإنجليزي الدائم، إضافة إلى الافتراضيات المحلية، مثل הסר بالعبرية، وأي كلمات مخصصة تضيفها.

معالجة كلمات SMS وWhatsApp

يعالج Joryio الكلمات الواردة تلقائياً مع تسامح حالة الأحرف والترقيم؛ فـ Stop وSTOP! و" stop " كلها مطابقة. STOPALL هي كلمة الإلغاء الوحيدة المدمجة على مستوى القناة، إضافة إلى أي كلمات عامة مخصصة؛ أما كل كلمة أخرى فتخص مجموعة الاشتراك لكل رقم أو WABA التي استقبلت الرسالة، وSTART يعيد اشتراك المجموعة نفسها.

SMS

الكلمةالإجراء
STOP, UNSUBSCRIBE, CANCEL, END, QUIT, REVOKE, OPTOUTإلغاء مجموعة الرقم المستلم
STOPALLإلغاء القناة كلها، كل الأرقام
START, YES, UNSTOP, SUBSCRIBE, OPTINإعادة اشتراك مجموعة الرقم المستلم
HELP, INFOإرسال رسالة مساعدة
الافتراضيات المحلية والإضافات المخصصةالإجراء نفسه لفئتها

WhatsApp

الكلمةالإجراء
STOP, UNSUBSCRIBE, CANCEL, END, QUIT, OPTOUT, OPT-OUTإلغاء مجموعة WABA المستلمة
STOPALLإلغاء القناة كلها، كل WABA
START, UNSTOP, SUBSCRIBE, YES, OPTIN, OPT-INإعادة اشتراك مجموعة WABA المستلمة

تتحقق توقيعات webhooks الواردة، فتُرفض STOP وSTART المزورة والمزودون غير الداعمين للتحقق. وعند تعذر حل المجموعة، يطبق الإلغاء بأمان على القناة كلها. يُضبط webhook SMS الوارد على أرقامك أثناء التهيئة وتعالج الكلمات تلقائياً.


أفضل الممارسات

  1. استخدم رؤوس List-Unsubscribe دائماً لتحسين التسليم وإظهار Gmail زر الإلغاء.
  2. نفذ الموافقة المزدوجة للتسويق لجودة قائمة وامتثال أفضل.
  3. راقب معدلات الارتداد لأن الارتدادات العالية تضر سمعة المرسل.
  4. قسّم حسب حالة الاشتراك وأرسل فقط لمن وافقوا.
  5. سهّل الإلغاء بنقرة واحدة ومن دون تسجيل دخول.
  6. احتفظ بسجلات التدقيق فهي مطلوبة للامتثال ومفيدة للنزاعات.
  7. اختبر مركز التفضيلات لتضمن قدرة المستخدمين على إدارة تفضيلاتهم.
  8. استخدم إلغاء خاصاً بالقائمة كي يظل المستخدم مشتركاً في بعض المحتوى.

استكشاف الأخطاء وإصلاحها

مشاكل شائعة

لا يُرسل Email

  • تحقق مما إذا كانت حالة Email للمستخدم unsubscribed.
  • تحقق مما إذا كان Email معلّماً غير صالح بسبب الارتدادات.
  • تحقق من حالة الارتداد في ملف المستخدم.

إلغاء الاشتراك لا يعمل

  • تحقق من انتهاء الرمز، الافتراضي 90 يوماً.
  • تحقق من صحة توقيع الرمز.
  • راجع سجل التدقيق بحثاً عن الأخطاء.

لا تُعالج الارتدادات

  • تحقق من ضبط URL لـ webhook في موفر Email.
  • تحقق من مصادقة webhook.
  • راجع سجلات الأخطاء.

التصحيح

تحقق من حالة الاشتراك:

# API call
curl -X GET "https://api-eu1.joryio.com/subscriptions/contacts/{userId}" \
-H "Authorization: Bearer {token}"

اعرض سجل التدقيق:

curl -X GET "https://api-eu1.joryio.com/subscriptions/contacts/{userId}/history" \
-H "Authorization: Bearer {token}"