Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Bulk Notifications Laravel Package

escolalms/bulk-notifications

Laravel package for sending bulk notifications to many recipients at once. Queue-friendly, supports multiple channels and templated messages, with simple APIs for scheduling and tracking delivery across large user groups in e-learning platforms.

View on GitHub
Deep Wiki
Context7

Getting Started

escolalms/bulk-notifications is the campaign layer of the EscolaLMS stack: you define an audience, compose a message, and the package fans it out to those users over the configured channels (mail, SMS, in-app) rather than you hand-rolling Notification::send() per segment.

Minimal setup:

composer require escolalms/bulk-notifications
php artisan vendor:publish --provider="EscolaLMS\BulkNotifications\Providers\BulkNotificationsServiceProvider"
php artisan migrate
php artisan db:seed --class="EscolaLMS\BulkNotifications\Database\Seeders\PermissionsTableSeeder"
php artisan db:seed --class="EscolaLMS\BulkNotifications\Database\Seeders\RolesTableSeeder"

Then check config/bulk-notifications.php first — that is where channel toggles and (as of 0.0.7) the new base_redirect_url live. Second stop: the admin API routes registered by the provider (/api/admin/bulk-notifications/*), which are the canonical example of every DTO and validation rule the package expects. Read the Models/BulkNotification and its audience/section relations before writing anything, because the audience model is what everything else keys off.

First use case worth shipping: an announcement to one course cohort. Create the notification, attach the audience (a constrained user query), preview the rendered body, then mark it ready and let the scheduled dispatcher pick it up. That gives you an end-to-end trace through models → jobs → channel drivers before you try anything clever like scheduled drip campaigns.

Implementation Patterns

Audience as a query, not a list. Don't collect user IDs into an array and pass them in. Build the audience from the same Eloquent scopes the rest of your app uses (enrolment, role, group membership) so it stays correct as users enrol or drop out between creation and send time. Materialising recipients should happen inside the dispatch job at send time, not at creation time.

Compose → preview → schedule → dispatch is a pipeline. Treat the notification record as a state machine. The high-value pattern is creating in draft, rendering a preview against a sample user (catches broken template variables before 5,000 people see {{ first_name }}), then transitioning to scheduled. Keep the preview step in your own admin UI even if the package exposes one.

Wrap creation in your own action/command class. The 0.x API surface moves. If your controllers call BulkNotification::create([...]) directly, every minor release is a refactor. Put a single CreateBulkNotificationAction or BulkNotificationService in your app that maps your domain concepts onto the package, and let the package's internals churn behind it.

Drive from events, not from polling. Whatever status fields the package exposes, poll them from a scheduled command only as a fallback. Prefer listening to the model events the provider hooks and recording delivery state into your own table if you need reporting the package doesn't give you.

Deep-linking with base_redirect_url (0.0.7). The new setting lets notification links resolve relative to a configurable base rather than a hardcoded app URL. This is exactly what you want when the same platform serves multiple front-ends (student portal, mobile web, white-label tenants): set the base per environment in .env, and set it per-tenant at runtime with config(['bulk-notifications.base_redirect_url' => $tenant->url]) inside a middleware if you're multi-tenant. Pair it with a signed or tokenised redirect route so a click can log engagement before bouncing the user to the destination.

Test with fakes. Anywhere you assert on sending, fake the notification/mail channel and assert on the queued jobs rather than on SMTP. Assert the audience count separately from the dispatch — most bulk-notification bugs are audience bugs, not mail bugs.

Notification::fake();
$this->artisan('bulk-notifications:dispatch')->assertSuccessful();
Notification::assertSentToTimes($user, CourseAnnouncement::class, 1);

Chunking and queue separation. If the package dispatches per-recipient jobs, give it its own queue connection (bulk-notifications queue) so a 20k-recipient campaign doesn't starve your transactional password-reset mail. Configure it in config/queue.php and point the package's queue config at it.

Gotchas and Tips

  • It's 0.x. Pin the exact version in composer.json ("escolalms/bulk-notifications": "0.0.7"). Minor bumps in 0.x are allowed to break; 0.0.7 adding base_redirect_url is additive, but nothing guarantees 0.0.8 will be.
  • php artisan config:cache after changing base_redirect_url. The single most common "the link goes to the wrong place" report is a stale config cache on a deployed environment. Also verify the base has a trailing slash policy — join it consistently, don't rely on the package to normalise, and never set it to a relative path.
  • Permissions are seeded, not migrated. A fresh deploy that runs migrate but forgets the permission seeder produces 403s on every admin endpoint with no obvious error. Add both seeders to your deploy script.
  • Scheduled notifications and timezones. Store send times in UTC and be explicit about it. Users expect "9am" in their locale; if the package schedules on a single global dispatcher, that means per-audience scheduling or per-recipient jobs, not one timestamp.
  • Retries cause duplicates. If dispatch is queued and a job retries after a partial failure, recipients already sent to may receive the message twice. Make your dispatch job idempotent by recording a (notification_id, user_id, channel) sent-marker with a unique index.
  • SMS is rate-limited upstream. Mail will happily take 10k messages; an SMS gateway will throttle or bill you. Check the channel driver config for batch/delay settings before your first large SMS campaign, and test with a 5-user audience first.
  • Template variables fail silently. A missing variable usually renders as an empty string rather than throwing. Assert in preview that every placeholder resolves, and validate placeholders at save time against the audience's available attributes.
  • Extension points: look for config-driven model and channel bindings (config/bulk-notifications.php typically allows swapping the notification model and registering channel drivers). Prefer registering a custom channel driver over forking — it survives upgrades, forking does not.
  • Debugging a "nothing sent" report: check queue worker is running on the right connection → check the notification's state is not still draft → check audience query returns non-zero at send time → check channel is enabled in config. That ordering resolves the vast majority of issues.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource