NewWe open-sourced 50+ Laravel packages
Custom AI apps, agents and automation — Roundly ConsultingRoundly
All packages

Open source

Campaigns for Laravel

Install
composer require roundly-consulting/campaigns-for-laravel
Requires: PHP ^8.4 · Laravel ^12.0|^13.0

Overview

Send one message to many recipients from any Laravel app. Campaigns for Laravel wraps Laravel’s own queues and job batches in a fluent builder: create a campaign, address it to email strings, contact records or model owners, and dispatch — one batch per campaign, one queued job per recipient, with progress tracking, lifecycle events and a cancel switch. Delivery is swappable (email, Laravel notifications or your own job), and so is storage: in-memory by default, database-backed with one config change. MIT-licensed and dependency-light — Laravel plus Roundly’s own contacts, options, enums and package-toolkit packages, no third-party mailing SDK.

What you get

Facade, handle & fake

Campaigns::create()->to()->dispatch() in one chain, a per-campaign handle, DI or plain actions — and Campaigns::fake() records every write.

Queued job batches

One Laravel job batch per campaign and one queued job per recipient. A failed delivery never stops the rest, and a running send can be cancelled.

Progress & lifecycle events

Status with sent, failed, pending and total counters and percentage(), plus seven events for campaigns and individual recipients.

Swappable delivery

HTML email by default, Laravel notifications for SMS or push, or your own job for any other transport.

Recipients from contacts

->to() accepts contacts-for-laravel records and HasContacts owners, with verified-only and contact-kind rules.

Runtime-editable defaults

Sender, sending queue, channel and recipient rules are typed options — stored values override config without a deploy.

Optional persistence

In-memory by default, a database store behind one env switch, or your own storage behind the CampaignStore contract.

Documentation

Installation

Install via Composer, run the options and contacts migrations, and publish the config and campaign tables only when you need them.

Configuration

Every config key, its default and env variable — store, sender, recipient rules, sending queue, delivery job and notification channel.

The Campaigns facade

Everything through one facade — create, prepare, start, cancel, find, all, a per-campaign handle, settings() and fake().

DI and actions

Inject CampaignManager instead of the facade, or run the prepare, start, cancel and recipient actions directly — with the facade-to-action map.

Sending a campaign

Create, address and dispatch a campaign with the fluent Campaigns facade — or prepare it now and start it later.

Recipients

Add recipients as strings, CampaignRecipient objects or iterables — including large lists streamed from a lazy query.

Recipients from contacts

Address campaigns from contacts-for-laravel records and HasContacts owners, with verified-only and contact-kind rules.

Progress & lookup

Find campaigns by UUID, read status, counters and percentage, page through them and cancel a running send.

Campaign status

The CampaignStatus lifecycle from Created to a terminal state, the event each transition fires, and the enum helpers.

Value objects

Campaign, CampaignRecipient and CampaignProgress — constructors, fields and their toArray() shapes.

Delivery channels

Deliver by HTML email with SendCampaignEmail or through Laravel notifications with SendCampaignNotification.

Custom delivery jobs

Implement ProcessesCampaignRecipient to deliver over SMS, push or any transport, with batch-safe cancellation and failure tracking.

Send defaults

Runtime-editable send defaults via options-for-laravel — option classes, registry keys, config seeds and precedence.

Campaign stores

Where campaigns live — the CampaignStore contract, the in-memory and database stores, and plugging in your own storage.

Database persistence

Switch to the DatabaseCampaignStore — schema, Eloquent models, factories and the UUID rule for persisted campaigns.

Queues & batches

How campaigns map to Laravel job batches — the sending queue, workers, failed deliveries, cancellation and the in-memory caveat.

Events

Seven lifecycle and recipient events with their payloads, for logging, dashboards, metrics and webhooks.

Artisan commands

List campaigns with their progress, cancel one by UUID, and check the setup with php artisan about.

Exceptions

CampaignNotFound, CampaignAlreadyExists, InvalidCampaignTransition, RecipientNotFound, config and builder argument errors — and when each occurs.

Testing

Record every write with Campaigns::fake() and assert created, started, cancelled and delivered — or run the real flow on a fake batch.

Requirements

PHP 8.4+, Laravel 12 or 13, four Roundly companion packages, a queue with job batches and a mailer or notification channel.

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 crypto

By 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.