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,
]);