g-giani / notifier
Channel-agnostic notification dispatcher for PHP. Ships with Email, Signal, ntfy, Slack, Discord, Mattermost, Telegram, Gotify and generic-webhook channels; extensible via a simple ChannelInterface.
Requires
- php: ^8.2
- guzzlehttp/guzzle: ^7.8
- psr/log: ^3.0
- symfony/mailer: ^6.4 || ^7.0
Requires (Dev)
- phpstan/phpstan: ^2.0
- phpunit/phpunit: ^11.0
README
A channel-agnostic notification dispatcher for PHP. Build a Message, hand it
to a Notifier, and it fans out to every configured channel (email, Signal,
and any other you implement). A failing channel is isolated — subsequent
channels still run.
Install
composer require g-giani/notifier
Requires PHP 8.2+.
Quick start
use GGiani\Notifier\{Notifier, Message, Severity}; use GGiani\Notifier\Channel\{EmailChannel, SignalChannel}; use Symfony\Component\Mailer\Mailer; use Symfony\Component\Mailer\Transport; use GuzzleHttp\Client; $email = new EmailChannel( mailer: new Mailer(Transport::fromDsn('smtp://user:pass@smtp.example.com:587')), from: 'alerts@example.com', to: ['ops@example.com'], subjectPrefix: '[Monitor]', ); $signal = new SignalChannel( http: new Client(['base_uri' => 'http://localhost:8080/']), sender: '+4915112345678', recipients: ['+4915187654321'], ); $notifier = new Notifier($email, $signal); $failures = $notifier->notify(new Message( title: 'Provider sync failed', body: 'Provider.com returned no records for 3 consecutive runs.', severity: Severity::Critical, context: ['provider_id' => 117, 'process_id' => '5dhxl36s'], )); // $failures is a list<ChannelException> — empty when everything went through.
Channels
| Channel | Dependency | Notes |
|---|---|---|
EmailChannel |
symfony/mailer |
Accepts any Symfony DSN (SMTP, SES, Mailgun, …) |
SignalChannel |
HTTP | Targets signal-cli-rest-api |
NtfyChannel |
HTTP | Targets an ntfy server (self-hosted or ntfy.sh) |
SlackChannel |
HTTP | Slack Incoming Webhook |
DiscordChannel |
HTTP | Discord Webhook (rich embeds) |
MattermostChannel |
HTTP | Mattermost Incoming Webhook |
TelegramChannel |
HTTP | Telegram Bot API (sendMessage) |
GotifyChannel |
HTTP | Self-hosted Gotify |
GenericWebhookChannel |
HTTP | POST JSON payload to any URL |
NullChannel |
— | For tests / dry-run |
Implement GGiani\Notifier\Channel\ChannelInterface to add your own
(Telegram, Slack, WhatsApp, webhook, …). Throw ChannelException on failure
to let the Notifier continue with the remaining channels.
Error handling
Notifier::notify() never throws — it returns the list of ChannelExceptions
from channels that failed, so the caller can decide what to do (log, retry,
escalate). If you want a logger wired in, call ->withLogger($psrLogger) —
failures are then also logged at error level.
License
MIT