Skip to content

Email Campaign Sending Process ​

Overview ​

This document provides technical documentation for the email campaign sending functionality in the MailHub module. It describes the components, process flow, and implementation details for sending email campaigns.

Technical Components ​

Models ​

  • MailCampaign: Contains campaign data including status, subject, scheduling information
  • MailTemplate: Stores email templates with HTML content
  • Subscriber: Represents recipients with email and status fields
  • Newsletter: Groups subscribers for targeting

Services ​

CampaignMailParser ​

php
namespace Modules\MailHub\Services;

// Class for parsing variables in email templates
class CampaignMailParser
{
    // Parses variables in content using @@variable@@ format
    public function parseVariables(string $content, array $data): string;

    // Extracts all variables from content
    public function extractVariables(string $content): array;

    // Generates unsubscribe URL for a subscriber
    private function generateUnsubscribeUrl(int $subscriberId): string;
}

CampaignMailer ​

php
namespace Modules\MailHub\Services;

// Service for sending campaign emails
class CampaignMailer
{
    // Sends a campaign email to a specific subscriber
    public function sendToSubscriber(MailCampaign $campaign, Subscriber $subscriber): void;

    // Gets template content from either database or file
    private function getTemplateContent(MailCampaign $campaign): string;

    // Creates a mailable instance with parsed content
    private function createEmail(string $html, string $subject, string $fromEmail, string $fromName): Mailable;
}

CampaignDispatcher ​

php
namespace Modules\MailHub\Services;

// Service for dispatching mail campaigns
class CampaignDispatcher
{
    // Dispatches a mail campaign for sending
    public function dispatchCampaign(MailCampaign $campaign): array;

    // Dispatches all pending campaigns that should be sent now
    public function dispatchPendingCampaigns(): array;
}

Jobs ​

ProcessCampaignJob ​

php
namespace Modules\MailHub\Jobs;

// Job to process an entire mail campaign
class ProcessCampaignJob implements ShouldQueue
{
    // Execute the job
    public function handle(CampaignRecipientResolver $recipientResolver,
                          CampaignValidator $validator): void;

    // Handle a job failure
    public function failed(Throwable $exception): void;
}

SendCampaignJob ​

php
namespace Modules\MailHub\Jobs;

// Job to send a mail campaign to a specific subscriber
class SendCampaignJob implements ShouldQueue
{
    // Execute the job
    public function handle(CampaignMailer $mailer): void;

    // Handle a job failure
    public function failed(Throwable $exception): void;
}

Commands ​

php
namespace Modules\MailHub\Console\Commands;

// Command to dispatch pending mail campaigns
class DispatchPendingCampaignsCommand extends Command
{
    // Execute the command
    public function handle(CampaignDispatcher $dispatcher): int;
}

Process Flow ​

  1. Campaign Preparation

    • User creates a campaign with template, subject, recipients
    • Campaign gets saved with status DRAFT or SCHEDULED
  2. Campaign Triggering

    • User manually triggers sending via Filament UI, or
    • Scheduled campaigns are picked up by the command
  3. Validation

    • CampaignDispatcher uses CampaignValidator to check:
      • Campaign has appropriate status
      • Template exists
      • Mail configuration exists
      • Recipients exist
  4. Queue Processing

    • ProcessCampaignJob is dispatched to queue
    • Campaign status is updated to PENDING
    • For each recipient, a SendCampaignJob is dispatched
  5. Email Generation and Sending

    • SendCampaignJob uses CampaignMailer to send to each recipient
    • CampaignMailParser processes template variables
    • Email is sent using Laravel's mail system
  6. Status Updates

    • When all sends are complete, campaign status is updated to SENT
    • If errors occur, status may be updated to FAILED

Template Variables ​

Variables in templates use the @@variable@@ format. Supported variables:

VariableDescription
@@userName@@Recipient's name
@@userEmail@@Recipient's email
@@date@@Current date
@@companyName@@Company name (in multi-tenant mode)
@@unsubscribeUrl@@Generated unsubscribe URL

Technical Implementation Notes ​

Campaign Status Flow ​

DRAFT → SCHEDULED → PENDING → SENT/FAILED
                  ↘ CANCELLED

Queue Configuration ​

  • ProcessCampaignJob: 2 attempts, 30 minute timeout
  • SendCampaignJob: 3 attempts, default timeout

Error Handling ​

  • Validation errors prevent campaign from being sent
  • Individual send failures don't mark entire campaign as failed
  • Campaign is marked as failed if too many sends fail or if processing job fails

Scheduled Task ​

Add to your application's app/Console/Kernel.php:

php
protected function schedule(Schedule $schedule)
{
    $schedule->command('mailhub:dispatch-pending-campaigns')
        ->everyMinute()
        ->withoutOverlapping();
}

Database Schema ​

mail_campaigns ​

ColumnTypeDescription
idbigintPrimary key
namestringCampaign name
subjectstringEmail subject line
statusenumStatus (draft, scheduled, pending, sent, failed, cancelled)
scheduled_atdatetimeWhen to send the campaign
sent_atdatetimeWhen the campaign was sent
created_bybigintUser ID who created the campaign
newsletter_idbigintAssociated newsletter ID (optional)
mail_template_idbigintAssociated template ID
custom_template_filestringPath to custom template file (optional)
sender_config_idbigintMail config ID
notestextCampaign notes

Integration Points ​

Filament UI ​

  • MailCampaignStatusAction: UI for changing campaign status and sending
  • EditMailCampaign: Adds "Send Now" button to edit page
  • Status management buttons added to campaign listing

Command Integration ​

Register the command in your service provider:

php
$this->commands([
    DispatchPendingCampaignsCommand::class,
]);

Usage Examples ​

Dispatching a Campaign Programmatically ​

php
$campaign = MailCampaign::find($id);
$dispatcher = app(CampaignDispatcher::class);
$result = $dispatcher->dispatchCampaign($campaign);

if ($result['success']) {
    // Campaign dispatched successfully
} else {
    // Handle error in $result['message']
}

Creating a Campaign with Template Variables ​

php
$template = MailTemplate::create([
    'name' => 'Welcome Template',
    'html' => '<h1>Hello @@userName@@!</h1><p>Welcome to our platform.</p>',
]);

$campaign = MailCampaign::create([
    'name' => 'Welcome Campaign',
    'subject' => 'Welcome, @@userName@@!',
    'mail_template_id' => $template->id,
    'sender_config_id' => $configId,
    'status' => MailCampaignStatus::DRAFT,
]);