PHPackages                             lettermint/lettermint-laravel - 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. [API Development](/categories/api)
4. /
5. lettermint/lettermint-laravel

ActiveLibrary[API Development](/categories/api)

lettermint/lettermint-laravel
=============================

Official Lettermint driver for Laravel

1.6.0(2mo ago)723.2k—6.9%2[3 PRs](https://github.com/lettermint/lettermint-laravel/pulls)MITPHPPHP ^8.2CI passing

Since Apr 22Pushed 2mo agoCompare

[ Source](https://github.com/lettermint/lettermint-laravel)[ Packagist](https://packagist.org/packages/lettermint/lettermint-laravel)[ Docs](https://github.com/lettermint/lettermint-laravel)[ RSS](/packages/lettermint-lettermint-laravel/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (10)Dependencies (28)Versions (19)Used By (0)

Official Lettermint driver for Laravel
======================================

[](#official-lettermint-driver-for-laravel)

[![Latest Version on Packagist](https://camo.githubusercontent.com/3d856da371743ba3bd374f4c992a152b58f004417247cf64edb42c82d216a1df/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6c65747465726d696e742f6c65747465726d696e742d6c61726176656c2e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/lettermint/lettermint-laravel)[![GitHub Tests Action Status](https://camo.githubusercontent.com/5c185e74bace7f84c49ec16eaf94b44bc1568360243904d5c407fafab039b440/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6c65747465726d696e742f6c65747465726d696e742d6c61726176656c2f72756e2d74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/lettermint/lettermint-laravel/actions?query=workflow%3Arun-tests+branch%3Amain)[![GitHub Code Style Action Status](https://camo.githubusercontent.com/ca6c10024b4594c0ebd4489d6dbc9e2537ff4f8b15658cdd8fd639b2a3d118eb/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6c65747465726d696e742f6c65747465726d696e742d6c61726176656c2f6669782d7068702d636f64652d7374796c652d6973737565732e796d6c3f6272616e63683d6d61696e266c6162656c3d636f64652532307374796c65267374796c653d666c61742d737175617265)](https://github.com/lettermint/lettermint-laravel/actions?query=workflow%3A%22Fix+PHP+code+style+issues%22+branch%3Amain)[![Total Downloads](https://camo.githubusercontent.com/c5d850754e9c2f86a158bc8e1134eecd3ab3ec8f24698a5d45c82d8935f32add/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6c65747465726d696e742f6c65747465726d696e742d6c61726176656c2e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/lettermint/lettermint-laravel)[![Join our Discord server](https://camo.githubusercontent.com/53ac78394b2bfdedbab92b06b9aa0593d5334263ac202bcb761913f2cbde04c3/68747470733a2f2f696d672e736869656c64732e696f2f646973636f72642f313330353531303039353538383831393033353f6c6f676f3d646973636f7264266c6f676f436f6c6f723d656565266c6162656c3d446973636f7264266c6162656c436f6c6f723d34363463653526636f6c6f723d3044304532382663616368655365636f6e64733d3433323030)](https://lettermint.co/r/discord)

Easily integrate [Lettermint](https://lettermint.co) into your Laravel application.

---

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

[](#requirements)

- PHP 8.2 or higher
- Laravel 9 or higher

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

[](#installation)

You can install the package via composer:

```
composer require lettermint/lettermint-laravel
```

You can publish the config file with:

```
php artisan vendor:publish --tag="lettermint-config"
```

This creates a `config/lettermint.php` file where you can add your API token.

Configuration
-------------

[](#configuration)

### Setting your API token

[](#setting-your-api-token)

Add your Lettermint API token in your `.env` file:

```
LETTERMINT_TOKEN=your-lettermint-token
```

Or update the `config/lettermint.php` file as needed.

### Add the transport

[](#add-the-transport)

In your `config/mail.php`, set the default option to lettermint:

```
        'lettermint' => [
            'transport' => 'lettermint',
        ],
```

### Add the service

[](#add-the-service)

In your `config/services.php`, add the Lettermint service:

```
    'lettermint' => [
        'token' => env('LETTERMINT_TOKEN'),
    ],
```

### Using Routes

[](#using-routes)

If you would like to specify the Lettermint route that should be used by a given mailer, you may add the `route_id` configuration option to the mailer's configuration array in your `config/mail.php` file:

```
'lettermint' => [
    'transport' => 'lettermint',
    'route_id' => env('LETTERMINT_ROUTE_ID'),
],
```

### Multiple mailers with different routes

[](#multiple-mailers-with-different-routes)

You can configure multiple mailers using the same Lettermint transport but with different route IDs:

```
// config/mail.php
'mailers' => [
    'lettermint_marketing' => [
        'transport' => 'lettermint',
        'route_id' => env('LETTERMINT_MARKETING_ROUTE_ID'),
    ],
    'lettermint_transactional' => [
        'transport' => 'lettermint',
        'route_id' => env('LETTERMINT_TRANSACTIONAL_ROUTE_ID'),
    ],
],
```

Then use them in your application:

```
Mail::mailer('lettermint_marketing')->to($user)->send(new MarketingEmail());
Mail::mailer('lettermint_transactional')->to($user)->send(new TransactionalEmail());
```

Idempotency Support
-------------------

[](#idempotency-support)

The Lettermint Laravel driver prevents duplicate email sends by using idempotency keys. This is especially useful when emails are sent from queued jobs that might be retried.

### Configuration Options

[](#configuration-options)

You can configure idempotency behavior per mailer in your `config/mail.php`:

```
'mailers' => [
    'lettermint' => [
        'transport' => 'lettermint',
        'idempotency' => true, // Enable automatic content-based idempotency
        'idempotency_window' => 86400, // Window in seconds (default: 24 hours)
    ],
    'lettermint_marketing' => [
        'transport' => 'lettermint',
        'route_id' => 'marketing',
        'idempotency' => false, // Disable automatic idempotency
    ],
],
```

#### Idempotency Options:

[](#idempotency-options)

- **`idempotency`**: Enable/disable automatic content-based idempotency
    - `true`: Generates idempotency keys based on email content
    - `false` (default): Disables automatic idempotency (user headers still work)
- **`idempotency_window`**: Time window in seconds for deduplication
    - Default: `86400` (24 hours to match Lettermint API retention)
    - Set to match your needs (e.g., `3600` for 1 hour, `300` for 5 minutes)
    - When set to `86400` or higher, emails with identical content are permanently deduplicated within the API retention period

### Automatic Idempotency

[](#automatic-idempotency)

When `idempotency` is `true`, the driver generates a unique key based on:

- Email subject, recipients (to, cc, bcc), and content
- Sender address (to differentiate between different sending contexts)
- Time window (if less than 24 hours)

This ensures:

- Identical emails are only sent once within the configured time window
- Retried queue jobs won't create duplicate emails
- Different emails or the same email after the time window will be sent normally

### Custom Idempotency Keys

[](#custom-idempotency-keys)

You can override any configuration by setting a custom idempotency key in the email headers:

```
Mail::send('emails.welcome', $data, function ($message) {
    $message->to('user@example.com')
        ->subject('Welcome!')
        ->getHeaders()->addTextHeader('Idempotency-Key', 'welcome-user-123');
});
```

**Priority order** (highest to lowest):

1. `Idempotency-Key` header in the email (always respected, overrides any config)
2. Automatic Message-ID (if `idempotency` is `true`)
3. No idempotency (if `idempotency` is `false`)

**Important:** The `idempotency: false` configuration only disables *automatic* idempotency. User-provided `Idempotency-Key` headers are always respected, giving users full control on a per-email basis.

Tags and Metadata
-----------------

[](#tags-and-metadata)

The Lettermint Laravel driver supports adding tags and metadata to your emails for better organization, tracking, and analytics.

### Using Tags

[](#using-tags)

Tags help you categorize and filter your emails in the Lettermint dashboard. You can add tags using Laravel's native mailable methods:

#### Method 1: Using Laravel's tag() method (Recommended)

[](#method-1-using-laravels-tag-method-recommended)

```
use App\Mail\WelcomeEmail;
use Illuminate\Support\Facades\Mail;

Mail::send((new WelcomeEmail($user))
    ->tag('onboarding')
);
```

#### Method 2: Using the envelope method in your Mailable

[](#method-2-using-the-envelope-method-in-your-mailable)

```
use Illuminate\Mail\Mailables\Envelope;

class WelcomeEmail extends Mailable
{
    public function envelope(): Envelope
    {
        return new Envelope(
            subject: 'Welcome to our platform!',
            tags: ['onboarding'], // Only one tag is allowed
        );
    }
}
```

#### Method 3: Using custom header (backward compatibility)

[](#method-3-using-custom-header-backward-compatibility)

To minimise confusion with the way of tagging emails sent via the SMTP relay, the Lettermint Laravel driver also supports the `X-LM-Tag` header. This will be converted to the `TagHeader` envelope method automatically.

```
use Illuminate\Mail\Mailables\Headers;

class WelcomeEmail extends Mailable
{
    public function headers(): Headers
    {
        return new Headers(
            text: [
                'X-LM-Tag' => 'onboarding',
            ],
        );
    }
}
```

### Using Metadata

[](#using-metadata)

Metadata allows you to attach custom key-value pairs to your emails for enhanced tracking and analytics:

#### Method 1: Using Laravel's metadata() method (Recommended)

[](#method-1-using-laravels-metadata-method-recommended)

```
Mail::send((new OrderConfirmation($order))
    ->metadata('order_id', $order->id)
    ->metadata('customer_id', $order->customer_id)
);
```

#### Method 2: Using the envelope method

[](#method-2-using-the-envelope-method)

```
public function envelope(): Envelope
{
    return new Envelope(
        subject: 'Order Confirmation',
        metadata: [
            'order_id' => $this->order->id,
            'customer_id' => $this->order->customer_id,
            'order_total' => $this->order->total,
        ],
    );
}
```

### Combining Tags and Metadata

[](#combining-tags-and-metadata)

You can use both tags and metadata together:

```
Mail::send((new OrderShipped($order))
    ->tag('transactional')
    ->metadata('order_id', $order->id)
    ->metadata('tracking_number', $order->tracking_number)
);
```

Or in your mailable:

```
public function envelope(): Envelope
{
    return new Envelope(
        subject: 'Your order has shipped!',
        tags: ['transactional', 'shipping'],
        metadata: [
            'order_id' => $this->order->id,
            'tracking_number' => $this->order->tracking_number,
            'carrier' => $this->order->carrier,
        ],
    );
}
```

### Note on Compatibility

[](#note-on-compatibility)

- The driver supports Laravel's native `tag()` and `metadata()` methods (Laravel 9+)
- The `X-LM-Tag` header is supported for backward compatibility
- When both `TagHeader` and `X-LM-Tag` are present, the `TagHeader` takes precedence

Webhooks
--------

[](#webhooks)

The package provides built-in support for handling Lettermint webhooks with automatic signature verification.

### Configuration

[](#configuration-1)

Add your webhook signing secret to your `.env` file:

```
LETTERMINT_WEBHOOK_SECRET=your-webhook-signing-secret
```

You can optionally configure the route prefix and timestamp tolerance:

```
LETTERMINT_WEBHOOK_PREFIX=lettermint
LETTERMINT_WEBHOOK_TOLERANCE=300
```

Or publish the config file and modify the webhooks section:

```
// config/lettermint.php
'webhooks' => [
    'secret' => env('LETTERMINT_WEBHOOK_SECRET'),
    'prefix' => env('LETTERMINT_WEBHOOK_PREFIX', 'lettermint'),
    'tolerance' => env('LETTERMINT_WEBHOOK_TOLERANCE', 300),
],
```

### Webhook Endpoint

[](#webhook-endpoint)

The package automatically registers a webhook endpoint at:

```
POST /{prefix}/webhook

```

By default, this is `POST /lettermint/webhook`. Configure this URL in your Lettermint dashboard.

### Handling Webhook Events

[](#handling-webhook-events)

The package dispatches Laravel events for each webhook type. Listen to specific events in your `EventServiceProvider` or using closures:

```
use Lettermint\Laravel\Events\MessageDelivered;
use Lettermint\Laravel\Events\MessageHardBounced;
use Lettermint\Laravel\Events\MessageSpamComplaint;

// In EventServiceProvider
protected $listen = [
    MessageDelivered::class => [
        HandleEmailDelivered::class,
    ],
    MessageHardBounced::class => [
        HandleEmailBounced::class,
    ],
];

// Or using closures
Event::listen(MessageDelivered::class, function (MessageDelivered $event) {
    Log::info('Email delivered', [
        'message_id' => $event->data->messageId,
        'recipient' => $event->data->recipient,
        'status_code' => $event->data->response->statusCode,
    ]);
});

Event::listen(MessageHardBounced::class, function (MessageHardBounced $event) {
    // Handle permanent bounce - consider disabling the recipient
    $recipient = $event->data->recipient;
    $reason = $event->data->response->content;
});
```

### Available Events

[](#available-events)

Event ClassWebhook TypeDescription`MessageCreated``message.created`Message accepted for processing`MessageSent``message.sent`Message sent to recipient server`MessageDelivered``message.delivered`Message successfully delivered`MessageHardBounced``message.hard_bounced`Permanent delivery failure`MessageSoftBounced``message.soft_bounced`Temporary delivery failure`MessageSpamComplaint``message.spam_complaint`Recipient reported spam`MessageFailed``message.failed`Processing failure`MessageSuppressed``message.suppressed`Message suppressed`MessageUnsubscribed``message.unsubscribed`Recipient unsubscribed`MessageInbound``message.inbound`Inbound email received`WebhookTest``webhook.test`Test event from dashboard### Listening to All Events

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

You can listen to all webhook events using the base class:

```
use Lettermint\Laravel\Events\LettermintWebhookEvent;

Event::listen(LettermintWebhookEvent::class, function (LettermintWebhookEvent $event) {
    Log::info('Webhook received', [
        'type' => $event->getEnvelope()->event->value,
        'id' => $event->getEnvelope()->id,
    ]);
});
```

### Event Structure

[](#event-structure)

Each event has two main properties:

- `$event->envelope` - Common webhook envelope (id, event type, timestamp)
- `$event->data` - Event-specific typed payload

```
// Envelope (common to all events)
$event->envelope->id;        // Webhook event ID (string)
$event->envelope->event;     // WebhookEventType enum
$event->envelope->timestamp; // DateTimeImmutable

// Data (typed per event)
// For MessageDelivered:
$event->data->messageId;              // string
$event->data->recipient;              // string
$event->data->response->statusCode;   // int
$event->data->response->content;      // string|null
$event->data->metadata;               // array
$event->data->tag;                    // string|null
```

### Typed Event Data

[](#typed-event-data)

Each event type has its own typed data class:

EventData Properties`MessageDelivered``messageId`, `recipient`, `response`, `metadata`, `tag``MessageHardBounced``messageId`, `recipient`, `response`, `metadata`, `tag``MessageCreated``messageId`, `from`, `to`, `cc`, `bcc`, `subject`, `metadata`, `tag``MessageInbound``route`, `messageId`, `from`, `to`, `subject`, `body`, `headers`, `attachments`, `isSpam`, `spamScore``WebhookTest``message`, `webhookId`, `timestamp`### Helper Methods

[](#helper-methods)

The `WebhookEventType` enum provides helper methods:

```
$event->envelope->event->isBounce();        // true for hard/soft bounces
$event->envelope->event->isDeliveryIssue(); // true for bounces, failed, suppressed
```

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)

- [Bjarn Bronsveld](https://github.com/bjarn)
- [All Contributors](../../contributors)

License
-------

[](#license)

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

###  Health Score

52

—

FairBetter than 96% of packages

Maintenance88

Actively maintained with recent releases

Popularity36

Limited adoption so far

Community11

Small or concentrated contributor base

Maturity58

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 88.5% 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 ~23 days

Recently: every ~40 days

Total

15

Last Release

62d ago

Major Versions

0.1.1 → 1.0.02025-06-14

### Community

Maintainers

![](https://www.gravatar.com/avatar/4b21c7b0783f49d47252342dde1bf0395079db0e423f0ee79e82620202355ab2?d=identicon)[bjarn](/maintainers/bjarn)

---

Top Contributors

[![bjarn](https://avatars.githubusercontent.com/u/14638441?v=4)](https://github.com/bjarn "bjarn (46 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (5 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (1 commits)")

---

Tags

laravellettermintlettermint-laravel

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

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

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

###  Alternatives

[dedoc/scramble

Automatic generation of API documentation for Laravel applications.

2.1k7.8M57](/packages/dedoc-scramble)[scalar/laravel

Render your OpenAPI-based API reference

6183.9k2](/packages/scalar-laravel)[ryangjchandler/bearer

Minimalistic token-based authentication for Laravel API endpoints.

8129.8k](/packages/ryangjchandler-bearer)[combindma/laravel-facebook-pixel

Meta pixel integration for Laravel

4956.9k](/packages/combindma-laravel-facebook-pixel)[stechstudio/laravel-hubspot

A Laravel SDK for the HubSpot CRM Api

2971.0k](/packages/stechstudio-laravel-hubspot)[njoguamos/laravel-plausible

A laravel package for interacting with plausible analytics api.

208.8k](/packages/njoguamos-laravel-plausible)

PHPackages © 2026

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