PHPackages                             schoolpalm/message-delivery - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Mail &amp; Notifications](/categories/mail)
4. /
5. schoolpalm/message-delivery

ActiveLibrary[Mail &amp; Notifications](/categories/mail)

schoolpalm/message-delivery
===========================

A message delivery package supporting email, sms, push and whatsapp providers for Laravel packages.

1.0.0(today)00MITPHPPHP ^8.2

Since Aug 1Pushed todayCompare

[ Source](https://github.com/codeparl/message-delivery)[ Packagist](https://packagist.org/packages/schoolpalm/message-delivery)[ Fund](https://schoolpalm.com)[ RSS](/packages/schoolpalm-message-delivery/feed)WikiDiscussions master Synced today

READMEChangelog (1)Dependencies (11)Versions (2)Used By (0)

SchoolPalm Message Delivery
===========================

[](#schoolpalm-message-delivery)

A Laravel package for multi-channel message delivery supporting **Email**, **SMS**, **WhatsApp**, **Push Notifications**, and **In-App Notifications** — with a **Notification Engine** that orchestrates the entire flow through resolver interfaces.

---

Table of Contents
-----------------

[](#table-of-contents)

- [SchoolPalm Message Delivery](#schoolpalm-message-delivery)
    - [Table of Contents](#table-of-contents)
    - [Architecture](#architecture)
    - [Installation](#installation)
        - [Aliases](#aliases)
    - [Configuration](#configuration)
        - [Configuration Reference](#configuration-reference)
    - [Message Delivery](#message-delivery)
        - [Single Channel](#single-channel)
        - [Multi-Channel](#multi-channel)
        - [Context Propagation](#context-propagation)
        - [Queue Options](#queue-options)
    - [Notification Engine](#notification-engine)
        - [Overview](#overview)
        - [Resolvers](#resolvers)
        - [Engine Flow](#engine-flow)
        - [Fluent API](#fluent-api)
        - [Extending Resolvers](#extending-resolvers)
    - [Channels](#channels)
    - [Providers](#providers)
        - [SMS Providers](#sms-providers)
        - [WhatsApp Providers](#whatsapp-providers)
        - [Push Providers](#push-providers)
        - [Email Providers](#email-providers)
        - [In-App Provider](#in-app-provider)
    - [Provider Definitions](#provider-definitions)
    - [Provider Registry](#provider-registry)
    - [Delivery Tracking](#delivery-tracking)
    - [Events](#events)
    - [Testing](#testing)
        - [Running Tests](#running-tests)
        - [Writing Tests](#writing-tests)
    - [Publishing](#publishing)
        - [Config](#config)
        - [Migrations](#migrations)
    - [License](#license)

---

Architecture
------------

[](#architecture)

```
Business Module
       │
       ▼
Notification Engine   (orchestrator — resolves everything)
       │
       ▼
    Resolvers         (interfaces — replaced by application adapters)
       │
       ▼
Message Builder       (fluent API for constructing messages)
       │
       ▼
Message Delivery      (core delivery logic)
       │
       ▼
  ┌────┬────┬────┬────┐
Email  SMS  Push  In-App
(WhatsApp)

```

**Key principle:** The package is an **infrastructure package** only. It knows nothing about your business models (Student, Parent, Teacher, etc.). All business-specific logic is supplied by your application through resolver interfaces.

---

Installation
------------

[](#installation)

```
composer require schoolpalm/message-delivery
```

The service provider is auto-discovered. If you disable auto-discovery, add it manually:

```
// config/app.php
'providers' => [
    SchoolPalm\MessageDelivery\MessageDeliveryServiceProvider::class,
],
```

### Aliases

[](#aliases)

The package registers two facades:

FacadeAccessorDescription`MessageDelivery``message-delivery`Direct message delivery API`Notification``notification`Notification Engine orchestration---

Configuration
-------------

[](#configuration)

Publish the configuration:

```
php artisan vendor:publish --tag=message-delivery-config
```

### Configuration Reference

[](#configuration-reference)

```
// config/message-delivery.php

return [

    /*
    | Default channel when none is explicitly selected.
    */
    'default_channel' => env('MESSAGE_DEFAULT_CHANNEL', 'email'),

    /*
    | Notification Engine defaults.
    */
    'notification' => [
        'default_language' => env('MESSAGE_DEFAULT_LANGUAGE', 'en'),
        'default_priority' => env('MESSAGE_DEFAULT_PRIORITY', 'normal'),
    ],

    /*
    | Enable/disable delivery lifecycle tracking.
    */
    'delivery_tracking' => env('MESSAGE_DELIVERY_TRACKING', true),

    /*
    | Default provider for each channel.
    */
    'channels' => [
        'email'    => env('MESSAGE_EMAIL_PROVIDER', 'laravel-mail'),
        'sms'      => env('MESSAGE_SMS_PROVIDER', 'egosms'),
        'whatsapp' => env('MESSAGE_WHATSAPP_PROVIDER', 'twilio-whatsapp'),
        'push'     => env('MESSAGE_PUSH_PROVIDER', 'firebase'),
    ],

    /*
    | Provider credentials (for development/testing only).
    | In production, providers may obtain config from TenantProviderSettings.
    */
    'providers' => [
        'laravel-mail' => [
            'mailer' => env('MESSAGE_MAIL_MAILER', env('MAIL_MAILER', 'smtp')),
        ],
        'egosms' => [
            'api_url'   => env('EGOSMS_API_URL'),
            'username'  => env('EGOSMS_USERNAME'),
            'password'  => env('EGOSMS_PASSWORD'),
            'sender_id' => env('EGOSMS_SENDER_ID'),
        ],
        'twilio-sms' => [
            'sid'   => env('TWILIO_SID'),
            'token' => env('TWILIO_TOKEN'),
            'from'  => env('TWILIO_FROM'),
        ],
        'twilio-whatsapp' => [
            'sid'   => env('TWILIO_SID'),
            'token' => env('TWILIO_TOKEN'),
            'from'  => env('TWILIO_WHATSAPP_FROM'),
        ],
        'firebase' => [
            'credentials' => env('FIREBASE_CREDENTIALS'),
        ],
    ],
];
```

---

Message Delivery
----------------

[](#message-delivery)

### Single Channel

[](#single-channel)

Each channel has a dedicated builder method accessible via the `MessageDelivery` facade.

**SMS:**

```
use SchoolPalm\MessageDelivery\Facades\MessageDelivery;

MessageDelivery::sms()
    ->to('+250788123456')
    ->text('Your verification code is 1234')
    ->send();
```

**Email:**

```
MessageDelivery::email()
    ->to('user@example.com')
    ->subject('Welcome')
    ->text('Thank you for joining')
    ->send();
```

**Email with view:**

```
MessageDelivery::email()
    ->to('user@example.com')
    ->view('emails.welcome')
    ->with(['name' => 'John'])
    ->send();
```

**Push Notification:**

```
MessageDelivery::push()
    ->to('device-token-xyz')
    ->title('New Message')
    ->text('You have a new message')
    ->with(['deep_link' => '/messages/123'])
    ->send();
```

**In-App Notification:**

```
MessageDelivery::inApp()
    ->to(['notifiable_type' => 'App\Models\User', 'notifiable_id' => 1])
    ->title('Account Updated')
    ->text('Your profile was updated successfully')
    ->send();
```

**WhatsApp:**

```
MessageDelivery::whatsapp()
    ->to('+250788123456')
    ->text('Your order has been confirmed')
    ->send();
```

### Multi-Channel

[](#multi-channel)

Send the same message through multiple channels:

```
MessageDelivery::multi()
    ->channels(['email', 'sms', 'in_app'])
    ->to('user@example.com')
    ->title('Payment Received')
    ->text('Your payment of $50 has been received')
    ->send();
```

Or chain with context:

```
MessageDelivery::withContext(['tenant_id' => 1])
    ->channels(['email', 'sms'])
    ->to('user@example.com')
    ->text('Your invoice is ready')
    ->send();
```

### Context Propagation

[](#context-propagation)

Attach execution context that flows through the entire delivery:

```
MessageDelivery::withContext([
    'tenant_id' => 1,
    'school_id' => 42,
    'module'    => 'finance',
])
->sms()
->to('+250788123456')
->text('Fee payment reminder')
->send();
```

### Queue Options

[](#queue-options)

Send messages through the queue:

```
// Queue immediately
MessageDelivery::sms()
    ->to('+250788123456')
    ->text('Hello')
    ->queue();

// Queue with delay
MessageDelivery::email()
    ->to('user@example.com')
    ->text('Reminder')
    ->delay(now()->addHours(24))
    ->queue();

// Advanced queue configuration
MessageDelivery::sms()
    ->to('+250788123456')
    ->text('Hello')
    ->onQueue('notifications')
    ->onConnection('redis')
    ->tries(3)
    ->backoff([10, 30, 60])
    ->timeout(120)
    ->send();
```

---

Notification Engine
-------------------

[](#notification-engine)

### Overview

[](#overview)

The Notification Engine is an **orchestrator** that sits between your business modules and the Message Delivery layer. Instead of calling `MessageDelivery::sms()->to(...)->send()` directly, you dispatch a **notification event** and the engine resolves everything.

```
use SchoolPalm\MessageDelivery\Facades\Notification;

// Simple dispatch
Notification::dispatch('fee.payment_received', [
    'student_name' => 'John Doe',
    'amount'       => 50000,
    'due_date'     => '2025-01-15',
]);

// Or use the fluent API
Notification::event('fee.payment_received')
    ->data(['student_name' => 'John Doe', 'amount' => 50000])
    ->channels(['email', 'sms'])
    ->priority('high')
    ->dispatch();
```

### Resolvers

[](#resolvers)

The engine uses **resolver interfaces** to determine how to deliver the notification. All resolvers have **Null implementations** so the package works out of the box. Your application replaces these bindings with custom implementations.

Resolver InterfaceNull ImplementationPurpose`EventResolver``NullEventResolver`Enrich event with metadata`RecipientResolver``NullRecipientResolver`Resolve who receives the notification`PreferenceResolver``NullPreferenceResolver`Resolve user channel preferences`ChannelResolver``NullChannelResolver`Determine delivery channels`LanguageResolver``NullLanguageResolver`Determine notification language`TemplateResolver``NullTemplateResolver`Load message templates`PriorityResolver``NullPriorityResolver`Determine message priority`ScheduleResolver``NullScheduleResolver`Determine delivery schedule`RetryResolver``NullRetryResolver`Determine retry policy### Engine Flow

[](#engine-flow)

```
NotificationEvent
       │
       ▼
EventResolver      → enrich event metadata
       │
       ▼
RecipientResolver  → resolve recipients
       │
       ▼
PreferenceResolver → resolve channel preferences
       │
       ▼
ChannelResolver    → determine channels
       │
       ▼
LanguageResolver   → determine language
       │
       ▼
TemplateResolver   → load message template
       │
       ▼
PriorityResolver   → determine priority
       │
       ▼
ScheduleResolver   → determine schedule/delay
       │
       ▼
RetryResolver      → determine retry policy
       │
       ▼
Build Messages     → construct Message objects per channel
       │
       ▼
MessageDelivery    → delegate to existing delivery infrastructure

```

### Fluent API

[](#fluent-api)

The `NotificationDispatch` builder provides a fluent chainable API:

```
Notification::event('student.admitted')
    ->data([
        'student_name' => 'Jane Doe',
        'class'        => 'Grade 5',
        'admission_no' => 'ADM-2025-001',
    ])
    ->context([
        'tenant_id' => 1,
        'school_id' => 42,
    ])
    ->metadata([
        'source' => 'admissions_module',
    ])
    ->channels(['email', 'sms', 'in_app'])
    ->language('en')
    ->priority('high')
    ->template('student_admitted')
    ->dispatch();
```

### Extending Resolvers

[](#extending-resolvers)

To replace a resolver, bind your implementation in the service container:

```
// In your AppServiceProvider or a dedicated service provider
use SchoolPalm\MessageDelivery\Notification\Contracts\RecipientResolver;

$this->app->bind(RecipientResolver::class, function ($app) {
    return new \App\Resolvers\MyRecipientResolver();
});
```

The engine will automatically use your implementation.

---

Channels
--------

[](#channels)

The package registers five channels out of the box:

ChannelIdentifierProvider(s)Email`email`Laravel Mail (SES, Mailgun, SMTP, Postmark, etc.)SMS`sms`EgoSMS, Twilio, Africa's TalkingWhatsApp`whatsapp`Meta WhatsApp, Twilio WhatsAppPush`push`Firebase Cloud MessagingIn-App`in_app`Database Notifications---

Providers
---------

[](#providers)

### SMS Providers

[](#sms-providers)

**EgoSMS** (`egosms`):

```
MessageDelivery::sms()
    ->provider('egosms')
    ->to('+250788123456')
    ->text('Hello from EgoSMS')
    ->send();
```

**Twilio SMS** (`twilio-sms`):

```
MessageDelivery::sms()
    ->provider('twilio-sms')
    ->to('+250788123456')
    ->text('Hello from Twilio')
    ->send();
```

**Africa's Talking** (`africas-talking`):

```
MessageDelivery::sms()
    ->provider('africas-talking')
    ->to('+250788123456')
    ->text('Hello from Africa\'s Talking')
    ->send();
```

### WhatsApp Providers

[](#whatsapp-providers)

**Meta WhatsApp** (`meta-whatsapp`):

```
MessageDelivery::whatsapp()
    ->provider('meta-whatsapp')
    ->to('+250788123456')
    ->text('Hello from Meta WhatsApp')
    ->send();
```

**Twilio WhatsApp** (`twilio-whatsapp`):

```
MessageDelivery::whatsapp()
    ->provider('twilio-whatsapp')
    ->to('+250788123456')
    ->text('Hello from Twilio WhatsApp')
    ->send();
```

### Push Providers

[](#push-providers)

**Firebase Cloud Messaging** (`firebase`):

```
MessageDelivery::push()
    ->provider('firebase')
    ->to('device-token')
    ->title('New Update')
    ->text('Your app has been updated')
    ->with(['click_action' => 'OPEN_ACTIVITY'])
    ->send();
```

### Email Providers

[](#email-providers)

**Laravel Mail** (`laravel-mail`):

```
MessageDelivery::email()
    ->provider('laravel-mail')
    ->to('user@example.com')
    ->subject('Welcome')
    ->text('Thank you for registering')
    ->send();
```

The Laravel Mail provider supports any mailer configured in `config/mail.php` (SES, Mailgun, Postmark, SMTP, Log, etc.).

### In-App Provider

[](#in-app-provider)

**Database Notifications** (`database-notifications`):

```
MessageDelivery::inApp()
    ->provider('database-notifications')
    ->to(['notifiable_type' => 'App\Models\User', 'notifiable_id' => 1])
    ->title('New Message')
    ->text('You have a new notification')
    ->send();
```

Recipients can be specified as:

- Associative array with `notifiable_type` and `notifiable_id` keys
- Simple string ID (uses configured default notifiable model)

---

Provider Definitions
--------------------

[](#provider-definitions)

Provider definitions expose configuration fields for admin UIs:

```
use SchoolPalm\MessageDelivery\Facades\MessageDelivery;

// Get a specific definition
$definition = MessageDelivery::definition('twilio-sms');
$fields = $definition->configurationFields();

// Get all definitions
$all = MessageDelivery::definitions();

// Get definitions for a channel
$smsProviders = MessageDelivery::providers('sms');
```

---

Provider Registry
-----------------

[](#provider-registry)

The provider registry manages the lifecycle of provider factories:

```
use SchoolPalm\MessageDelivery\Registry\ProviderRegistry;

$registry = app(ProviderRegistry::class);
$factory = $registry->resolve('sms', 'egosms');
$provider = $factory->create($config);
```

---

Delivery Tracking
-----------------

[](#delivery-tracking)

When enabled, the package records delivery lifecycle events:

```
// config/message-delivery.php
'delivery_tracking' => true,
```

Each delivery goes through statuses:

- `queued` → `processing` → `sent` → `delivered` / `failed`

Data is stored in the `message_deliveries` table and operational logs are written via `AppLogger`.

---

Events
------

[](#events)

EventDescription`MessageSending`Dispatched before a message is sent`MessageSent`Dispatched after a message is sent successfully`MessageFailed`Dispatched when a message fails`DeliveryReceiptReceived`Dispatched when a delivery receipt is received---

Testing
-------

[](#testing)

### Running Tests

[](#running-tests)

```
composer test
```

This runs all 225+ tests (712+ assertions) covering:

- Each channel and provider
- Delivery tracking lifecycle
- Provider resolution and configuration
- Failure handling and timeouts
- Metadata handling
- Multi-channel message building
- Notification Engine dispatch
- Resolver resolution and replacement
- Default (Null) resolver behavior
- Queue options
- Context propagation

### Writing Tests

[](#writing-tests)

```
php vendor/bin/pest --filter="Notification Engine"
php vendor/bin/pest --filter="SMS|Push"
```

---

Publishing
----------

[](#publishing)

### Config

[](#config)

```
php artisan vendor:publish --tag=message-delivery-config
```

### Migrations

[](#migrations)

```
php artisan vendor:publish --tag=message-delivery-migrations
php artisan migrate
```

---

License
-------

[](#license)

MIT License. See [LICENSE](LICENSE) for more information.

###  Health Score

39

—

LowBetter than 84% of packages

Maintenance100

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity45

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

0d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/47620945?v=4)[Mugabo Hassan](/maintainers/codeparl)[@codeparl](https://github.com/codeparl)

---

Top Contributors

[![codeparl](https://avatars.githubusercontent.com/u/47620945?v=4)](https://github.com/codeparl "codeparl (9 commits)")

---

Tags

messagelaravelpushemailsmsprovidersmessagingwhatsappdeliveryschoolpalm

###  Code Quality

TestsPest

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/schoolpalm-message-delivery/health.svg)

```
[![Health](https://phpackages.com/badges/schoolpalm-message-delivery/health.svg)](https://phpackages.com/packages/schoolpalm-message-delivery)
```

###  Alternatives

[illuminate/notifications

The Illuminate Notifications package.

483.1M1.2k](/packages/illuminate-notifications)[laravel/horizon

Dashboard and code-driven configuration for Laravel queues.

4.2k99.8M338](/packages/laravel-horizon)[propaganistas/laravel-disposable-email

Disposable email validator

6023.2M7](/packages/propaganistas-laravel-disposable-email)[jurager/teams

Laravel package to manage team functionality and operate with user permissions.

23723.3k](/packages/jurager-teams)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
