PHPackages                             shaffe/laravel-mail-log-channel - 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. [Logging &amp; Monitoring](/categories/logging)
4. /
5. shaffe/laravel-mail-log-channel

ActiveLibrary[Logging &amp; Monitoring](/categories/logging)

shaffe/laravel-mail-log-channel
===============================

A package to support logging via email in Laravel

v3.2.0(1mo ago)1398.2k↓26.8%1MITPHPPHP ^8.1

Since Sep 4Pushed 1mo ago2 watchersCompare

[ Source](https://github.com/shaffe-fr/laravel-mail-log-channel)[ Packagist](https://packagist.org/packages/shaffe/laravel-mail-log-channel)[ Docs](https://github.com/shaffe-fr/laravel-mail-log-channel)[ RSS](/packages/shaffe-laravel-mail-log-channel/feed)WikiDiscussions master Synced 2w ago

READMEChangelog (9)Dependencies (27)Versions (20)Used By (0)

Laravel Mail Log Channel
========================

[](#laravel-mail-log-channel)

[![Latest Stable Version](https://camo.githubusercontent.com/685a3aa0845bf4c743de0dd34cbe858ae9c79f107627b025916fe59c00dfadf0/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f7368616666652d66722f6c61726176656c2d6d61696c2d6c6f672d6368616e6e656c2e737667)](https://packagist.org/packages/shaffe/laravel-mail-log-channel)[![Total Downloads](https://camo.githubusercontent.com/2a43a57a83ea839ee5b7850c08ea431bc18288e1dbe50c3defd6b57d376a9c1e/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f7368616666652f6c61726176656c2d6d61696c2d6c6f672d6368616e6e656c2e737667)](https://packagist.org/packages/shaffe/laravel-mail-log-channel)[![License: MIT](https://camo.githubusercontent.com/fdf2982b9f5d7489dcf44570e714e3a15fce6253e0cc6b5aa61a075aac2ff71b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d79656c6c6f772e737667)](https://opensource.org/licenses/MIT)

Receive detailed error emails from your Laravel application. Plug it into Laravel's logging stack and get notified when things break — with full context, stack trace, SQL queries, and more.

📸 Example email[![screenshot](docs/screenshot.png)](docs/screenshot.png)

Features
--------

[](#features)

- **Rich error emails** — structured HTML with clear, readable sections
- **Execution context** — HTTP request (method, URL, route, controller, authenticated user), Artisan command, or Queue job
- **Environment info** — app environment, PHP/Laravel versions, server hostname, peak memory, execution time
- **Code snippet** — source code around the error line, highlighted
- **Smart stack trace** — application frames expanded, vendor frames collapsed
- **SQL queries** — last 10 queries with bindings and execution time
- **Request payload** — optional, redacted capture of the incoming request body and uploaded files
- **Throttling** — identical errors are deduplicated to avoid inbox flooding
- **Level-based routing** — send to different recipients based on log level, suppress specific levels
- **Editor links** — clickable file paths that open in your IDE
- **Previous exceptions** — full chain display
- **Additional context** — from `Exception::context()` and log record context
- **Test command** — `php artisan mail-log:test` to verify your setup

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

[](#installation)

```
composer require shaffe/laravel-mail-log-channel
```

The package auto-registers its service provider.

### Compatibility

[](#compatibility)

LaravelPackage10, 11, 12, 13^3.05.6 – 13^2.05.6^1.0Quick Start
-----------

[](#quick-start)

Add a `mail` channel to `config/logging.php` and include it in your stack:

```
'channels' => [
    'stack' => [
        'driver' => 'stack',
        'channels' => ['daily', 'mail'],
    ],

    'mail' => [
        'driver' => 'mail',
        'level' => env('LOG_MAIL_LEVEL', 'error'),
        'to' => env('LOG_MAIL_ADDRESS'),
    ],
],
```

Add the recipient to your `.env`:

```
LOG_MAIL_ADDRESS=errors@yourapp.com
```

That's it. Unhandled exceptions at or above the configured level will now arrive in your inbox.

Configuration Reference
-----------------------

[](#configuration-reference)

All options with their defaults:

```
'mail' => [
    'driver' => 'mail',
    'level' => 'error',

    // Recipients (see formats below)
    'to' => env('LOG_MAIL_ADDRESS'),

    // Sender (defaults to mail.from config)
    'from' => [
        'address' => env('LOG_MAIL_FROM_ADDRESS'),
        'name' => env('LOG_MAIL_FROM_NAME', 'Errors'),
    ],

    // Subject line pattern
    // Placeholders: %level_name%, %message%, %env%, %context%, %app_name%, %channel%, %datetime%
    'subject_format' => '[%level_name%] [%env%] %context% — %message%',

    // Throttle identical errors (seconds). Set to 0 or false to disable.
    'throttle' => 60,

    // Cache store for throttle state (null = default store)
    'throttle_cache_store' => null,

    // Include last N SQL queries in the email
    'log_queries' => true,

    // Maximum number of SQL queries to include (default: 10)
    'query_limit' => 10,

    // Include the incoming request payload (opt-in, off by default).
    // Sensitive fields (passwords, tokens, card data) are always redacted.
    'log_request_payload' => false,

    // Extra field names to redact, merged with the built-in defaults.
    'redact_keys' => [],

    // Truncate scalar values longer than this many characters.
    'payload_max_value_length' => 500,

    // Maximum number of fields kept per array level.
    'payload_max_keys' => 50,

    // Collapse vendor frames in stack trace
    'collapse_vendor_frames' => true,

    // Custom Mailable class (receives $content and $records)
    // 'mailable' => \App\Mail\CustomLogMail::class,
],
```

### Recipient Formats

[](#recipient-formats)

The `to` option accepts several formats:

```
// Simple string
'to' => 'dev@example.com',

// Multiple addresses
'to' => ['dev@example.com', 'ops@example.com'],

// With names
'to' => ['dev@example.com' => 'Dev Team'],

// Structured
'to' => [
    ['address' => 'dev@example.com', 'name' => 'Dev Team'],
    ['address' => 'ops@example.com', 'name' => 'Ops'],
],
```

### Level-Based Routing

[](#level-based-routing)

Route error emails to different recipients based on log level. Levels without a configured recipient (and no `default`) won't send any email.

```
'to' => [
    'default' => 'dev@example.com',       // fallback for levels not listed
    'critical' => 'oncall@example.com',   // critical & emergency → on-call
    'emergency' => [
        ['address' => 'oncall@example.com', 'name' => 'On-Call'],
        ['address' => 'cto@example.com', 'name' => 'CTO'],
    ],
    'debug' => null,                       // explicitly suppress debug emails
    'info' => '',                          // same — no email for info
],
```

Level keys also accept Monolog `Level` enum values or their numeric equivalents:

```
use Monolog\Level;

'to' => [
    'default' => 'dev@example.com',
    Level::Critical->value => 'oncall@example.com',  // 500
    'warning' => 'dev@example.com',                  // string works too
    Level::Debug->value => null,                     // 100 — suppressed
],
```

**Rules:**

- If a level has recipients → email is sent to those recipients.
- If a level is not listed → falls back to `default`.
- If a level is explicitly set to `null`, `''`, or `false` → no email is sent, even if `default` exists.
- If a level is not listed and there is no `default` → no email is sent.
- This is fully backward-compatible: a plain string or simple array `to` works exactly as before.

Each level value accepts the same formats as the standard `to` option (string, array of strings, named array, structured array).

Throttling
----------

[](#throttling)

Identical errors are automatically deduplicated to prevent inbox flooding. When the same error occurs multiple times within the throttle window, only the first occurrence sends an email.

**Enabled by default** with a 60-second window.

### Fingerprinting

[](#fingerprinting)

Each log record gets a fingerprint to determine uniqueness:

Record typeFingerprint componentsExceptionclass + code + message + file + linePlain messagechannel + level + message### Suppressed Occurrences Counter

[](#suppressed-occurrences-counter)

When an error is throttled and then reappears after the window expires, the next email includes a notice indicating how many times the error has occurred since it first appeared, along with the timestamp of the first occurrence.

For example: *"⚠️ This error has occurred 47 times since 15 Mar 2025 14:30:00 UTC."*

This gives you immediate visibility into the scale of a recurring issue without flooding your inbox.

### Configuration

[](#configuration)

```
// Throttle window in seconds (default: 60)
'throttle' => 60,

// Disable throttling
'throttle' => 0,

// Use a specific cache store (useful for multi-server setups)
'throttle_cache_store' => 'redis',
```

### Good to Know

[](#good-to-know)

- Messages with dynamic content (e.g. `"User 42 not found"`) produce distinct fingerprints — they won't be incorrectly grouped together.
- For multi-server deployments, use a shared cache store (Redis, Memcached) so throttling works across all instances.

SQL Query Logging
-----------------

[](#sql-query-logging)

The last N SQL queries leading up to the error are included in the email, with bindings and execution time. This helps understand the database state at the time of failure.

```
// Number of queries to keep (default: 10)
'query_limit' => 10,

// Disable SQL query logging entirely
'log_queries' => false,
```

Warning

Query **bindings are shown as-is and are not redacted**. This is intentional: the whole point of query logging is to reproduce the failing query, and masking the values would defeat it. As a result, a query such as `insert into users (email, password) values (?, ?)` will expose its bound values in the email.

Treat error emails as **confidential**: send them to a controlled, access-restricted inbox, and set `'log_queries' => false` if your threat model can't accommodate this. The same applies to the request payload and context sections — redaction there is best-effort on **known** field names only.

Request Payload
---------------

[](#request-payload)

Capture the incoming request body in the error email to help reproduce HTTP failures. **Disabled by default** because request data is sensitive.

Enable it per channel:

```
'log_request_payload' => true,
```

The payload is read with Laravel's `request->all()`, so it covers both form (`application/x-www-form-urlencoded`, `multipart/form-data`) and JSON requests. Nothing is captured on the console or when no request is available.

### Redaction

[](#redaction)

Sensitive fields are **always** redacted, recursively and case-insensitively. Their keys remain visible as `[REDACTED]` so you can tell which fields were present without seeing their values.

The built-in list covers:

CategoryFieldsAuth / secrets`password`, `password_confirmation`, `current_password`, `new_password`, `secret`, `token`, `_token`, `access_token`, `refresh_token`, `api_key`, `apikey`, `api_token`, `authorization`, `client_secret`Card / PCI`card_number`, `cardnumber`, `card_no`, `cc_number`, `ccnumber`, `cc_num`, `cvc`, `cvv`, `cvv2`, `cvc2`, `card_cvc`, `card_cvv`, `security_code`, `exp_month`, `exp_year`, `expiry`, `expiration`, `expiration_date`, `exp_date`Stripe`stripe_token`, `stripetoken`, `payment_method`, `payment_intent`, `setup_intent`Braintree / PayPal`payment_method_nonce`, `nonce`Bank details`iban`, `bic`, `account_number`, `routing_number`, `sort_code`Add your own field names — they are **merged** with the defaults, never replacing them:

```
'redact_keys' => ['ssn', 'national_id'],
```

Redacted fields remain visible in the email as `[REDACTED]` so you can see **which** fields were submitted without exposing their values.

### Size limits

[](#size-limits)

To keep emails readable and within SMTP limits, the payload is bounded:

```
// Truncate any scalar value longer than this (characters).
// Truncated values are annotated, e.g. "abc… [1200 chars total]".
'payload_max_value_length' => 500,

// Keep at most this many fields per array level.
// Omitted fields are reported as "+ N more fields omitted".
'payload_max_keys' => 50,
```

### Uploaded files

[](#uploaded-files)

Files are **described, never dumped** — only the original name, MIME type, and size are included. File contents are never read or attached.

Editor Links
------------

[](#editor-links)

File paths in error emails are clickable when `app.editor` is configured. Clicking opens the file at the correct line in your IDE.

```
// config/app.php
'editor' => 'phpstorm',
```

Or via `.env`:

```
APP_EDITOR=phpstorm
```

Examples: `phpstorm`, `vscode`, `vscode-insiders`, `cursor`, `sublime`, `kiro`, `nova`, `idea`.

Custom URL scheme:

```
'editor' => [
    'href' => 'custom://open?file={file}&line={line}',
],
```

Remote path remapping (when server paths differ from local):

```
'editor' => [
    'name' => 'phpstorm',
    'base_path' => '/local/path/to/project',
],
```

Environment Info
----------------

[](#environment-info)

Each error email includes badges showing the application environment, PHP and Laravel versions, server hostname, **peak memory usage**, and **execution time** (time elapsed since `LARAVEL_START`).

This helps identify errors related to resource exhaustion or slow requests at a glance.

Testing Your Configuration
--------------------------

[](#testing-your-configuration)

Verify that your mail log channel is properly configured by sending a test email:

```
php artisan mail-log:test
```

Options:

```
# Test with a specific log level
php artisan mail-log:test --level=critical

# Test a specific channel name
php artisan mail-log:test --channel=mail
```

This sends a fake exception through the configured channel so you can confirm recipients, SMTP settings, and throttle behavior without waiting for a real error.

Upgrading
---------

[](#upgrading)

### v2 → v3

[](#v2--v3)

- Requires PHP 8.1+ and Laravel 10+
- Complete redesign of the email HTML output
- `HtmlFormatter::addRow()` has been removed
- Configuration API is unchanged — no config migration needed

If you extended `HtmlFormatter` or parsed the HTML output, review the new format.

Credits
-------

[](#credits)

This package is a fork of [laravel-log-mailer](https://packagist.org/packages/designmynight/laravel-log-mailer) by Steve Porter.

License
-------

[](#license)

MIT — see [LICENSE](LICENSE).

###  Health Score

60

—

FairBetter than 98% of packages

Maintenance90

Actively maintained with recent releases

Popularity39

Limited adoption so far

Community13

Small or concentrated contributor base

Maturity80

Battle-tested with a long release history

 Bus Factor1

Top contributor holds 94.7% 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 ~168 days

Recently: every ~26 days

Total

18

Last Release

48d ago

Major Versions

v1.0.2 → v2.0.02020-02-19

v2.6.0 → v3.0.02026-03-18

### Community

Maintainers

![](https://www.gravatar.com/avatar/d69542006c81a06197d5a15f1b350392dad178d77eb2a900ba6c043fffedf44e?d=identicon)[shaffe](/maintainers/shaffe)

---

Top Contributors

[![shaffe-fr](https://avatars.githubusercontent.com/u/3834222?v=4)](https://github.com/shaffe-fr "shaffe-fr (54 commits)")[![dev-idsys-mi](https://avatars.githubusercontent.com/u/62592572?v=4)](https://github.com/dev-idsys-mi "dev-idsys-mi (1 commits)")[![jbeales](https://avatars.githubusercontent.com/u/104935?v=4)](https://github.com/jbeales "jbeales (1 commits)")[![u01jmg3](https://avatars.githubusercontent.com/u/1266205?v=4)](https://github.com/u01jmg3 "u01jmg3 (1 commits)")

---

Tags

laravellaravel-logginglaravelloggingmonologlaravel-log-mailerlaravel-mail-log-channelmail channelshaffe

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/shaffe-laravel-mail-log-channel/health.svg)

```
[![Health](https://phpackages.com/badges/shaffe-laravel-mail-log-channel/health.svg)](https://phpackages.com/packages/shaffe-laravel-mail-log-channel)
```

###  Alternatives

[laravel/scout

Laravel Scout provides a driver based solution to searching your Eloquent models.

1.7k57.2M683](/packages/laravel-scout)[flarum/core

Delightfully simple forum software.

211.5M2.5k](/packages/flarum-core)[illuminate/notifications

The Illuminate Notifications package.

483.1M1.2k](/packages/illuminate-notifications)[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9922.4M146](/packages/roots-acorn)[psalm/plugin-laravel

Psalm plugin for Laravel

3345.4M354](/packages/psalm-plugin-laravel)[illuminate/broadcasting

The Illuminate Broadcasting package.

7127.4M237](/packages/illuminate-broadcasting)

PHPackages © 2026

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