Appearance
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 informationMailTemplate
: Stores email templates with HTML contentSubscriber
: Represents recipients with email and status fieldsNewsletter
: 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
Campaign Preparation
- User creates a campaign with template, subject, recipients
- Campaign gets saved with status
DRAFT
orSCHEDULED
Campaign Triggering
- User manually triggers sending via Filament UI, or
- Scheduled campaigns are picked up by the command
Validation
CampaignDispatcher
usesCampaignValidator
to check:- Campaign has appropriate status
- Template exists
- Mail configuration exists
- Recipients exist
Queue Processing
ProcessCampaignJob
is dispatched to queue- Campaign status is updated to
PENDING
- For each recipient, a
SendCampaignJob
is dispatched
Email Generation and Sending
SendCampaignJob
usesCampaignMailer
to send to each recipientCampaignMailParser
processes template variables- Email is sent using Laravel's mail system
Status Updates
- When all sends are complete, campaign status is updated to
SENT
- If errors occur, status may be updated to
FAILED
- When all sends are complete, campaign status is updated to
Template Variables
Variables in templates use the @@variable@@
format. Supported variables:
Variable | Description |
---|---|
@@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 timeoutSendCampaignJob
: 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
Column | Type | Description |
---|---|---|
id | bigint | Primary key |
name | string | Campaign name |
subject | string | Email subject line |
status | enum | Status (draft, scheduled, pending, sent, failed, cancelled) |
scheduled_at | datetime | When to send the campaign |
sent_at | datetime | When the campaign was sent |
created_by | bigint | User ID who created the campaign |
newsletter_id | bigint | Associated newsletter ID (optional) |
mail_template_id | bigint | Associated template ID |
custom_template_file | string | Path to custom template file (optional) |
sender_config_id | bigint | Mail config ID |
notes | text | Campaign notes |
Integration Points
Filament UI
MailCampaignStatusAction
: UI for changing campaign status and sendingEditMailCampaign
: 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,
]);