Skip to content

Sending notifications

A BaseNotify subclass is an ordinary Laravel notification: send it with $notifiable->notify() or Notification::send(). What the package adds happens inside it — via() decides the channels, toMail() / toArray() pick the template.

Two sending patterns cover most cases.

The event fires; the listener asks your recipient resolver who should get it, grouped by role, and sends one notification per role so each role gets its own template and channels:

use App\Events\OrderOrdered;
use App\Notifications\OrderOrderedNotify;
use Fomvasss\NotifyTemplates\Contracts\NotifyRoleResolverInterface;
use Fomvasss\NotifyTemplates\Facades\NotifyTemplates;
use Illuminate\Support\Facades\Notification;
class SendOrderOrderedNotifications
{
public function __construct(protected NotifyRoleResolverInterface $resolver) {}
public function handle(OrderOrdered $event): void
{
$order = $event->order->fresh();
foreach ($this->resolver->resolveUsersForNotify('OrderOrdered', $order) as $roleKey => $users) {
Notification::send(
$users,
(new OrderOrderedNotify($order, $roleKey))
->delay(NotifyTemplates::resolveDelay('OrderOrdered', $roleKey)),
);
}
}
}
sequenceDiagram
    participant App as App code
    participant Listener
    participant Resolver as NotifyRoleResolverInterface
    participant Laravel as Notification::send()
    participant Notify as OrderOrderedNotify

    App->>Listener: event(new OrderOrdered($order))
    Listener->>Resolver: resolveUsersForNotify('OrderOrdered', $order)
    Resolver-->>Listener: ['role_key' => users]
    loop each role_key
        Listener->>Laravel: send($users, new OrderOrderedNotify($order, $roleKey))
        Laravel->>Notify: via($user) — opt-outs, subscription, routes
        Laravel->>Notify: toMail($user) / toTelegram($user) / ...
        Notify->>Notify: resolveTemplate() — DB row or typeDefinition defaults
    end

resolveDelay() returns seconds from the subscription’s options.delay (minutes), 0 without a subscription. delay() comes from Queueable and works only for queued notifications.

For notifications triggered by the user’s own action — a login code, a password reset — send to the user directly with the role whose subscription and template apply:

$user->notify(new UserOtpNotify(roleKey: 'client', code: $code));

Mark such types 'user_configurable' => false when they must always arrive: they then go out through default_channels even without an active subscription. See User preferences.

only() and except() are applied last in via():

// only the mail out of the resolved channels
$user->notify((new UserOtpNotify(roleKey: 'client', code: $code))->only(['mail']));
// all resolved channels except sms
$user->notify((new OrderOrderedNotify($order, 'client'))->except(['sms']));

To force channels regardless of subscriptions, bypass via() with Laravel’s own sendNow():

Notification::sendNow($user, new UserOtpNotify(roleKey: 'client', code: $code), ['mail']);

Send to an address without a model with Notification::route():

Notification::route('mail', 'guest@example.com')
->notify(new OrderOrderedNotify($order, 'guest'));

mail is kept when the notifiable has a mail route — routeNotificationFor('mail'), which covers on-demand recipients, routeNotificationForMail() and the email attribute; a notifiable without routeNotificationFor() falls back to ->email. Before 0.12.2 only ->email was checked, so on-demand mail and routeNotificationForMail() were silently dropped. For an on-demand recipient there are no user preferences: isNotifyEnabled() is always true and no per-user channel preference applies; the role subscription still does. See Custom channels for the rest of mapChannel().

ChannelMethodContent
mailtoMail()Template slot mail: subject and body through prepareText()
database, broadcasttoArray()['message' => strip_tags(...)] of the messenger body
custom (Telegram, SMS, …)your to{Channel}()Usually getMessengerBody() — slot messenger, falling back to mail

Token substitution is your prepareText() — see Templates.