Drip Sequences
A drip sequence is a series of emails sent to contacts automatically, each after a configurable delay from the previous one. Common use cases: welcome sequences, onboarding flows, re-engagement campaigns.
How it works
- You create a
drip_sequencecampaign and add steps to it (each step is one email with a delay) - Contacts get enrolled — either at subscribe time, or explicitly via
DripService - A cron job runs
courier:process-dripsfrequently; it finds enrollments whosenext_send_athas passed, sends the email, and advances the contact to the next step - When a contact completes all steps, their enrollment is marked
completed; if they unsubscribe, all active enrollments are cancelled
Creating a drip campaign
<?php
$campaignService = service('campaignService');
$campaign = $campaignService->create([
'name' => 'Welcome Sequence',
'subject' => 'Welcome!', // overridden per-step
'from_name' => 'Acme Team',
'from_email' => 'hello@acme.com',
'type' => 'drip_sequence',
]);
Adding steps
Each step needs a view, a subject, and a delay_hours — how many hours after the previous step (or enrollment) to wait before sending.
<?php
// Step 1: send immediately (0-hour delay)
$campaignService->addDripStep($campaign->id, [
'subject' => 'Welcome to Acme!',
'view' => 'App\Views\emails\welcome_step1',
'delay_hours' => 0,
]);
// Step 2: send 24 hours after step 1
$campaignService->addDripStep($campaign->id, [
'subject' => 'Getting started with Acme',
'view' => 'App\Views\emails\welcome_step2',
'delay_hours' => 24,
]);
// Step 3: send 72 hours after step 2
$campaignService->addDripStep($campaign->id, [
'subject' => 'Pro tips you\'ll love',
'view' => 'App\Views\emails\welcome_step3',
'delay_hours' => 72,
]);
Steps are ordered by position, which is assigned automatically (1, 2, 3…) if you don't set it.
Enrolling contacts
At subscribe time
The easiest way — pass dripCampaignId to ContactService::subscribe():
<?php
service('contactService')->subscribe(
['email' => 'ada@example.com'],
dripCampaignId: $campaign->id
);
Explicitly
<?php
$dripService = service('dripService');
$enrollment = $dripService->enroll($contact->id, $campaign->id);
enroll() returns null if the contact is already enrolled (any status — prevents double-enrolling). It throws a RuntimeException if the contact isn't subscribed or the campaign has no steps yet.
Processing due steps
The courier:process-drips command does the actual sending. Run it frequently via cron:
Each run processes up to $batchSize enrollments (default: 200). If you have more than that in the queue, they'll drain across successive runs — that's intentional so you don't blast your email provider.
Cancelling an enrollment
To cancel a specific contact from one campaign:
To cancel all drip enrollments for a contact (this happens automatically on unsubscribe):
Checking enrollment status
<?php
$enrollment = $dripService->getEnrollmentStatus($contact->id, $campaign->id);
// Returns DripEnrollmentDTO or null
Enrollment statuses: active, cancelled, completed.