Table of Contents
ويقتضي التسويق الحديث حملات بريدية تكيف بسرعة مع قطاعات الجمهور، واختبارات A/B، والمحتوى الدينامي، ويصبح التنفيذ الجامد والمحتكري سريعا كابوسا للنفقة مع تطور المتطلبات، ويوفر لارافل، مع النظام الإيكولوجي السافر والقائم، أساسا مثاليا، ولكن المفتاح الحقيقي للمرونة الطويلة الأجل يكمن في اختيار نمط التصميم الصحيح، ويبرز نمط البناء كحل قوي لإعادة تصميم الأشياء المعقدة.
وفي هذا الدليل الشامل، ستتعلمون كيف تصممون نظاماً مرناً للحملات البريدية في لارافل باستخدام خطة البناء، وسنقوم بكسر النظرية، ونسير من خلال التنفيذ التفصيلي، ونستكشفون التكامل مع نظم بريد وطرح الرسائل في لارافل، وفي النهاية سيكون لديكم نهج واضح في الإنتاج لتوليد أي متغيرات في الرسائل الإلكترونية من رسائل الازدواج في المعاملات بين القطاعين العام والخاص، وذلك بهدف تحقيق الحد الأدنى من الازدواجية في مجال استخدام أجهزة الاتصال الحاسوبي.
ما هو "بائع البناء"؟
إن خطة البناء هي نمط تصميمي مبتكر يفصل بين بناء جسم معقد وبين تمثيله النهائي، وبدلا من إيجاد جسم عن طريق بناء ضخم أو مجموعة من أساليب المصنع، تفوض عملية البناء إلى رتب مصممة ومصممة، ويرتب المدير الخطوات، بينما يعرف كل بنائي كيفية تجميع المكونات لبديل محدد.
وهذا النمط يشع عندما يتطلب الجسم أجزاء اختيارية عديدة، أو عندما تحتاج إلى إنتاج مختلف أشكال التمثيل ذات الصلة، وبالنسبة للحملات البريدية، فإن " الهدف " هو رسالة بريدية إلكترونية كاملة مع موضوع وجسد وملحقات ومتلقين ورأسين وبيانات مائية، ويمكن لكل نوع من أنواع الحملات )الزراعة، والمعاملات، والتظاهرات( أن يتقاسم قاعدة مشتركة، ولكن في شكل مخطط أو مرسل في شكل معلومات.
كيف يُشفى من "خطبة المصنع"
وبينما تركز خطة المصنع على إنشاء الأشياء في نداء واحد، فإن خطة البناء تسمح بعملية بناء متحكم بها ومجزأة، والمصانع مثالية عندما يكون منطق الخلق بسيطا؛ والبناء أفضل عندما تحتاج إلى التحكم في ترتيب واختيار الأجزاء، وفي نظم البريد الإلكتروني، غالبا ما تحتاج إلى إضافة ملحقات مشروطة، أو تتفاوت نموذج الجسم، أو تضع أولويات تسليم مختلفة.
"تهيئين بيئة "لارافل
قبل أن تتنازل عن القانون، تضمن أن يكون لديك طلب لارافل (التحويل 9 أو لاحقا) مع تشكيل البريد غير المقصود، وسنفترض أن لديك جداول قواعد البيانات اللازمة للحملات والمشتركين والنماذج - ولكن بالنسبة لهذه المادة، نركز على منطق البناء نفسه، ويمكن أن تتبعوا مع تركيبة جديدة من لارافل باستخدام الحاسوب:
composer create-project laravel/laravel email-campaign-builder
وبعد ذلك، سنضع مركب البريد في ] (مثلاً، ] للاختبار، وسنستخدم أيضاً موكب لارافل ]] والفصول المدمجة لاحقاً، ولكن بناائنا سيظل مستقلاً عنهم للحفاظ على الفصل النظيف.
العناصر الأساسية لنهج البناء
وسننفذ أربعة عناصر أساسية:
- Product] — The final email object (could be a plain , an value object, or an extension of Laravel’s ).
- Builder Interface] - Declares methods for each part of the email: subject, body, recipients, attacheds, headers, etc.
- Concrete Builders] - Each implements the interface for a specific email type (Promotional, Transactional, welcome series).
- Director] – Orchestrates the building steps in a defined order, often using the same builder to produce multiple emails from a blueprint.
الخطوة 1: تعريف منتج الرسالة الإلكترونية
وسننشئ هدفا بسيطا من القيم لحمل جميع البيانات البريدية، مما يبقي رمز البناء خاليا من الاختبارات.
<?php
namespace App\Values;
class EmailMessage
{
public string $subject;
public string $body;
public string $mimeType = 'text/html'; // or text/plain
public array $recipients = [];
public array $ccRecipients = [];
public array $bccRecipients = [];
public array $attachments = [];
public array $headers = [];
public ?string $fromAddress = null;
public ?string $fromName = null;
public function toArray(): array
{
return [
'subject' => $this->subject,
'body' => $this->body,
'mimeType' => $this->mimeType,
'recipients' => $this->recipients,
'cc' => $this->ccRecipients,
'bcc' => $this->bccRecipients,
'attachments' => $this->attachments,
'headers' => $this->headers,
'from' => ['address' => $this->fromAddress, 'name' => $this->fromName],
];
}
}
الخطوة 2: البناء
الواجهة تحدد العقد لبناء أيّ متغير بريدي.
<?php
namespace App\Builders\Contracts;
use App\Values\EmailMessage;
interface EmailBuilderContract
{
public function setSubject(string $subject): self;
public function setBody(string $body, string $mimeType = 'text/html'): self;
public function addRecipient(string $email, ?string $name = null): self;
public function addCc(string $email, ?string $name = null): self;
public function addBcc(string $email, ?string $name = null): self;
public function addAttachment(string $filePath, ?string $name = null): self;
public function addHeader(string $key, string $value): self;
public function setFrom(string $address, ?string $name = null): self;
public function getEmail(): EmailMessage;
public function reset(): void;
}
الخطوة 3: بناء أكاديم للإيميل الترويجي
فلننفذ بناءاً يصمم البريد الإلكتروني للترويجات - المزيجات، وصلات التقاسم الاجتماعي، وخط قدم غير مطابق.
<?php
namespace App\Builders;
use App\Builders\Contracts\EmailBuilderContract;
use App\Values\EmailMessage;
class PromotionalEmailBuilder implements EmailBuilderContract
{
private EmailMessage $email;
public function __construct()
{
$this->reset();
}
public function setSubject(string $subject): self
{
$this->email->subject = '[Promo] ' . $subject;
return $this;
}
public function setBody(string $body, string $mimeType = 'text/html'): self
{
// Wrap body with promotional header/footer
$this->email->body = $this->wrapBody($body);
$this->email->mimeType = $mimeType;
return $this;
}
private function wrapBody(string $body): string
{
return "<div style=\"background:#f5f5f5; padding:20px;\">
<div style=\"max-width:600px; margin:auto;\">
$body
<hr>
<p style=\"font-size:12px; color:#888;\">
You received this because you opted in.
<a href=\"{{unsubscribe_url}}\">Unsubscribe</a>
</p>
</div>
</div>";
}
public function addRecipient(string $email, ?string $name = null): self
{
$this->email->recipients[] = compact('email', 'name');
return $this;
}
public function addCc(string $email, ?string $name = null): self
{
$this->email->ccRecipients[] = compact('email', 'name');
return $this;
}
public function addBcc(string $email, ?string $name = null): self
{
$this->email->bccRecipients[] = compact('email', 'name');
return $this;
}
public function addAttachment(string $filePath, ?string $name = null): self
{
$this->email->attachments[] = ['path' => $filePath, 'name' => $name];
return $this;
}
public function addHeader(string $key, string $value): self
{
$this->email->headers[$key] = $value;
return $this;
}
public function setFrom(string $address, ?string $name = null): self
{
$this->email->fromAddress = $address;
$this->email->fromName = $name;
return $this;
}
public function getEmail(): EmailMessage
{
$built = clone $this->email;
$this->reset();
return $built;
}
public function reset(): void
{
$this->email = new EmailMessage();
}
}
الخطوة 4: نموذج بناء المعاملات
ويحتاج البريد الإلكتروني (مثل تأكيد الطلب) إلى ملف مختلف - الحد الأدنى من العلامات التجارية، والرؤساء ذوي الأولوية، ولا أي قدم غير مصفوف.
<?php
namespace App\Builders;
class TransactionalEmailBuilder implements EmailBuilderContract
{
private EmailMessage $email;
// ... same structure, but setSubject does not prepend prefix
// and wrapBody() uses a simple layout with order details
// getEmail() resets the builder
}
المدير: تنسيق البناء
ويقوم المدير بصناعة البناء ويسمي خطواته بترتيب محدد، ويمكنك تحديد التسلسلات القياسية، مثل " بناء بريد إلكتروني للحملة لمشترك معين " .
<?php
namespace App\Builders;
use App\Builders\Contracts\EmailBuilderContract;
use App\Models\User;
class CampaignDirector
{
public function __construct(private EmailBuilderContract $builder) {}
public function buildPromotionalCampaign(User $user, string $subject, string $body): EmailMessage
{
return $this->builder
->setFrom('[email protected]', 'Marketing Team')
->setSubject($subject)
->addRecipient($user->email, $user->name)
->addHeader('X-Campaign-Id', $campaignId)
->setBody($body)
->getEmail();
}
public function buildTransactionalOrderConfirmation(Order $order): EmailMessage
{
// Switch builder if needed, or use a different director method
// (In practice, you'd instantiate a TransactionalEmailBuilder)
$this->builder = new TransactionalEmailBuilder();
$body = view('emails.order-confirmation', compact('order'))->render();
return $this->builder
->setFrom('[email protected]', 'Order System')
->setSubject('Order Confirmation #' . $order->id)
->addRecipient($order->user->email, $order->user->name)
->setBody($body)
->addHeader('X-Transaction-Id', $order->transaction_id)
->addAttachment(storage_path('invoices/' . $order->invoice_file))
->getEmail();
}
}
استخدام المدير يبقي منطق البناء مركزياً إذا كنت بحاجة فيما بعد إلى إضافة طريقة ، أنت فقط تمدّد المدير دون لمس البنين.
إدماج مع شركة لارافل
بمجرد أن يكون لديك هدف قيم ، يجب أن ترسله، إنشاء موصل تجاري عادي يقبل ويجعله يستخدم نظام بريد لارافل المبني.
<?php
namespace App\Mail;
use App\Values\EmailMessage;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Attachment;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
class CampaignMail extends Mailable
{
use Queueable, SerializesModels;
public function __construct(public EmailMessage $emailMessage) {}
public function envelope(): Envelope
{
return new Envelope(
from: $this->emailMessage->fromAddress
? new Address($this->emailMessage->fromAddress, $this->emailMessage->fromName)
: null,
subject: $this->emailMessage->subject,
cc: $this->emailMessage->ccRecipients,
bcc: $this->emailMessage->bccRecipients,
headers: $this->emailMessage->headers,
);
}
public function content(): Content
{
return new Content(
htmlString: $this->emailMessage->body,
);
}
public function attachments(): array
{
return array_map(function ($attach) {
return Attachment::fromPath($attach['path'])
->as($attach['name'] ?? null);
}, $this->emailMessage->attachments);
}
}
الآن يمكنك إرسال رسائل إلكترونية من أي متحكم أو وظيفة باستخدام البنايين:
use App\Builders\PromotionalEmailBuilder;
use App\Builders\CampaignDirector;
use App\Mail\CampaignMail;
use Illuminate\Support\Facades\Mail;
$builder = new PromotionalEmailBuilder();
$director = new CampaignDirector($builder);
$emailMessage = $director->buildPromotionalCampaign($user, 'Summer Sale', $htmlContent);
Mail::to($user->email)->send(new CampaignMail($emailMessage));
Leveraging the Queue for Scalability
ويجب أن تتعامل نظم الحملات البريدية مع آلاف المستفيدين بغرابة، ونظام لارافل للصفوف تطابق مثالي، ومسح منطق الإرسال في وظيفة مطهرة تستخدم البنايات لكل متلقي.
<?php
namespace App\Jobs;
use App\Builders\Contracts\EmailBuilderContract;
use App\Builders\CampaignDirector;
use App\Mail\CampaignMail;
use App\Models\Subscriber;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Mail;
class SendCampaignEmail implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function __construct(
private Subscriber $subscriber,
private string $subject,
private string $body,
private string $builderClass // class-string
) {}
public function handle(): void
{
$builder = app($this->builderClass);
$director = new CampaignDirector($builder);
$emailMessage = $director->buildPromotionalCampaign(
$this->subscriber->user,
$this->subject,
$this->body
);
Mail::to($this->subscriber->email)
->send(new CampaignMail($emailMessage));
}
}
إرسال وظيفة كل مشترك في حلقة (أو أفضل، استخدام ] لإدارة الرسائل الناجحة/الموجهة.
إضافة معمل الديناميكية مع بليد
إن سطوح الـ "إتش تي إل" في البنايات ليس مثالياً، بل إنّه يجعل من "بلايد آر" الجسد، فبنائك يمكنهم قبول اسم مرئي و صفيفة بيانات، ثمّ يدعو داخل .
public function setBody(string $viewName, array $data = [], string $mimeType = 'text/html'): self
{
$rendered = view($viewName, $data)->render();
$this->email->body = $this->wrapBody($rendered);
$this->email->mimeType = $mimeType;
return $this;
}
الآن يمكنك الاتصال .
المنافع في الحملات العالمية الحقيقية
- Variety without duplication - Different campaign types share the same interface; builders encapsulate the differences.
- Compability] - يمكنك اختبار كل بناة من خلال استعادة وتأكيد ممتلكاتها.
- ]Easier A/B Testing - Swap builders per variant group. The director’s construction process remains changed.
- Audit tracks] – Add logging inside the builder to record every step for later analysis.
- Integration with external services] - Use the builder to assemble payloads for services like Mailgun, SendGrid, or SparkPost.
أفضل الممارسات والخيوط المشتركة
أبقوا البنايات عديمي الجنسية حيثما يمكن
The method ensures a builder can be reused. If you forget to call , the same builder instance may leak state between different campaigns. In our example, calls automatically — a safe pattern.
لا تتعدى على المهندسين في البريد الإلكتروني المبسّط
إذا أرسل طلبك نوع واحد فقط من البريد الإلكتروني، قد يكون البُنيّر أكثر من اللازم، يشرق عندما يكون لديك ثلاثة أنواع بريد إلكتروني مميزة على الأقل مع عناصر مختلفة.
حقن الإعالة المستخدم في البناء
سجلوا بناتكم في حاوية الخدمات حتى تتمكنوا من حقن المعالين (مثل قطع الأشجار أو خدمات التعقب) فيهم بسهولة
العقل عدد المتلقين
وينبغي ألا يجمع البنّاء آلاف المتلقين في واحدة - من شأنها أن تحمل غيغابايت في الذاكرة، بل أن ينشئ بريداً إلكترونياً واحداً لكل متلقي أو يستخدم أجهزة تسجيل أو تقييد استعمال دفعة (Milgun’s ).
التحسينات الإضافية
النظر في إضافة - نموذج ملوث يخزن طبقة البناء والنماذج والبارامترات الافتراضية، ثم قراءة جدول الأعمال للخطط واستخدام المدير في بناء البريد الإلكتروني لجميع المشتركين النشطين.
ويمكنكم أيضاً أن تستحدثوا التي تطبق قواعد عالمية (مثل أن تضيف دائماً حلقة اتصال غير مقصودة) قبل أن تُنقل إلى البنّاء المحدد، وهذا يضيف طبقة أخرى من الفصل.
الموارد الخارجية
- خط الأساس - اعادة تصنيع الغورو ] (شرح بصري مُسبق)
- Laravel Mail Documentation (للإشارة إلى درجة الميول)
- Laravel Queues] (لتوصيل البريد الإلكتروني)
خاتمة
إن تصميم نظام مرن للحملة البريدية لا يتطلب إطارا هائلا، إذ أن خطة البناء في لارافل، تتحكمون بدقة في بناء البريد الإلكتروني، مما يجعل قاعدتكم قابلة للتكيف مع احتياجات التسويق المتغيرة، وبفصل ما )بنائك( عن كيفية )مدير(، ستمكن الأفرقة من إضافة أنواع جديدة من الحملات دون خوف من كسر تلك القائمة، وتضعون هذه القاعدة في شكل بريد وبنى تحتية قابلة للاختبار، ولكم حل.