Queues & batches
Every campaign is one Laravel job batch. prepare() opens an empty batch on the sending queue — with allowFailures() and a finally callback that ends the campaign once every job ran — and stores its id on the campaign. start() then adds one process-recipient-job per stored recipient to that batch; with nobody to send to, the campaign completes at once.
Workers
Point the sending queue at a dedicated queue and run a worker for it:
CAMPAIGNS_SENDING_QUEUE=campaignsphp artisan queue:work --queue=campaignsA Laravel batch pushes all of its jobs onto its own queue, so the batch is opened on sending-queue (the DefaultSendingQueue option) and every delivery job runs there — make sure a worker listens to it.
Failures and cancellation
- Failures are allowed: one bad recipient never stops the rest, and the campaign stays cancellable.
- A delivery fails when the job records it as failed — the shipped jobs catch every exception and do — or when the job itself fails (throws, times out, runs out of attempts). Either way it counts once, as failed, never as sent.
- Once every job ran, the campaign is Completed — even with failed recipients — or Failed when not one delivery got through. Read progress->failed, listen to RecipientFailed or query the recipients to find the failures.
- cancel() cancels the batch; queued jobs check $this->batch()?->cancelled() and exit without sending. A cancelled campaign stays Canceled when its batch finishes.
In-memory store and workers
The in-memory store lives for one request, console command or queued job — the container binds it scoped, so a long-running worker never accumulates campaigns. The next request or job, and every queue worker, starts empty: deliveries and events still happen in the worker, but progress is only tracked where the campaign was created. Use the database store whenever status and progress must be visible across requests and processes.
Show your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.