PHPackages                             stboris/filament-outbox - 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. stboris/filament-outbox

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

stboris/filament-outbox
=======================

Configurable notification channels (Discord, Slack, Microsoft Teams, generic webhook) for Laravel, with a Filament v5 admin panel on top.

v1.1.0(1mo ago)221MITPHPPHP ^8.3CI failing

Since Jul 11Pushed 3w agoCompare

[ Source](https://github.com/stboris/filament-outbox)[ Packagist](https://packagist.org/packages/stboris/filament-outbox)[ RSS](/packages/stboris-filament-outbox/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (14)Versions (3)Used By (0)

Filament Outbox
===============

[](#filament-outbox)

Configurable notification channels for Laravel - **Discord**, **Slack**, **Microsoft Teams**, and **generic signed webhooks** - built on Laravel's native notification system. No new APIs to learn: write a normal `Notification` class, return a message object, done.

Requirements
------------

[](#requirements)

- PHP 8.3+
- Laravel 13

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

[](#installation)

```
composer require stboris/filament-outbox
```

Optionally publish the config:

```
php artisan vendor:publish --tag="filament-outbox-config"
```

Usage
-----

[](#usage)

### Discord

[](#discord)

```
use Stboris\FilamentOutbox\Messages\DiscordMessage;
use Stboris\FilamentOutbox\Messages\DiscordEmbed;

class TradeOpened extends Notification
{
    public function via(object $notifiable): array
    {
        return ['discord'];
    }

    public function toDiscord(object $notifiable): DiscordMessage
    {
        return DiscordMessage::make()
            ->username('Trading Bot')
            ->embed(fn (DiscordEmbed $embed) => $embed
                ->title('LONG opened - BTCUSDT')
                ->color('#2A78D6')
                ->fields([
                    'Entry price' => '$100.00',
                    'Invested' => '$500.00',
                ])
                ->timestamp());
    }
}
```

The webhook URL is resolved in this order:

1. `->to($url)` on the message
2. `routeNotificationForDiscord()` on the notifiable
3. `config('filament-outbox.discord.webhook_url')` (env `OUTBOX_DISCORD_WEBHOOK_URL`)

### Slack (incoming webhook)

[](#slack-incoming-webhook)

```
use Stboris\FilamentOutbox\Messages\SlackMessage;

public function via(object $notifiable): array
{
    // The 'slack' alias is only claimed when laravel/slack-notification-channel
    // is not installed; the class name always works.
    return [\Stboris\FilamentOutbox\Channels\SlackChannel::class];
}

public function toSlack(object $notifiable): SlackMessage
{
    return SlackMessage::make('Trade closed - +$42.00')
        ->section('*LONG closed - BTCUSDT*');
}
```

### Microsoft Teams (Workflows webhook)

[](#microsoft-teams-workflows-webhook)

Sends [Adaptive Cards](https://adaptivecards.io) to the webhook URL of a Power Automate workflow (the *"When a Teams webhook request is received"* trigger) - the mechanism that replaces the retired Office 365 Connector webhooks.

```
use Stboris\FilamentOutbox\Messages\TeamsMessage;

public function via(object $notifiable): array
{
    return ['teams'];
}

public function toTeams(object $notifiable): TeamsMessage
{
    return TeamsMessage::make('Deploy finished without errors.')
        ->title('Deployment')
        ->color('good')
        ->facts(['Version' => 'v2.14.0', 'Environment' => 'production']);
}
```

`->block([...])` appends raw Adaptive Card elements; `->card([...])` replaces the generated card entirely.

### Generic webhook

[](#generic-webhook)

```
use Stboris\FilamentOutbox\Messages\WebhookMessage;

public function via(object $notifiable): array
{
    return ['webhook'];
}

public function toWebhook(object $notifiable): WebhookMessage
{
    return WebhookMessage::make([
        'event' => 'trade.closed',
        'symbol' => 'BTCUSDT',
        'pnl' => 42.0,
    ])->header('X-Source', 'my-app');
}
```

When a secret is configured (`OUTBOX_WEBHOOK_SECRET` or `->secret(...)` on the message), the raw JSON body is signed with HMAC-SHA256 and the hex digest is sent in the `X-Outbox-Signature` header, so receivers can verify authenticity:

```
hash_equals($request->header('X-Outbox-Signature'), hash_hmac('sha256', $request->getContent(), $secret));
```

Testing an endpoint
-------------------

[](#testing-an-endpoint)

Verify any endpoint from the command line before relying on it:

```
php artisan outbox:test discord --to="https://discord.com/api/webhooks/..."
php artisan outbox:test slack                     # uses the configured default URL
php artisan outbox:test teams --to="https://.../workflows/.../invoke"
php artisan outbox:test webhook --message="Custom check"
```

Resilient sending
-----------------

[](#resilient-sending)

Transient failures - connection errors, HTTP 429 rate limits, and 5xx responses - are automatically retried with exponential backoff (2 attempts by default, configurable via `http.retry` in the config). Permanent client errors (4xx) fail immediately with a descriptive `CouldNotSendNotification` exception.

Testing
-------

[](#testing)

```
composer test
```

License
-------

[](#license)

MIT.

###  Health Score

43

—

FairBetter than 89% of packages

Maintenance93

Actively maintained with recent releases

Popularity12

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity50

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

Every ~8 days

Total

2

Last Release

42d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/3891cb1553b2a3e264c172a8ab016291be67c863bd191010a6ba7294517b8fe4?d=identicon)[stboris](/maintainers/stboris)

---

Top Contributors

[![stboris](https://avatars.githubusercontent.com/u/48769916?v=4)](https://github.com/stboris "stboris (24 commits)")

---

Tags

discordfilamentlaravelnotificationsslackwebhooklaravelnotificationsslackwebhookfilamentdiscordmicrosoft-teams

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/stboris-filament-outbox/health.svg)

```
[![Health](https://phpackages.com/badges/stboris-filament-outbox/health.svg)](https://phpackages.com/packages/stboris-filament-outbox)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3365.5M359](/packages/psalm-plugin-laravel)[defstudio/telegraph

A laravel facade to interact with Telegram Bots

818355.4k3](/packages/defstudio-telegraph)[spatie/laravel-health

Monitor the health of a Laravel application

89313.5M195](/packages/spatie-laravel-health)[laravel/cashier

Laravel Cashier provides an expressive, fluent interface to Stripe's subscription billing services.

2.5k31.8M166](/packages/laravel-cashier)[laravel/mcp

Rapidly build MCP servers for your Laravel applications.

80732.6M270](/packages/laravel-mcp)[laravel/socialite

Laravel wrapper around OAuth 1 &amp; OAuth 2 libraries.

5.7k118.2M1.0k](/packages/laravel-socialite)

PHPackages © 2026

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