PHPackages                             jeffersongoncalves/laravel-mail - 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. jeffersongoncalves/laravel-mail

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

jeffersongoncalves/laravel-mail
===============================

Complete email management for Laravel: logging, database templates with translation, delivery tracking via webhooks (SES, SendGrid, Postmark, Mailgun, Resend), preview, resend, and analytics.

1.3.0(1mo ago)641↑2900%1MITPHPPHP ^8.2CI passing

Since Apr 6Pushed 1mo ago1 watchersCompare

[ Source](https://github.com/jeffersongoncalves/laravel-mail)[ Packagist](https://packagist.org/packages/jeffersongoncalves/laravel-mail)[ Docs](https://github.com/jeffersongoncalves/laravel-mail)[ GitHub Sponsors](https://github.com/jeffersongoncalves)[ RSS](/packages/jeffersongoncalves-laravel-mail/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (4)Dependencies (11)Versions (5)Used By (1)

[![Laravel Mail](https://raw.githubusercontent.com/jeffersongoncalves/laravel-mail/master/art/jeffersongoncalves-laravel-mail.jpg)](https://raw.githubusercontent.com/jeffersongoncalves/laravel-mail/master/art/jeffersongoncalves-laravel-mail.jpg)

Laravel Mail
============

[](#laravel-mail)

[![Latest Version on Packagist](https://camo.githubusercontent.com/89e9942a510e659b6b638f64614086e03dbe27b7422ad2997d1eb8d63547db16/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6a6566666572736f6e676f6e63616c7665732f6c61726176656c2d6d61696c2e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/jeffersongoncalves/laravel-mail)[![GitHub Tests Action Status](https://camo.githubusercontent.com/ba971339360404730fef9409566b0de37720f4dbd31665edd9c6165a048fa3bb/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6a6566666572736f6e676f6e63616c7665732f6c61726176656c2d6d61696c2f72756e2d74657374732e796d6c3f6272616e63683d6d6173746572266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/jeffersongoncalves/laravel-mail/actions?query=workflow%3Arun-tests+branch%3Amaster)[![GitHub Code Style Action Status](https://camo.githubusercontent.com/66a3b2c22aa1d322df71b4ae35a911a63905025d9c1a2dda66982f4c9629cd3b/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6a6566666572736f6e676f6e63616c7665732f6c61726176656c2d6d61696c2f6669782d7068702d636f64652d7374796c652d6973737565732e796d6c3f6272616e63683d6d6173746572266c6162656c3d636f64652532307374796c65267374796c653d666c61742d737175617265)](https://github.com/jeffersongoncalves/laravel-mail/actions?query=workflow%3A%22Fix+PHP+code+styling%22+branch%3Amaster)[![Total Downloads](https://camo.githubusercontent.com/76f76523b6a508ae04747928798bf63957c40eaa3b5eda4efd2d4a1f2f0a9b54/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6a6566666572736f6e676f6e63616c7665732f6c61726176656c2d6d61696c2e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/jeffersongoncalves/laravel-mail)

Complete email management for Laravel: logging, database templates with translation (spatie/laravel-translatable), delivery tracking via webhooks (SES, SendGrid, Postmark, Mailgun, Resend), pixel tracking (provider-independent open &amp; click tracking), suppression list, inline CSS, List-Unsubscribe headers, browser preview, statistics, notification channel, retry, attachment storage, and analytics.

Features
--------

[](#features)

- **Email Logging** — Automatically logs all outgoing emails via `MessageSent` event
- **Database Templates** — Store email templates with Blade rendering and multi-locale translation via `spatie/laravel-translatable`
- **Template Versioning** — Automatic version history on every content change
- **Delivery Tracking** — Webhook handlers for 5 providers (SES, SendGrid, Postmark, Mailgun, Resend) with HMAC validation
- **Pixel Tracking** — Provider-independent open and click tracking via injected 1x1 transparent pixel and link rewriting (works with any mailer including plain SMTP)
- **Webhook Idempotency** — Duplicate webhook deliveries are detected and ignored via `provider_event_id`
- **Tracking Events** — Laravel events dispatched on delivery, bounce, complaint, open, click, and deferral
- **Suppression List** — Auto-suppress hard bounces and complaints, block sending to suppressed addresses
- **Inline CSS** — Automatic CSS inlining for email client compatibility (Outlook, Gmail, etc.)
- **List-Unsubscribe Headers** — Gmail/Yahoo compliance with `List-Unsubscribe` and `List-Unsubscribe-Post` headers
- **Browser Preview** — View sent emails and templates in the browser via signed URLs
- **Statistics** — Query helpers for sent, delivered, bounced, opened, clicked counts and daily aggregations
- **Notification Channel** — Send database templates via Laravel Notifications
- **Retry Failed Emails** — Retry failed or soft-bounced emails with max attempts control
- **Resend Emails** — Resend any previously sent email from the log
- **Attachment File Storage** — Optionally store email attachment files to disk (S3, local, etc.)
- **Pruning** — Artisan command to clean up old mail logs with per-status retention policies
- **Polymorphic Association** — Associate mail logs with any model via `HasMailLogs` trait
- **Multi-Tenant** — Optional tenant scoping for all tables
- **Customizable** — Override models, table names, and database connection
- **CLI Commands** — `mail:send-test`, `mail:templates`, `mail:stats`, `mail:prune`, `mail:retry`, `mail:unsuppress`

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

[](#installation)

```
composer require jeffersongoncalves/laravel-mail
```

Publish and run the migrations:

```
php artisan vendor:publish --tag="laravel-mail-migrations"
php artisan migrate
```

Optionally publish the config file:

```
php artisan vendor:publish --tag="laravel-mail-config"
```

Email Logging
-------------

[](#email-logging)

Logging is enabled by default. Every email sent through Laravel's `Mail` facade is automatically logged to the `mail_logs` table.

```
// Just send emails normally — they are logged automatically
Mail::to('user@example.com')->send(new WelcomeMail($user));
```

Each log entry captures: mailer, subject, from/to/cc/bcc/reply-to, HTML body, text body, headers, attachments metadata, and provider message ID.

When using `TemplateMailable`, the `mail_template_id` is automatically associated with the log entry.

### Disable Logging

[](#disable-logging)

```
LARAVEL_MAIL_LOGGING_ENABLED=false
```

### Control What Gets Stored

[](#control-what-gets-stored)

```
LARAVEL_MAIL_STORE_HTML=true
LARAVEL_MAIL_STORE_TEXT=true
```

Database Templates
------------------

[](#database-templates)

Create email templates in the database with multi-locale support via `spatie/laravel-translatable` and Blade rendering.

### Creating a Template

[](#creating-a-template)

```
use JeffersonGoncalves\LaravelMail\Models\MailTemplate;

MailTemplate::create([
    'key' => 'welcome',
    'name' => 'Welcome Email',
    'subject' => ['en' => 'Welcome, {{ $name }}!', 'pt_BR' => 'Bem-vindo, {{ $name }}!'],
    'html_body' => [
        'en' => 'Hello {{ $name }}Welcome to our platform.',
        'pt_BR' => 'Ola {{ $name }}Bem-vindo a nossa plataforma.',
    ],
    'variables' => [
        ['name' => 'name', 'type' => 'string', 'example' => 'John'],
    ],
]);
```

### Using Templates in Mailables

[](#using-templates-in-mailables)

Extend `TemplateMailable` to create mailables that fetch content from the database:

```
use JeffersonGoncalves\LaravelMail\Mail\TemplateMailable;
use Illuminate\Mail\Mailables\Content;

class WelcomeEmail extends TemplateMailable
{
    public function __construct(
        public User $user,
    ) {}

    public function templateKey(): string
    {
        return 'welcome';
    }

    public function templateData(): array
    {
        return ['name' => $this->user->name];
    }

    protected function fallbackSubject(): string
    {
        return 'Welcome!';
    }

    protected function fallbackContent(): Content
    {
        return new Content(
            view: 'emails.welcome',
            with: ['user' => $this->user],
        );
    }
}
```

### Translation API

[](#translation-api)

The `MailTemplate` model uses `spatie/laravel-translatable`. You can access translations via:

```
// Get for current locale
$template->subject; // Returns string for app()->getLocale()

// Get for specific locale
$template->getSubjectForLocale('pt_BR');
$template->getHtmlBodyForLocale('en');
$template->getTextBodyForLocale('es');

// Get all translations
$template->getTranslations('subject'); // ['en' => '...', 'pt_BR' => '...']

// Set translation
$template->setTranslation('subject', 'fr', 'Bienvenue !');
```

### Template Versioning

[](#template-versioning)

Every content change (subject, html\_body, text\_body) automatically creates a version snapshot:

```
$template->update([
    'subject' => ['en' => 'Updated Welcome, {{ $name }}!'],
    'html_body' => ['en' => 'New design for {{ $name }}'],
]);

// Version 2 is automatically created
$template->versions; // Collection of MailTemplateVersion
```

### Template Preview

[](#template-preview)

Preview a template with example data without sending:

```
use JeffersonGoncalves\LaravelMail\Actions\PreviewTemplateAction;

$action = new PreviewTemplateAction();
$preview = $action->execute($template, ['name' => 'Alice'], 'en');

// Returns: ['subject' => '...', 'html' => '...', 'text' => '...']
// HTML is automatically CSS-inlined when templates.inline_css is true
```

### Layouts

[](#layouts)

Wrap template content in a shared layout:

```
// config/laravel-mail.php
'templates' => [
    'default_layout' => '{!! $slot !!}',
],

// Or per template
$template->update(['layout' => '{!! $slot !!}']);
```

Inline CSS
----------

[](#inline-css)

Automatically inlines CSS styles for email client compatibility (Outlook, Gmail, Yahoo, etc.). Uses `tijsverkoyen/css-to-inline-styles` which is already included with Laravel.

```
LARAVEL_MAIL_INLINE_CSS=true  # Enabled by default
```

When enabled, any `` tags in your template HTML will be converted to inline `style` attributes on the corresponding elements. This applies to both `TemplateMailable` sending and `PreviewTemplateAction` rendering.

List-Unsubscribe Headers
------------------------

[](#list-unsubscribe-headers)

Add `List-Unsubscribe` and `List-Unsubscribe-Post` headers for Gmail/Yahoo compliance (required since 2024 for bulk senders).

```
// config/laravel-mail.php
'templates' => [
    'unsubscribe' => [
        'enabled' => true,
        'url' => 'https://yourapp.com/unsubscribe/{email}', // {email} is replaced with recipient
        'mailto' => 'unsubscribe@yourapp.com',
    ],
],
```

When enabled, all emails sent via `TemplateMailable` will include:

- `List-Unsubscribe: , `
- `List-Unsubscribe-Post: List-Unsubscribe=One-Click`

Delivery Tracking via Webhooks
------------------------------

[](#delivery-tracking-via-webhooks)

Track email delivery status in real-time via provider webhooks. Supports: **Amazon SES**, **SendGrid**, **Postmark**, **Mailgun**, and **Resend**.

### Enable Tracking

[](#enable-tracking)

```
LARAVEL_MAIL_TRACKING_ENABLED=true
```

### Configure Provider

[](#configure-provider)

Enable the providers you use in `config/laravel-mail.php`:

```
'tracking' => [
    'enabled' => true,
    'route_prefix' => 'webhooks/mail',

    'providers' => [
        'ses' => [
            'enabled' => true,
        ],
        'sendgrid' => [
            'enabled' => true,
            'signing_secret' => env('LARAVEL_MAIL_SENDGRID_SIGNING_SECRET'),
        ],
        'postmark' => [
            'enabled' => true,
            'username' => env('LARAVEL_MAIL_POSTMARK_WEBHOOK_USERNAME'),
            'password' => env('LARAVEL_MAIL_POSTMARK_WEBHOOK_PASSWORD'),
        ],
        'mailgun' => [
            'enabled' => true,
            'signing_key' => env('LARAVEL_MAIL_MAILGUN_SIGNING_KEY'),
        ],
        'resend' => [
            'enabled' => true,
            'signing_secret' => env('LARAVEL_MAIL_RESEND_SIGNING_SECRET'),
        ],
    ],
],
```

### Webhook URLs

[](#webhook-urls)

Configure these URLs in your email provider's dashboard:

ProviderWebhook URLAmazon SES`https://yourapp.com/webhooks/mail/ses`SendGrid`https://yourapp.com/webhooks/mail/sendgrid`Postmark`https://yourapp.com/webhooks/mail/postmark`Mailgun`https://yourapp.com/webhooks/mail/mailgun`Resend`https://yourapp.com/webhooks/mail/resend`### Tracked Events

[](#tracked-events)

EventDescriptionUpdates StatusLaravel Event`delivered`Email successfully delivered`sent` -&gt; `delivered``MailDelivered``bounced`Email bounced (hard/soft)-&gt; `bounced``MailBounced``complained`Recipient marked as spam-&gt; `complained``MailComplained``opened`Email was openedNo`MailOpened``clicked`Link was clickedNo`MailClicked``deferred`Delivery was delayedNo`MailDeferred`### Webhook Idempotency

[](#webhook-idempotency)

Duplicate webhook deliveries from providers are automatically detected and ignored. Each webhook handler extracts a unique `provider_event_id` from the payload (e.g., SNS `MessageId` for SES, `sg_event_id` for SendGrid, `svix-id` for Resend). If an event with the same ID already exists, it is skipped — no duplicate tracking events, no duplicate Laravel events dispatched.

### Listening to Tracking Events

[](#listening-to-tracking-events)

React to delivery events in your application:

```
use JeffersonGoncalves\LaravelMail\Events\MailBounced;
use JeffersonGoncalves\LaravelMail\Events\MailComplained;

// In a listener or EventServiceProvider
Event::listen(MailBounced::class, function (MailBounced $event) {
    // $event->mailLog — the MailLog model
    // $event->trackingEvent — the MailTrackingEvent model
    Log::warning("Email bounced: {$event->trackingEvent->recipient}");
});

Event::listen(MailComplained::class, function (MailComplained $event) {
    // Disable the user's account, send alert, etc.
});
```

### Signature Validation

[](#signature-validation)

Each provider uses its own authentication method:

- **SES** — SNS certificate URL verification
- **SendGrid** — Timestamp-based validation (ECDSA)
- **Postmark** — HTTP Basic Auth
- **Mailgun** — HMAC SHA256 signature
- **Resend** — Svix HMAC SHA256 signature

When no signing secret is configured, validation is skipped (useful for development).

Pixel Tracking (Provider-Independent)
-------------------------------------

[](#pixel-tracking-provider-independent)

Track email opens and clicks without relying on email provider webhooks. Works with any mailer including plain SMTP. The package injects a 1x1 transparent GIF pixel for open tracking and rewrites links for click tracking.

### Enable Pixel Tracking

[](#enable-pixel-tracking)

```
LARAVEL_MAIL_PIXEL_OPEN_TRACKING=true
LARAVEL_MAIL_PIXEL_CLICK_TRACKING=true
```

```
// config/laravel-mail.php
'tracking' => [
    'pixel' => [
        'open_tracking' => true,   // Inject tracking pixel in emails
        'click_tracking' => true,  // Rewrite links for click tracking
        'route_prefix' => 'mail/t',
        'route_middleware' => [],
        'signing_key' => env('LARAVEL_MAIL_PIXEL_SIGNING_KEY'), // null = uses APP_KEY
    ],
],
```

### How It Works

[](#how-it-works)

1. When an email is sent, the `InjectTrackingPixel` listener modifies the HTML body:
    - **Open tracking**: Injects a `` tag with a 1x1 transparent GIF before ``
    - **Click tracking**: Rewrites all `` links to route through the package's click endpoint
2. When the recipient opens the email, the pixel image is loaded from your server, registering an `opened` event
3. When the recipient clicks a link, it passes through your server (registering a `clicked` event) and redirects to the original URL

### Tracking URLs

[](#tracking-urls)

EndpointPurpose`GET /mail/t/pixel/{id}?sig={hmac}`Serves 1x1 transparent GIF, records open event`GET /mail/t/click/{id}?url={base64}&sig={hmac}`Records click event, redirects to original URLAll URLs are signed with HMAC-SHA256 to prevent forgery. Invalid signatures are silently ignored for pixel requests (still serves the GIF) and rejected with 403 for click requests.

### Security

[](#security)

- URLs are signed with HMAC-SHA256 using the configured `signing_key` (or `APP_KEY` as fallback)
- Click redirects validate that the target URL uses `http` or `https` schemes (blocks `javascript:`, `data:`, etc.)
- `mailto:`, `tel:`, `sms:`, and anchor (`#`) links are not rewritten
- Pixel responses include `Cache-Control: no-store` to prevent caching

### Coexistence with Provider Webhooks

[](#coexistence-with-provider-webhooks)

Pixel tracking works alongside webhook-based tracking. Both register events in the `mail_tracking_events` table with different providers (`pixel` vs `ses`/`sendgrid`/etc.), and both dispatch the same Laravel events (`MailOpened`, `MailClicked`).

Suppression List
----------------

[](#suppression-list)

Automatically suppress email addresses that hard bounce or receive spam complaints. Suppressed addresses are blocked from receiving future emails.

### Enable Suppression

[](#enable-suppression)

```
LARAVEL_MAIL_SUPPRESSION_ENABLED=true
```

```
// config/laravel-mail.php
'suppression' => [
    'enabled' => true,
    'auto_suppress_hard_bounces' => true,
    'auto_suppress_complaints' => true,
],
```

When enabled, the package automatically:

- Adds hard-bounced addresses to the suppression list
- Adds complained addresses to the suppression list
- Blocks sending to any suppressed address (cancels the email before it's sent)

### Manual Suppression Management

[](#manual-suppression-management)

```
use JeffersonGoncalves\LaravelMail\Models\MailSuppression;
use JeffersonGoncalves\LaravelMail\Enums\SuppressionReason;

// Manually suppress an address
MailSuppression::create([
    'email' => 'user@example.com',
    'reason' => SuppressionReason::Manual,
    'suppressed_at' => now(),
]);

// Check if an address is suppressed
$isSuppressed = MailSuppression::where('email', 'user@example.com')->exists();
```

### Unsuppress Command

[](#unsuppress-command)

```
php artisan mail:unsuppress user@example.com
```

Browser Preview
---------------

[](#browser-preview)

View sent emails and templates directly in the browser.

### Enable Preview

[](#enable-preview)

```
LARAVEL_MAIL_PREVIEW_ENABLED=true
```

```
// config/laravel-mail.php
'preview' => [
    'enabled' => true,
    'route_prefix' => 'mail/preview',
    'route_middleware' => ['web'],
    'signed_urls' => true, // Require signed URLs for security
],
```

### Preview URLs

[](#preview-urls)

Access preview URLs via model accessors:

```
$mailLog->preview_url;    // GET /mail/preview/mail-log/{id}?signature=...
$template->preview_url;   // GET /mail/preview/template/{id}?signature=...
```

When `signed_urls` is enabled, URLs are cryptographically signed and cannot be tampered with. When disabled, plain URLs are generated.

Statistics
----------

[](#statistics)

Query email statistics with the `MailStats` facade:

```
use JeffersonGoncalves\LaravelMail\Facades\MailStats;
use Illuminate\Support\Carbon;

$from = Carbon::now()->subDays(30);
$to = Carbon::now();

MailStats::sent($from, $to);          // int
MailStats::delivered($from, $to);     // int
MailStats::bounced($from, $to);       // int
MailStats::complained($from, $to);    // int
MailStats::opened($from, $to);        // int (from tracking events)
MailStats::clicked($from, $to);       // int (from tracking events)
MailStats::deliveryRate($from, $to);  // float (percentage)
MailStats::bounceRate($from, $to);    // float (percentage)
MailStats::dailyStats($from, $to);    // Collection of daily aggregations
```

Notification Channel
--------------------

[](#notification-channel)

Send database templates via Laravel Notifications:

```
use JeffersonGoncalves\LaravelMail\Channels\TemplateMailChannel;
use Illuminate\Notifications\Notification;

class WelcomeNotification extends Notification
{
    public function via($notifiable): array
    {
        return [TemplateMailChannel::class];
    }

    public function toTemplateMail($notifiable): array
    {
        return [
            'template_key' => 'welcome',
            'data' => ['name' => $notifiable->name],
            'locale' => 'en',
        ];
    }
}
```

Retry Failed Emails
-------------------

[](#retry-failed-emails)

Retry emails that failed to send or soft-bounced.

### Enable Retry

[](#enable-retry)

```
// config/laravel-mail.php
'retry' => [
    'enabled' => true,
    'max_attempts' => 3,
],
```

### Retry Programmatically

[](#retry-programmatically)

```
use JeffersonGoncalves\LaravelMail\Actions\RetryFailedMailAction;

$action = new RetryFailedMailAction();
$action->execute($failedMailLog); // Returns true on success, false if max attempts reached
```

### Retry via Command

[](#retry-via-command)

```
# Retry failed emails from the last 24 hours
php artisan mail:retry

# Retry soft-bounced emails from the last 48 hours
php artisan mail:retry --status=bounced --hours=48

# Limit the number of retries
php artisan mail:retry --limit=50
```

Hard bounces are automatically skipped when retrying bounced emails.

Resend Emails
-------------

[](#resend-emails)

Resend any previously logged email:

```
use JeffersonGoncalves\LaravelMail\Actions\ResendMailAction;

$action = new ResendMailAction();
$action->execute($mailLog);
```

Attachment File Storage
-----------------------

[](#attachment-file-storage)

Optionally store email attachment files to disk for later retrieval:

```
LARAVEL_MAIL_STORE_ATTACHMENT_FILES=true
LARAVEL_MAIL_ATTACHMENTS_DISK=local   # or s3, etc.
```

```
// config/laravel-mail.php
'logging' => [
    'store_attachment_files' => true,
    'attachments_disk' => 'local',
    'attachments_path' => 'mail-attachments',
],
```

When enabled, each attachment is stored to the configured disk and the `path` and `disk` are added to the attachment metadata in the mail log. When pruning, stored files are automatically cleaned up.

Pruning Old Logs
----------------

[](#pruning-old-logs)

Clean up old mail logs:

```
php artisan mail:prune            # Prune logs older than 30 days (default)
php artisan mail:prune --days=7   # Prune logs older than 7 days
```

### Per-Status Retention Policies

[](#per-status-retention-policies)

Keep different statuses for different durations:

```
// config/laravel-mail.php
'prune' => [
    'enabled' => true,
    'older_than_days' => 30, // default fallback
    'policies' => [
        'delivered' => 30,   // delete delivered after 30 days
        'bounced' => 90,     // keep bounced for 90 days
        'complained' => 365, // keep complaints for 1 year
    ],
],
```

Schedule it:

```
Schedule::command('mail:prune')->daily();
```

CLI Commands
------------

[](#cli-commands)

CommandDescription`mail:prune`Delete old mail logs (supports `--days` option)`mail:retry`Retry failed/bounced emails (supports `--status`, `--hours`, `--limit`)`mail:unsuppress {email}`Remove an email from the suppression list`mail:send-test {key} {email}`Send a test email using a template (supports `--locale`, `--data`)`mail:templates`List all mail templates in a table`mail:stats`Show email statistics (supports `--days`)### Send Test Email

[](#send-test-email)

```
# Send with example data from template variables
php artisan mail:send-test welcome user@example.com

# With specific locale
php artisan mail:send-test welcome user@example.com --locale=pt_BR

# With custom data
php artisan mail:send-test welcome user@example.com --data='{"name":"Alice"}'
```

### View Statistics

[](#view-statistics)

```
php artisan mail:stats            # Last 7 days (default)
php artisan mail:stats --days=30  # Last 30 days
```

### List Templates

[](#list-templates)

```
php artisan mail:templates
```

Polymorphic Association
-----------------------

[](#polymorphic-association)

Associate mail logs with any model:

```
use JeffersonGoncalves\LaravelMail\Traits\HasMailLogs;

class User extends Model
{
    use HasMailLogs;
}

$user->mailLogs()->latest()->get();
```

Multi-Tenancy
-------------

[](#multi-tenancy)

```
// config/laravel-mail.php
'tenant' => [
    'enabled' => true,
    'column' => 'tenant_id',
],
```

Custom Models
-------------

[](#custom-models)

```
// config/laravel-mail.php
'models' => [
    'mail_log' => \App\Models\MailLog::class,
    'mail_template' => \App\Models\MailTemplate::class,
    'mail_template_version' => \App\Models\MailTemplateVersion::class,
    'mail_tracking_event' => \App\Models\MailTrackingEvent::class,
    'mail_suppression' => \App\Models\MailSuppression::class,
],
```

Custom Table Names
------------------

[](#custom-table-names)

```
// config/laravel-mail.php
'database' => [
    'connection' => null,
    'tables' => [
        'mail_logs' => 'mail_logs',
        'mail_templates' => 'mail_templates',
        'mail_template_versions' => 'mail_template_versions',
        'mail_tracking_events' => 'mail_tracking_events',
        'mail_suppressions' => 'mail_suppressions',
    ],
],
```

Facades
-------

[](#facades)

```
use JeffersonGoncalves\LaravelMail\Facades\LaravelMail;

LaravelMail::isLoggingEnabled();  // bool
LaravelMail::isTrackingEnabled(); // bool
LaravelMail::findByProviderMessageId('msg-id-123'); // ?MailLog
LaravelMail::updateStatus($mailLog, MailStatus::Delivered); // MailLog
```

```
use JeffersonGoncalves\LaravelMail\Facades\MailStats;

MailStats::sent($from, $to);
MailStats::deliveryRate($from, $to);
MailStats::dailyStats($from, $to);
```

Testing
-------

[](#testing)

```
composer test
```

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](CONTRIBUTING.md) for details.

Security Vulnerabilities
------------------------

[](#security-vulnerabilities)

Please review [our security policy](../../security/policy) on how to report security vulnerabilities.

Credits
-------

[](#credits)

- [Jefferson Goncalves](https://github.com/jeffersongoncalves)
- [All Contributors](../../contributors)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

44

—

FairBetter than 92% of packages

Maintenance90

Actively maintained with recent releases

Popularity16

Limited adoption so far

Community11

Small or concentrated contributor base

Maturity49

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 ~0 days

Total

4

Last Release

45d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/411493?v=4)[Jefferson Gonçalves](/maintainers/jeffersongoncalves)[@jeffersongoncalves](https://github.com/jeffersongoncalves)

---

Top Contributors

[![jeffersongoncalves](https://avatars.githubusercontent.com/u/411493?v=4)](https://github.com/jeffersongoncalves "jeffersongoncalves (19 commits)")

---

Tags

delivery-trackingemailemail-analyticsemail-previewemail-suppressioninline-csslaravellaravel-maillaravel-packagemail-logmail-templatemailgunnotification-channelphppixel-trackingpostmarkresendsendgridseswebhooklaravelemailsendgridresendwebhookmailgunsesjeffersongoncalvespostmarklaravel-mailmail templatemail-logmail-tracking

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/jeffersongoncalves-laravel-mail/health.svg)

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

###  Alternatives

[s-ichikawa/laravel-sendgrid-driver

This library adds a 'sendgrid' mail driver to Laravel.

4089.3M1](/packages/s-ichikawa-laravel-sendgrid-driver)[propaganistas/laravel-disposable-email

Disposable email validator

6012.6M6](/packages/propaganistas-laravel-disposable-email)[slm/mail

Integration of various email service providers in the Laminas\\Mail

108732.4k1](/packages/slm-mail)[omnimail/omnimail

PHP Library to send email across all platforms using one interface.

32934.3k](/packages/omnimail-omnimail)[vormkracht10/laravel-mails

Laravel Mails can collect everything you might want to track about the mails that has been sent by your Laravel app.

24149.7k](/packages/vormkracht10-laravel-mails)[outerweb/image-library

Store and link files to your models

1113.0k2](/packages/outerweb-image-library)

PHPackages © 2026

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