Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Exception Mail Laravel Package

tmsllc/laravel-exception-mail

Laravel package that emails exception details straight to your inbox so you can monitor production errors without a third-party service. Simple configuration integrates with Laravel's existing exception handler and alerts you the moment something breaks.

View on GitHub
Deep Wiki
Context7

Getting Started

laravel-exception-mail pipes unhandled exceptions out through Laravel's mail layer, so you get an inbox notification instead of (or alongside) a log line. Version 1.0.1 is a compatibility patch that adds Laravel 11 support — no new features or breaking changes — so if you are already on 1.0.0 with Laravel 10, upgrading is a no-op; if you are on Laravel 11, 1.0.1 is the first version you can install.

composer require tmsllc/laravel-exception-mail:^1.0.1
php artisan vendor:publish --provider="Tmsllc\ExceptionMail\ExceptionMailServiceProvider"

Laravel 11 auto-discovers the service provider, so there is nothing to register in bootstrap/providers.php. Before wiring anything up:

  1. Open the published config (config/exception-mail.php or similar) and read every key — recipients, enabled, environment gating, and any throttling/deduplication settings are the four things you actually care about.
  2. Read the service provider to see where it hooks in. In Laravel 11 the default App\Exceptions\Handler is gone and reporting is configured through bootstrap/app.php → ->withExceptions(...). Confirm the package listens on the container's exception handler / reportable pipeline rather than expecting an app-level Handler class you no longer have.
  3. Set recipients via env ([email protected]) rather than hardcoding addresses in config, so staging and production can diverge.

First use case: you have a production app with no APM and no Sentry budget. You want a mail when a 500 fires, with the exception class, message, file:line, and a trimmed stack trace. Install, set recipients, force an exception on a staging box, confirm the mail arrives — done in ten minutes.

Implementation Patterns

Environment-gate it, always. You do not want a mail per exception on every developer's machine. Either toggle the package's enabled flag from APP_ENV, or rely on Laravel's own gating:

// config/exception-mail.php
'enabled' => app()->environment(['production', 'staging']),

Queue the mail. Sending synchronously from inside the exception handler blocks the response and, on a slow SMTP server, turns a 500 into a 30-second 500. Push the mailable onto the queue and make sure a queue worker is actually running — a queued alert with no worker is silently the same as no alert.

Throttle by fingerprint, not by time. The naive "at most one mail per minute" config still lets a loop in a hot endpoint send one mail per minute forever. Prefer packages that dedupe on a fingerprint (exception class + file + line) or add your own RateLimiter key in a wrapper.

Prune the noise list. Validation, auth, and 404s are not incidents:

// bootstrap/app.php (Laravel 11)
->withExceptions(function (Exceptions $exceptions) {
    $exceptions->dontReport([
        \Illuminate\Validation\ValidationException::class,
        \Illuminate\Auth\AuthenticationException::class,
        \Symfony\Component\HttpKernel\Exception\NotFoundHttpException::class,
    ]);
})

dontReport runs before the package's hook, so this is the cheapest place to suppress — no package config needed.

Wrap the send in a guard. If the mail transport throws inside the exception handler you get a nested exception and often a blank response. If the package does not already do this, decorate it:

try {
    Mail::to(config('exception-mail.to'))->queue(new ExceptionOccurred($e));
} catch (\Throwable $mailFailure) {
    Log::error('exception-mail: failed to send alert', ['original' => $e, 'mail' => $mailFailure]);
}

Test it with Mail::fake(). In a feature test, hit an endpoint that throws and assert the mailable was queued — that is the only way to know the package is wired into your handler chain after a Laravel upgrade reshuffles bootstrap/app.php.

Gotchas and Tips

  • The Laravel 11 handler reshape is the main risk here. 1.0.1 exists precisely because the previous release assumed the old exception-handler shape. If you upgrade to Laravel 11, re-run your forced-exception smoke test rather than trusting the changelog; framework-compat patches on small packages are frequently "it boots" rather than "it reports."
  • Recursion. Any package that mails from the exception handler must not throw from within itself. If you see a stack overflow or a Maximum function nesting level in the logs while testing, that is the failure mode — guard the send.
  • MAIL_MAILER=log in production is the classic silent-alert outage. Assert on MAIL_MAILER (and a working From address — SES/SendGrid reject unverified senders) at deploy time, or you will discover it during the incident.
  • Bootstrap-phase failures never reach the handler. Syntax errors in a service provider, missing env vars, DB connection failures during boot — none of these produce a mail. Exception mail is not uptime monitoring; pair it with an external check.
  • Stack traces contain secrets. Request bodies, headers, and env values leak into traces. Confirm the package truncates or redacts, and never point it at a public mailing list.
  • Version pinning: 1.0.0 for Laravel ≤10, ^1.0.1 for Laravel 11. Check the composer.json illuminate/* constraints before upgrading a Laravel 10 app — a patch bump that widens a constraint usually still allows 10, but verify rather than assume.
  • Extension points to look for if the defaults are too coarse: a custom Mailable class (swap in your own Blade view and subject line), a formatter/transformer for the exception payload, and the throttle/shouldReport callback. These are the seams to use before forking.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin