gnello/laravel-mattermost-driver
A Laravel notification driver for Mattermost that lets your app send notifications to Mattermost channels through incoming webhooks. Configure a webhook URL and use a simple channel class to deliver alerts, updates, and team messages.
Install the package with Composer:
composer require gnello/laravel-mattermost-driver
Laravel’s package discovery registers the service provider and the Mattermost facade automatically on 5.5+. On older versions, add them to config/app.php.
Publish the config and inspect it first — it is the single place that decides whether you get webhook mode or API mode:
php artisan vendor:publish --tag=config
Look at config/mattermost.php. You will typically set one of:
MATTERMOST_WEBHOOK — an incoming webhook URL (simplest, no auth, no server-side permissions).MATTERMOST_URL + MATTERMOST_LOGIN / MATTERMOST_PASSWORD, or MATTERMOST_TOKEN — full API mode, which lets you target channels and users programmatically.First use case — fire a smoke test from php artisan tinker:
use Gnello\LaravelMattermostDriver\Facades\Mattermost;
Mattermost::message('Hello from Laravel 👋');
If that lands in your configured channel, you have a working baseline. If it throws, the failure is almost always config: bad webhook URL, wrong server URL, or credentials rejected by the API.
Then wrap it in something real: a deploy-complete ping from a DeployCommand, a TicketCreated notification, or a daily digest command. The package is a thin transport; it does not give you opinionated notifications, so pick your first integration point deliberately.
Webhook vs API mode — choose per use case.
Static channels, dynamic content (webhook pattern):
Mattermost::message(sprintf(
"**Deploy #%s** → `production`\nCommit: `%s`\nBy: %s",
$deployment->id,
$deployment->commit,
$deployment->user->name,
));
Dynamic channel routing (API pattern). Resolve or look up the channel ID once, cache it, then post. Channel names are not stable inputs — the driver ultimately expects an ID in API mode:
$channelId = Cache::remember("mattermost:channel:{$project->slug}", 3600, function () use ($project) {
return Mattermost::channel($project->mattermost_channel)->getId();
});
Mattermost::channel($channelId)->message($body);
Wrap it in a small application service. Do not sprinkle Mattermost:: calls across controllers. A single MattermostNotifier class gives you one place to handle markdown escaping, retries, and channel resolution:
final class MattermostNotifier
{
public function send(string $channelName, string $text): void
{
try {
Mattermost::channel($channelName)->message($text);
} catch (\Throwable $e) {
Log::warning('Mattermost delivery failed', ['e' => $e->getMessage()]);
}
}
}
Queue the send. Mattermost (or the network between you and it) will occasionally time out. Pushing the call onto a queue keeps user-facing requests fast and isolates failures from your HTTP response path:
dispatch(new SendMattermostMessage($channel, $text))->onQueue('notifications');
Custom Notification channel. If you already use Laravel notifications, implement a MattermostChannel and map toMattermost($notifiable) to the driver call. This keeps the package at the edge and lets notifications be ShouldQueue-ed and tested with Notification::fake().
Exception and lifecycle hooks. Reporting uncaught production exceptions to a #alerts channel is a natural fit:
// AppServiceProvider::boot()
$this->app->make(ExceptionHandler::class)->reportable(function (\Throwable $e) {
if ($e instanceof \Illuminate\Auth\AuthenticationException) return;
rescue(fn () => (new MattermostNotifier)->send('alerts', "🔥 " . get_class($e)));
});
Debounce or rate-limit this aggressively — an error loop will hammer Mattermost.
Multi-tenant / multi-webhook. The facade is a singleton bound to one configuration. If you need several Mattermost servers or webhooks, bypass the facade and construct the underlying Gnello\Mattermost\Driver directly inside your service with per-tenant config, leaving the facade for the “default” workspace.
tinker, failed in Horizon” symptoms.config:cache will freeze your credentials. Any env() values are resolved at cache time. Rotate tokens by deploying, not by editing .env on the box, and remember php artisan config:clear when debugging locally.$tries/backoff, set an application-level timeout, and always catch — a chat notification should never break a deploy or a payment flow.HTTP_PROXY/HTTPS_PROXY env), not by disabling verification globally in the app. See the driver’s issue tracker for how it exposes Guzzle options — this is a common friction point given the package’s low maintenance activity.Mattermost is a facade, Mattermost::shouldReceive('message')->once() works in feature tests. For anything integration-shaped (channel ID lookups, error handling), mock your own MattermostNotifier instead — that keeps tests independent of the third-party driver’s exact signature.gnello/php-mattermost-driver and the two do not always move together. When you upgrade either, re-run your smoke test — method names, argument order, and the shape returned by channel/team lookups have changed across versions.Http facade — you will get better typing, testing, and timeout control.How can I help you explore Laravel packages today?