Laravel notification channels for Email, WhatsApp (Facebook Graph API) and SMS (Taqnyat)

Maintainers

Package info

github.com/abdallahisham/notify

pkg:composer/softlandtech/notify

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 2

Open Issues: 0

dev-master 2026-03-17 04:31 UTC

This package is auto-updated.

Last update: 2026-05-17 04:52:35 UTC


README

A powerful Laravel package that extends Laravel's notification system with advanced features for Email, SMS (Taqnyat), and WhatsApp channels.

Features

  • Universal Channel Support: Works with any Laravel notification channel from laravel-notification-channels.com (100+ channels available)
  • Built-in Channels: Email (Mail), SMS (Taqnyat), WhatsApp Business API
  • Flexible Delivery Strategies: Send to all channels or use round-robin fallback
  • Channel Priority/Ordering: Define the order in which channels are attempted
  • Retry Logic: Automatic retry with exponential or linear backoff
  • Rate Limiting: Prevent notification spam
  • User Preferences: Allow users to choose their preferred channels
  • Sandbox Mode: Test notifications without actually sending them
  • Events System: Monitor notification lifecycle with dispatchable events
  • Notification History: Log all sent notifications to database
  • Channel Health Monitoring: Check channel configuration and API connectivity
  • Conditional Channel Rules: Custom logic to determine when each channel should be used
  • Template Management: Named WhatsApp templates with helper methods
  • Localization Support: Multi-language notification support
  • Testing Helpers: Sandbox assertions for easy testing

Installation

Step 1: Install the Package

composer require softlandtech/notify

Step 2: Publish Configuration

php artisan vendor:publish --tag=notify-config

Step 3: (Optional) Publish Migrations

If you want to use notification history:

php artisan vendor:publish --tag=notify-migrations
php artisan migrate

Configuration

The package is configured via config/notify.php and environment variables.

Environment Variables

# Notification Strategy
NOTIFICATION_STRATEGY=all  # or 'round_robin'

# Channels to use (comma-separated)
NOTIFICATION_CHANNELS=mail,sms,whatsapp

# Channel Order
NOTIFICATION_CHANNEL_ORDER=mail,sms,whatsapp

# Sandbox Mode
NOTIFICATION_SANDBOX=false

# Retry Configuration
NOTIFICATION_RETRY_ENABLED=false
NOTIFICATION_RETRY_ATTEMPTS=3
NOTIFICATION_RETRY_BACKOFF=exponential  # or 'linear'
NOTIFICATION_RETRY_DELAY=1000

# Rate Limiting
NOTIFICATION_RATE_LIMIT_ENABLED=true
NOTIFICATION_RATE_LIMIT_MAX=5
NOTIFICATION_RATE_LIMIT_DECAY=1

# Notification History
NOTIFICATION_HISTORY_ENABLED=false
NOTIFICATION_HISTORY_PRUNE_DAYS=30

# User Preferences
NOTIFICATION_USER_PREFERENCES_ENABLED=false

# Events
NOTIFICATION_EVENTS_ENABLED=true

# Taqnyat SMS
TAQNYAT_BASE_URL=https://api.taqnyat.sa
TAQNYAT_TOKEN=your-token
TAQNYAT_SENDER=your-sender

# WhatsApp
WHATSAPP_API_VERSION=v22.0
WHATSAPP_PHONE_NUMBER_ID=your-phone-number-id
WHATSAPP_TOKEN=your-access-token
WHATSAPP_TEMPLATE_NAME=your-default-template
WHATSAPP_TEMPLATE_LANGUAGE=en_US
WHATSAPP_DEFAULT_LANGUAGE=ar

# WhatsApp Templates
WHATSAPP_TEMPLATE_OTP=otp_template
WHATSAPP_TEMPLATE_VERIFICATION=verification_template
WHATSAPP_TEMPLATE_PASSWORD_RESET=password_reset_template

Also configure channels in config/notifications.php:

'channels' => array_filter(array_map('trim', explode(',', env('NOTIFICATION_CHANNELS', 'mail')))),

'channel_mapping' => [
    'mail' => \SoftLandTech\Notify\Channels\MailChannel::class,
    'sms' => \SoftLandTech\Notify\Channels\TaqnyatChannel::class,
    'whatsapp' => \SoftLandTech\Notify\Channels\WhatsappChannel::class,
],

Usage

Basic Notification

Create a notification that extends the package's base class:

<?php

namespace App\Notifications;

use SoftLandTech\Notify\Notification;
use SoftLandTech\Notify\Contracts\MailNotification;
use SoftLandTech\Notify\Contracts\SmsNotification;
use SoftLandTech\Notify\Contracts\WhatsAppNotification;

class WelcomeNotification extends Notification implements MailNotification, SmsNotification, WhatsAppNotification
{
    public function toMail(object $notifiable): array
    {
        return [
            'view' => 'emails.welcome',
            'subject' => 'Welcome to Our App',
            'data' => ['user' => $notifiable],
        ];
    }

    public function toSms(object $notifiable): string
    {
        return 'Welcome to our app!';
    }

    public function toWhatsapp(object $notifiable): array
    {
        return [
            'template_name' => 'welcome_template',
            'language' => 'ar',
            'parameters' => [$notifiable->name],
        ];
    }
}

Important: No need to define the via() method! The package handles channel routing automatically based on configuration.

Sending Notifications

$user->notify(new WelcomeNotification());

Advanced Features

1. Delivery Strategies

Send to All Channels (Default)

NOTIFICATION_STRATEGY=all

All configured channels will receive the notification, regardless of success/failure.

Round-Robin with Fallback

NOTIFICATION_STRATEGY=round_robin

Channels are tried in order. The first successful send stops the process.

You can also override per notification:

class UrgentNotification extends Notification
{
    protected function getStrategy(): string
    {
        return 'round_robin';  // Try channels until one succeeds
    }
}

2. Channel Priority/Ordering

Define the order in which channels are attempted:

NOTIFICATION_CHANNEL_ORDER=whatsapp,sms,mail

Or override per notification:

class SmsFirstNotification extends Notification
{
    protected function getChannelOrder(): array
    {
        return ['sms', 'whatsapp', 'mail'];
    }
}

3. Retry Logic

Enable automatic retries for failed notifications:

NOTIFICATION_RETRY_ENABLED=true
NOTIFICATION_RETRY_ATTEMPTS=3
NOTIFICATION_RETRY_BACKOFF=exponential  # or 'linear'
NOTIFICATION_RETRY_DELAY=1000  # milliseconds

Or customize per notification:

class ImportantNotification extends Notification
{
    protected function shouldRetry(): bool
    {
        return true;
    }

    protected function getRetryConfig(): array
    {
        return [
            'attempts' => 5,
            'backoff' => 'exponential',
            'delay' => 2000,
        ];
    }
}

4. Rate Limiting

Prevent notification spam:

NOTIFICATION_RATE_LIMIT_ENABLED=true
NOTIFICATION_RATE_LIMIT_MAX=5  # Max 5 notifications
NOTIFICATION_RATE_LIMIT_DECAY=1  # Per minute

Override per notification:

class LimitedNotification extends Notification
{
    protected function shouldRateLimit(): bool
    {
        return true;
    }

    protected function getRateLimitConfig(): array
    {
        return [
            'max_attempts' => 3,
            'decay_minutes' => 5,
        ];
    }
}

5. User Channel Preferences

Allow users to control which channels they receive notifications on:

NOTIFICATION_USER_PREFERENCES_ENABLED=true

Add a notification_preferences attribute to your User model:

// User model
protected $casts = [
    'notification_preferences' => 'array',
];

// Set user preferences
$user->notification_preferences = ['mail', 'whatsapp'];
$user->save();

6. Sandbox Mode

Test notifications without sending them:

NOTIFICATION_SANDBOX=true
use SoftLandTech\Notify\Channels\SandboxChannel;

// In tests
SandboxChannel::assertSent(WelcomeNotification::class);
SandboxChannel::assertSent(WelcomeNotification::class, function ($notification, $notifiable) use ($user) {
    return $notifiable->id === $user->id;
});
SandboxChannel::assertNotSent(SpamNotification::class);
SandboxChannel::clear();  // Clear sandbox history

7. Events System

Listen to notification events:

use SoftLandTech\Notify\Events\NotificationSending;
use SoftLandTech\Notify\Events\NotificationSent;
use SoftLandTech\Notify\Events\NotificationFailed;
use SoftLandTech\Notify\Events\ChannelSkipped;
use SoftLandTech\Notify\Events\RoundRobinFallback;

Event::listen(NotificationSent::class, function ($event) {
    Log::info('Notification sent', [
        'notification' => get_class($event->notification),
        'channel' => $event->channel,
    ]);
});

8. Notification History

Enable database logging of all notifications:

NOTIFICATION_HISTORY_ENABLED=true
php artisan vendor:publish --tag=notify-migrations
php artisan migrate

Query notification history:

use SoftLandTech\Notify\Models\NotificationHistory;

// Get all sent notifications for a user
$history = NotificationHistory::where('notifiable_type', User::class)
    ->where('notifiable_id', $user->id)
    ->where('status', 'sent')
    ->get();

// Get failed notifications
$failed = NotificationHistory::where('status', 'failed')->get();

9. Channel Health Monitoring

Check if your notification channels are properly configured:

# Check all channels
php artisan notifications:check-health

# Check specific channel
php artisan notifications:check-health mail
php artisan notifications:check-health sms
php artisan notifications:check-health whatsapp

Programmatically:

use SoftLandTech\Notify\ChannelHealthMonitor;

$monitor = app(ChannelHealthMonitor::class);

$results = $monitor->checkAll();
// ['mail' => [...], 'sms' => [...], 'whatsapp' => [...]]

$mailHealth = $monitor->checkMail();

10. Conditional Channel Rules

Implement custom logic to determine when each channel should be used:

class PremiumNotification extends Notification
{
    protected function shouldUseChannel(string $channelName, object $notifiable): bool
    {
        // Only use WhatsApp for premium users
        if ($channelName === 'whatsapp') {
            return $notifiable->isPremium();
        }

        // Only send emails during business hours
        if ($channelName === 'mail') {
            return now()->hour >= 9 && now()->hour < 17;
        }

        return true;
    }
}

11. Template Management

Use the template management trait for WhatsApp notifications:

use SoftLandTech\Notify\Notification;
use SoftLandTech\Notify\Concerns\HasTemplates;
use SoftLandTech\Notify\Contracts\WhatsAppNotification;

class OtpNotification extends Notification implements WhatsAppNotification
{
    use HasTemplates;

    public function __construct(public string $code) {}

    public function toWhatsapp(object $notifiable): array
    {
        // Helper method for OTP templates
        return $this->buildOtpTemplate($this->code, 5);
    }
}

Available template helpers:

$this->buildOtpTemplate($code, $expiryMinutes);
$this->buildVerificationTemplate($code);
$this->buildPasswordResetTemplate($code, $expiryMinutes);
$this->buildTemplate('custom_template', ['param1', 'param2'], 'ar');
$this->getTemplate('otp');  // Gets template name from config

12. Localization Support

Use the localization trait for multi-language support:

use SoftLandTech\Notify\Notification;
use SoftLandTech\Notify\Concerns\Localizable;
use SoftLandTech\Notify\Contracts\MailNotification;

class LocalizedNotification extends Notification implements MailNotification
{
    use Localizable;

    public function toMail(object $notifiable): array
    {
        return $this->withLocale($notifiable, function () use ($notifiable) {
            return [
                'view' => 'emails.welcome',
                'subject' => $this->trans('notifications.welcome.subject', [], $notifiable),
                'data' => [
                    'message' => $this->trans('notifications.welcome.message', ['name' => $notifiable->name]),
                ],
            ];
        });
    }
}

The trait will automatically detect the user's locale from:

  1. $notifiable->locale attribute
  2. $notifiable->preferredLocale() method
  3. Application default locale

Adding Community Notification Channels

The package supports any Laravel notification channel from laravel-notification-channels.com. All features (retry, rate limiting, sandbox mode, events, etc.) automatically work with any channel!

Example: Adding Slack

  1. Install the Slack channel:
composer require laravel/slack-notification-channel
  1. Add to config/notifications.php:
'channels' => array_filter(array_map('trim', explode(',', env('NOTIFICATION_CHANNELS', 'mail,slack')))),

'channel_mapping' => [
    'mail' => \SoftLandTech\Notify\Channels\MailChannel::class,
    'sms' => \SoftLandTech\Notify\Channels\TaqnyatChannel::class,
    'whatsapp' => \SoftLandTech\Notify\Channels\WhatsappChannel::class,
    'slack' => \Illuminate\Notifications\Slack\SlackChannel::class, // Add this
],
  1. Update your .env:
NOTIFICATION_CHANNELS=mail,slack
SLACK_WEBHOOK_URL=your-webhook-url
  1. Use in notifications:
use SoftLandTech\Notify\Notification;
use SoftLandTech\Notify\Contracts\MailNotification;
use Illuminate\Notifications\Slack\SlackMessage;

class OrderShipped extends Notification implements MailNotification
{
    public function toMail(object $notifiable): array
    {
        return [
            'view' => 'emails.order-shipped',
            'subject' => 'Your order has shipped!',
        ];
    }

    public function toSlack(object $notifiable): SlackMessage
    {
        return (new SlackMessage)
            ->content('Your order has shipped!');
    }
}

// Add routing in your User model
public function routeNotificationFor(string $channel): mixed
{
    return match($channel) {
        'mail' => $this->email,
        'slack' => env('SLACK_WEBHOOK_URL'),
        'sms', 'whatsapp' => $this->phone,
        default => null,
    };
}

That's it! Slack notifications now have retry logic, rate limiting, sandbox mode, and all other features.

More Channel Examples

Discord

composer require laravel-notification-channels/discord
'discord' => \NotificationChannels\Discord\DiscordChannel::class,

Telegram

composer require laravel-notification-channels/telegram
'telegram' => \NotificationChannels\Telegram\TelegramChannel::class,

Vonage (SMS)

composer require laravel/vonage-notification-channel
'vonage' => \Illuminate\Notifications\VonageChannel::class,

Twilio

composer require laravel-notification-channels/twilio
'twilio' => \NotificationChannels\Twilio\TwilioChannel::class,

Firebase (Push Notifications)

composer require laravel-notification-channels/fcm
'fcm' => \NotificationChannels\Fcm\FcmChannel::class,

Browse All Channels

Visit laravel-notification-channels.com to see 100+ available channels including:

  • Social: Facebook, Twitter, LinkedIn
  • Messaging: Discord, Telegram, Slack, Microsoft Teams
  • SMS: Twilio, Nexmo, Vonage, MessageBird
  • Push: Firebase, OneSignal, Pusher
  • And many more!

Facades

The package provides convenient facades:

use Taqnyat;
use Whatsapp;

// Send SMS via Taqnyat
Taqnyat::sendSms('966500000000', 'Your OTP is 123456');

// Send WhatsApp template
Whatsapp::sendTemplate('966500000000', [
    'template_name' => 'otp',
    'language' => 'ar',
    'parameters' => ['123456', '5'],
]);

Testing

Unit Tests

vendor/bin/pest

Using Sandbox Mode in Tests

use SoftLandTech\Notify\Channels\SandboxChannel;

class NotificationTest extends TestCase
{
    protected function setUp(): void
    {
        parent::setUp();
        config(['notify.sandbox' => true]);
        SandboxChannel::clear();
    }

    public function test_welcome_notification_is_sent()
    {
        $user = User::factory()->create();

        $user->notify(new WelcomeNotification());

        SandboxChannel::assertSent(WelcomeNotification::class, function ($notification, $notifiable) use ($user) {
            return $notifiable->id === $user->id;
        });
    }
}

Customization

Custom Notification Stub

The package modifies the make:notification stub to automatically extend the package's base class:

php artisan make:notification MyNotification

This will generate:

<?php

namespace App\Notifications;

use SoftLandTech\Notify\Notification;
use Illuminate\Bus\Queueable;

class MyNotification extends Notification
{
    use Queueable;

    // No via() method needed!
}

Events Reference

Event Properties Description
NotificationSending $notification, $notifiable, $channel Fired before sending
NotificationSent $notification, $notifiable, $channel, $response Fired after successful send
NotificationFailed $notification, $notifiable, $channel, $exception Fired on failure
ChannelSkipped $notification, $notifiable, $channel, $reason Fired when a channel is skipped
RoundRobinFallback $notification, $notifiable, $failedChannel, $nextChannel, $exception Fired during round-robin fallback

Architecture

The package uses the Decorator pattern to layer features around any Laravel notification channel:

SandboxChannel (if enabled)
  └─ RateLimitedChannel (if enabled)
      └─ RetryableChannel (if enabled)
          └─ Any Channel (MailChannel, SlackChannel, DiscordChannel, etc.)

This architecture ensures that:

  • All features (retry, rate limiting, sandbox, events, history) work with any Laravel notification channel
  • Features can be enabled/disabled independently
  • New channels can be added instantly without code changes
  • The decorator layers are applied automatically to all channels

Simply add any community channel to your channel_mapping config and all features will work immediately!

License

This package is proprietary software.

Credits

Created by Abdallah Isham