الحملات
إنشاء حملات التسويق عبر البريد الإلكتروني وجدولتها وإرسالها مع التتبع والتحليلات
أنشئ حملات التسويق عبر البريد الإلكتروني وأدرها. يتولى MailLand اختيار المستلمين والإرسال وتتبع التسليم وتحليلات التفاعل لكل حملة.
دورة حياة الحملة
تمر كل حملة بتدفق حالة محدد:
| الحالة | القيمة | الوصف |
|---|---|---|
Draft | 0 | الحالة الأولية: قابلة للتعديل، لم تُرسَل بعد |
Scheduled | 1 | في قائمة الانتظار للتسليم المستقبلي |
Sending | 2 | قيد الإرسال إلى المستلمين |
Sent | 3 | تمت معالجة جميع المستلمين |
Paused | 4 | الإرسال متوقف في المنتصف |
Cancelled | 5 | تم إلغاء الإرسال |
Failed | 6 | خطأ في النظام أثناء الإرسال |
الانتقالات المسموح بها:
Draft→Scheduled(جدولة) أوSending(إرسال فوري) أوCancelled(إلغاء)Scheduled→SendingأوCancelled: إعادة جدولة حملة في حالةScheduledغير مدعومةSending→SentأوPausedأوCancelledأوFailedPaused→Sending(استئناف)SentأوCancelled→ مؤرشف
أنواع الحملات
| النوع | القيمة | الوصف |
|---|---|---|
Regular | 0 | حملة قياسية لمرة واحدة |
Automated | 1 | يُفعَّل عبر الأتمتة |
ABTest | 2 | حملة اختبار A/B |
التخصيص (Personalization)
تدعم سطور الموضوع ومحتوى الحملة وسوم الدمج {{variable}}، التي تُستبدل لكل مستلم من سجل ذلك المشترك نفسه.
| الوسم | القيمة |
|---|---|
{{firstName}} | الاسم الأول للمشترك |
{{lastName}} | اسم عائلة المشترك |
{{fullName}} | الاسم الأول والأخير مجتمعين |
{{email}} | عنوان البريد الإلكتروني للمشترك |
{{subscriberId}} | معرّف غامق للمشترك |
{{custom_<field>}} | أي حقل مخصص في المشترك، متاح أيضاً كـ {{<field>}} |
<p>Hi {{firstName}}, here's what's new this month.</p>الوسم الذي لا قيمة له يُترك كما كُتب تماماً: {{firstName}} لمشترك بلا اسم أول يبقى {{firstName}} في البريد المُسلَّم بدلاً من أن يصبح فراغاً. اكتب محتوى يُقرأ بشكل صحيح في الحالتين، مثلاً Hi there{{firstName}} خيار سيئ لكن "Your account" آمن. استخدم تحية بديلة عندما لا تكون متأكداً أن كل مشترك لديه الحقل.
تُهرَّب القيم بحسب الجزء الذي تحل فيه: محتوى HTML يُهرَّب كـ HTML (بحيث لا يمكن لاسم يحتوي على & أو < كسر تنسيقك)، بينما سطر الموضوع والنص العادي لا يُهرَّبان أبداً، تبقى Ben & Jerry's كما هي تماماً.
التهجئات القديمة بصيغة snake_case ({{first_name}}، {{last_name}}، {{full_name}}، {{subscriber_id}}) تستمر بالعمل كأسماء بديلة.
إنشاء حملة
يجب أن تكون مساحة العمل موثّقة كأعمال (Business Verified) قبل إنشاء أو تحديث أي حملة: وهو تحقق سابق ومنفصل عن تحقق fromEmail أدناه. إذا لم يكن كذلك، يُرفض الطلب بالخطأ 400 INVALID_REQUEST ("Marketing campaigns require Business Verified status…").
يجب أن يكون نطاق fromEmail مضافاً بالفعل ومُتحقَّقاً منه بالكامل (SPF + DKIM + DMARC) وقت الإنشاء والتحديث، وإلا يُرفض الطلب (400/404). يحدث هذا التحقق هنا، وليس وقت الإرسال، راجع الإرسال الفوري.
POST https://api.mail.land/v1/marketing/campaigns{
"name": "February Newsletter",
"subject": "What's new in February",
"previewText": "Product updates and tips",
"fromName": "MailLand Team",
"fromEmail": "[email protected]",
"replyTo": "[email protected]",
"htmlContent": "<html>...</html>",
"textContent": "Plain text version...",
"type": 0,
"mailingListId": "ddv6ou6kz4wbto",
"segmentId": "x4xa3ep1zmqq0b"
}| الحقل | النوع | مطلوب | الوصف |
|---|---|---|---|
name | string | نعم | اسم الحملة |
subject | string | نعم | سطر موضوع البريد الإلكتروني |
previewText | string | لا | نص المعاينة الظاهر في صندوق الوارد |
fromName | string | نعم | الاسم المعروض للمرسل |
fromEmail | string | نعم | عنوان البريد الإلكتروني للمرسل |
replyTo | string | لا | عنوان الرد |
htmlContent | string | نعم | محتوى HTML للبريد الإلكتروني |
textContent | string | لا | النسخة البديلة بالنص العادي |
templateId | string | لا | معرّف القالب للاستخدام |
type | int | لا | نوع الحملة (الافتراضي: 0 عادية) |
mailingListId | string | لا* | قائمة المراسلة المستهدفة |
segmentId | string | لا* | الشريحة المستهدفة |
* أرسل mailingListId أو segmentId: أحدهما مطلوب ما لم يكن templateId محدداً.
curl -X POST https://api.mail.land/v1/marketing/campaigns \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"name": "February Newsletter",
"subject": "What'\''s new in February",
"fromName": "MailLand Team",
"fromEmail": "[email protected]",
"htmlContent": "<html><body><h1>Hello!</h1></body></html>",
"mailingListId": "ddv6ou6kz4wbto"
}'الاستجابة
{
"id": "uivozyvucowj9w",
"name": "February Newsletter",
"subject": "What's new in February",
"previewText": "Product updates and tips",
"fromName": "MailLand Team",
"fromEmail": "[email protected]",
"status": "draft",
"statusName": "Draft",
"type": 0,
"typeName": "Regular",
"mailingListId": "ddv6ou6kz4wbto",
"mailingListName": "Main Newsletter",
"segmentId": null,
"segmentName": null,
"createdAt": "2026-02-17T12:00:00Z",
"updatedAt": "2026-02-17T12:00:00Z"
}عرض قائمة الحملات
GET https://api.mail.land/v1/marketing/campaigns| المعامل | النوع | الافتراضي | الوصف |
|---|---|---|---|
cursor | string | - | مؤشر معتم من nextCursor للصفحة السابقة. احذفه للصفحة الأولى. |
limit | int | 20 | العناصر لكل صفحة (الحد الأقصى 100) |
search | string | - | البحث بالاسم |
status | int | - | التصفية بـ CampaignStatus |
type | int | - | التصفية بـ CampaignType |
mailingListId | string | - | التصفية بقائمة المراسلة |
sortBy | string | - | حقل الفرز |
sortDesc | bool | false | الفرز تنازلياً |
includeArchived | bool | false | تضمين الحملات المؤرشفة |
curl "https://api.mail.land/v1/marketing/campaigns?limit=20&status=3" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."{
"items": [
{
"id": "uivozyvucowj9w",
"name": "February Newsletter",
"subject": "What's new in February",
"status": "sent",
"statusName": "Sent",
"type": 0,
"typeName": "Regular",
"mailingListId": "ddv6ou6kz4wbto",
"mailingListName": "Main Newsletter",
"totalRecipients": 5000,
"totalSent": 4980,
"totalDelivered": 4900,
"totalOpened": 1520,
"totalClicked": 195,
"totalBounced": 45,
"totalUnsubscribed": 12,
"sentAt": "2026-02-15T10:00:00Z",
"completedAt": "2026-02-15T10:35:00Z",
"createdAt": "2026-02-14T08:00:00Z"
}
],
"nextCursor": "eyJ2IjoxLCJzIjoiY3JlYXRlZGF0OmRlc2MiLCJrIjoi...",
"hasMore": true
}الحصول على تفاصيل الحملة
GET https://api.mail.land/v1/marketing/campaigns/{id}يُعيد CampaignDetailDto الكامل بما يشمل محتوى HTML وجميع الإحصائيات ومعدلات التفاعل المحسوبة:
curl https://api.mail.land/v1/marketing/campaigns/uivozyvucowj9w \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."{
"id": "uivozyvucowj9w",
"name": "February Newsletter",
"subject": "What's new in February",
"previewText": "Product updates and tips",
"fromName": "MailLand Team",
"fromEmail": "[email protected]",
"replyTo": "[email protected]",
"status": "sent",
"statusName": "Sent",
"type": 0,
"typeName": "Regular",
"htmlContent": "<html>...</html>",
"textContent": "Plain text...",
"mailingListId": "ddv6ou6kz4wbto",
"mailingListName": "Main Newsletter",
"totalRecipients": 5000,
"totalSent": 4980,
"totalDelivered": 4900,
"totalOpened": 1520,
"totalClicked": 195,
"totalBounced": 45,
"totalUnsubscribed": 12,
"totalComplaints": 2,
"deliveryRate": 98.39,
"openRate": 31.02,
"clickRate": 3.98,
"clickToOpenRate": 12.83,
"bounceRate": 0.9,
"unsubscribeRate": 0.24,
"openTrackingEnabled": true,
"clickTrackingEnabled": true,
"sentAt": "2026-02-15T10:00:00Z",
"completedAt": "2026-02-15T10:35:00Z",
"createdAt": "2026-02-14T08:00:00Z",
"updatedAt": "2026-02-15T10:35:00Z"
}معدلات التفاعل
| المعدل | الصيغة |
|---|---|
deliveryRate | totalDelivered / totalSent * 100 |
openRate | totalOpened / totalDelivered * 100 |
clickRate | totalClicked / totalDelivered * 100 |
clickToOpenRate | totalClicked / totalOpened * 100 |
bounceRate | totalBounced / totalSent * 100 |
unsubscribeRate | totalUnsubscribed / totalDelivered * 100 |
تُحسب المعدلات على الخادم من العدّادات الخام (الفتحات والنقرات فريدة لكل مستلم). deliveryRate وbounceRate نسبتان إلى المُرسَل؛ وopenRate وclickRate وunsubscribeRate نِسَب إلى المُسلَّم؛ أما clickToOpenRate (CTOR) فهو النقرات نسبةً إلى الفتحات ومقياس مستقل عن clickRate. المعدل نسبة مئوية بلا سقف (قد يتجاوز clickToOpenRate 100) وقيمته null لا 0 عند عدم توفره: المقام صفر أو أن التتبع المطلوب متوقف في الحساب (openTrackingEnabled / clickTrackingEnabled تُظهران الإعداد الحالي). لدمج الحملات اجمع العدّادات واقسم مرة واحدة؛ لا تأخذ متوسط النسب. وتُرجع القائمة الحقول نفسها لكل حملة.
تحديث حملة
PUT https://api.mail.land/v1/marketing/campaigns/{id}يمكن تحديث الحملات ذات الحالة Draft أو Scheduled فقط. يتطابق نص الطلب مع طلب الإنشاء، باستثناء type الذي لا يمكن تغييره.
| الحالة | الكود | الوصف |
|---|---|---|
200 | - | تم تحديث الحملة |
400 | INVALID_REQUEST | يمكن تعديل الحملات المسودة فقط |
404 | RESOURCE_NOT_FOUND | الحملة غير موجودة |
curl -X PUT https://api.mail.land/v1/marketing/campaigns/uivozyvucowj9w \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"name": "February Newsletter (Updated)",
"subject": "What'\''s new in February - updated",
"fromName": "MailLand Team",
"fromEmail": "[email protected]",
"htmlContent": "<html><body><h1>Updated!</h1></body></html>",
"mailingListId": "ddv6ou6kz4wbto"
}'جدولة حملة
POST https://api.mail.land/v1/marketing/campaigns/{id}/schedule{
"scheduledAt": "2026-02-20T14:00:00Z"
}يجب أن يكون وقت scheduledAt في المستقبل. تتغير حالة الحملة إلى Scheduled ويلتقطها CampaignWorker في الوقت المحدد.
الجدولة مسموحة فقط من حالة Draft: لا يمكن إعادة جدولة حملة في حالة Scheduled بالفعل عبر هذه النقطة.
| الحالة | الكود | الوصف |
|---|---|---|
200 | - | تمت جدولة الحملة |
400 | VALIDATION_FAILED | يجب أن يكون وقت الجدولة في المستقبل |
404 | RESOURCE_NOT_FOUND | الحملة غير موجودة أو لا يمكن جدولتها |
403 | MARKETING_NOT_YET_ALLOWED | التسويق غير مفتوح للحساب بعد (راجع رموز الأخطاء)؛ ويعيده /send أيضًا |
403 | MARKETING_SUSPENDED | التسويق غير متاح على مستوى المنصة؛ ويعيده /send أيضًا |
422 | CAMPAIGN_LINK_BLOCKED | رابط في الحملة يشير إلى وجهة مصنّفة على أنها غير آمنة؛ ويعيده /send أيضًا. لا تتم جدولة أو إرسال أي شيء |
curl -X POST https://api.mail.land/v1/marketing/campaigns/uivozyvucowj9w/schedule \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{ "scheduledAt": "2026-02-20T14:00:00Z" }'الإرسال الفوري
POST https://api.mail.land/v1/marketing/campaigns/{id}/sendيُرسل الحملة فوراً. تنتقل حالة الحملة إلى Sending، ويبدأ CampaignWorker في معالجة المستلمين.
لا يتحقق /send نفسه من حالة تحقق النطاق: يحدث هذا الفحص وقت الإنشاء/التحديث (راجع إنشاء حملة). يُعيد /send الرمز 422 CAMPAIGN_NO_ELIGIBLE_RECIPIENTS إذا لم يكن أي أحد في القائمة/الشريحة المستهدفة مؤهلاً لاستلام الحملة (مثلاً إذا كان الجميع مكبوتين أو أوقفوا الاشتراك).
curl -X POST https://api.mail.land/v1/marketing/campaigns/uivozyvucowj9w/send \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."الإيقاف المؤقت والاستئناف
إيقاف حملة قيد الإرسال مؤقتاً:
POST https://api.mail.land/v1/marketing/campaigns/{id}/pausecurl -X POST https://api.mail.land/v1/marketing/campaigns/uivozyvucowj9w/pause \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."استئناف حملة متوقفة:
POST https://api.mail.land/v1/marketing/campaigns/{id}/resumecurl -X POST https://api.mail.land/v1/marketing/campaigns/uivozyvucowj9w/resume \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."يوقف الإيقاف المؤقت CampaignWorker عن معالجة المستلمين المتبقين. لا تتأثر رسائل البريد الإلكتروني المُرسَلة مسبقاً. يستأنف الإرسال من حيث توقف.
إلغاء حملة
POST https://api.mail.land/v1/marketing/campaigns/{id}/cancelيُلغي حملة Draft أو Scheduled أو Sending. لا يتم استرداد رسائل البريد الإلكتروني المُرسَلة مسبقاً.
curl -X POST https://api.mail.land/v1/marketing/campaigns/uivozyvucowj9w/cancel \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."نسخ حملة
POST https://api.mail.land/v1/marketing/campaigns/{id}/duplicate?name=Copy%20of%20Newsletterينشئ حملة Draft جديدة بجميع الإعدادات المنسوخة من الأصل. معامل الاستعلام name اختياري.
curl -X POST "https://api.mail.land/v1/marketing/campaigns/uivozyvucowj9w/duplicate?name=Copy%20of%20Newsletter" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."الأرشفة وإلغاء الأرشفة
أرشفة حملة Sent أو Cancelled:
POST https://api.mail.land/v1/marketing/campaigns/{id}/archivecurl -X POST https://api.mail.land/v1/marketing/campaigns/uivozyvucowj9w/archive \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."إلغاء أرشفة حملة مؤرشفة:
POST https://api.mail.land/v1/marketing/campaigns/{id}/unarchivecurl -X POST https://api.mail.land/v1/marketing/campaigns/uivozyvucowj9w/unarchive \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."تُخفى الحملات المؤرشفة من عرض القائمة الافتراضي ما لم يتم تمرير includeArchived=true.
مستلمو الحملة
الحصول على المستلمين بترقيم الصفحات مع حالة التسليم لحملة معينة:
GET https://api.mail.land/v1/marketing/campaigns/{id}/recipients| المعامل | النوع | الافتراضي | الوصف |
|---|---|---|---|
cursor | string | - | مؤشر معتم من nextCursor للصفحة السابقة. احذفه للصفحة الأولى. |
limit | int | 20 | العناصر لكل صفحة (الحد الأقصى 100) |
status | string | - | التصفية بحالة المستلم |
search | string | - | البحث بالبريد الإلكتروني |
curl "https://api.mail.land/v1/marketing/campaigns/uivozyvucowj9w/recipients?limit=20" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."{
"items": [
{
"email": "[email protected]",
"status": "Opened",
"sentAt": "2026-02-15T10:00:30Z",
"deliveredAt": "2026-02-15T10:00:32Z",
"openedAt": "2026-02-15T11:15:00Z",
"clickedAt": "2026-02-15T11:16:30Z",
"bouncedAt": null,
"complainedAt": null,
"unsubscribedAt": null,
"openCount": 2,
"clickCount": 1,
"bounceReason": null
}
],
"nextCursor": "eyJ2IjoxLCJzIjoiY3JlYXRlZGF0OmRlc2MiLCJrIjoi...",
"hasMore": true
}حالات المستلمين
| الحالة | القيمة | الوصف |
|---|---|---|
Pending | 0 | في قائمة الانتظار، لم يُرسَل بعد |
Sent | 1 | قُبل من قبل MTA |
Delivered | 2 | تم تسليمه إلى المستلم |
Opened | 3 | فتحه المستلم |
Clicked | 4 | نقر المستلم على رابط |
Bounced | 5 | ارتداد صعب |
Unsubscribed | 6 | ألغى المستلم الاشتراك |
Complained | 7 | شكوى بريد مزعج |
Failed | 8 | فشل التسليم |
تتضمن openedAt/openCount وclickedAt/clickCount نشاطاً آلياً، الجلب المسبق لحماية خصوصية بريد Apple وماسحات الروابط الأمنية، والتي لا تُصفّيها MailLand حالياً. عامل المعدلات المشتقة من الفتح/النقر كحد أعلى، وليس رقماً دقيقاً لتفاعل بشري.
حذف حملة
DELETE https://api.mail.land/v1/marketing/campaigns/{id}يحذف الحملة وبيانات مستلميها بشكل دائم. يمكن حذف الحملات في حالة Draft أو Scheduled فقط؛ حذف أي حالة أخرى يُعيد 404: استخدم الأرشفة بدلاً من ذلك للحملات المُرسَلة.
curl -X DELETE https://api.mail.land/v1/marketing/campaigns/uivozyvucowj9w \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."استجابات الخطأ
| الحالة | الكود | الوصف |
|---|---|---|
400 | VALIDATION_FAILED | الحقول المطلوبة مفقودة |
400 | INVALID_REQUEST | يمكن تعديل الحملات المسودة فقط |
403 | FORBIDDEN | صلاحيات غير كافية |
404 | RESOURCE_NOT_FOUND | الحملة غير موجودة |