lettermint/lettermint-laravel 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

lettermint/lettermint-laravel

Composer 安装命令:

composer require lettermint/lettermint-laravel

包简介

Official Lettermint driver for Laravel

README 文档

README

Latest Version on Packagist GitHub Tests Action Status GitHub Code Style Action Status Total Downloads Join our Discord server

Easily integrate Lettermint into your Laravel application.

Requirements

  • PHP 8.2 or higher
  • Laravel 9 or higher

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 project and API tokens.

Configuration

Setting your project token

Add your Lettermint project token in your .env file. This token is used for sending email through Laravel mail:

LETTERMINT_PROJECT_TOKEN=your-lettermint-project-token

The legacy LETTERMINT_TOKEN environment variable is still supported, but LETTERMINT_PROJECT_TOKEN is preferred for new applications.

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

Setting your API token

Add your Lettermint API token in your .env file when you want to use the Team API from your Laravel application:

LETTERMINT_API_TOKEN=your-lettermint-api-token

Setting the request timeout

The default Lettermint API request timeout is 15 seconds. You can override it in your .env file:

LETTERMINT_TIMEOUT=30

Add the transport

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

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

Add the service

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

    'lettermint' => [
        'token' => env('LETTERMINT_PROJECT_TOKEN', env('LETTERMINT_TOKEN')),
        'api_token' => env('LETTERMINT_API_TOKEN'),
    ],

Using the Team API

Resolve the PHP SDK API client from Laravel's container:

use Lettermint\Client\ApiClient;

$projects = app(ApiClient::class)->projects->list();
$team = app('lettermint.api')->team->retrieve();

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

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

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

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: 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

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

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

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

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)

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

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)

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

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)

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

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

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

  • 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

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

Configuration

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

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

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

Event Class Webhook Type Description
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
MessagePolicyRejected message.policy_rejected Rejected by sending policy
MessageUnsubscribed message.unsubscribed Recipient unsubscribed
MessageOpened message.opened Recipient opened the email
MessageClicked message.clicked Recipient clicked a link
MessageInbound message.inbound Inbound email received
WebhookTest webhook.test Test event from dashboard

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

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

Each event type has its own typed data class:

Event Data Properties
MessageDelivered messageId, recipient, response, metadata, tag
MessageHardBounced messageId, recipient, response, metadata, tag
MessageCreated messageId, from, to, cc, bcc, subject, metadata, tag
MessagePolicyRejected messageId, subject, reason, score, spamSymbols, metadata, tag
MessageOpened messageId, subject, recipient, openedAt, firstOpen, deviceType, clientType, bot
MessageClicked messageId, subject, recipient, clickedAt, destinationUrl, linkIndex, firstClick, bot
MessageInbound route, messageId, from, to, subject, body, headers, attachments, isSpam, spamScore
WebhookTest message, webhookId, timestamp

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

composer test

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security Vulnerabilities

Please review our security policy on how to report security vulnerabilities.

Credits

License

The MIT License (MIT). Please see License File for more information.

lettermint/lettermint-laravel 适用场景与选型建议

lettermint/lettermint-laravel 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 76.86k 次下载、GitHub Stars 达 10, 最近一次更新时间为 2025 年 04 月 21 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「laravel」 「lettermint」 「lettermint-laravel」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 lettermint/lettermint-laravel 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 lettermint/lettermint-laravel 我们能提供哪些服务?
定制开发 / 二次开发

基于 lettermint/lettermint-laravel 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 76.86k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 10
  • 点击次数: 9
  • 依赖项目数: 1
  • 推荐数: 0

GitHub 信息

  • Stars: 10
  • Watchers: 1
  • Forks: 3
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2025-04-21