Recipients
->to() is additive and accepts an email/route string, a CampaignRecipient, a contacts-for-laravel Contact record, a HasContacts owner model, or any iterable of those — an array, a collection or a generator:
use Illuminate\Support\Str;
use RoundlyConsulting\Campaigns\CampaignRecipient;
use RoundlyConsulting\Campaigns\Facades\Campaigns;
Campaigns::create('Our spring collection is here', $html)
->from('[email protected]', 'Example Shop')
->to('[email protected]') // one address or route
->to(['[email protected]', '[email protected]']) // any iterable — calls are additive
->to(new CampaignRecipient( // full control over the id and name
uuid: (string) Str::uuid(),
name: 'Dana Novak',
reachableAt: '[email protected]',
))
->dispatch();- A plain string becomes a recipient whose name and address are both that string, with a generated UUID.
- A CampaignRecipient is kept as-is — use it to set a display name or your own id.
- Each address is added once: one already on the campaign — compared case-insensitively, however it arrives (a string, a CampaignRecipient, an owner or a contact) — is skipped, and the first one added wins.
- A recipient that already belongs to another campaign is added as a fresh copy — new uuid, clean delivery state — and never moved out of the campaign it came from.
- Anything else — a number, or a model without the HasContacts trait — throws InvalidArgumentException.
Contact records and owners have their own rules — see Recipients from contacts.
Large lists
For big audiences, stream the source query instead of loading it at once: lazyById() reads the table in chunks, and to() accepts the lazy collection like any other iterable. Every recipient is stored when the campaign is prepared, and start() then dispatches one job per stored recipient:
use App\Models\Subscriber;
use Illuminate\Support\Str;
use RoundlyConsulting\Campaigns\CampaignRecipient;
use RoundlyConsulting\Campaigns\Facades\Campaigns;
$campaign = Campaigns::create('Monthly digest', $html)
->from('[email protected]', 'Example Shop')
->to(Subscriber::query()->lazyById(500)->map(fn (Subscriber $subscriber) => new CampaignRecipient(
uuid: (string) Str::uuid(),
name: $subscriber->name,
reachableAt: $subscriber->email,
)))
->prepare();
Campaigns::start($campaign); // one job per stored recipientCollect the whole audience before prepare() or dispatch() — start() queues the recipients stored at that moment.
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.