{"id":46455640,"url":"https://github.com/lettermint/lettermint-laravel","last_synced_at":"2026-05-11T09:55:45.297Z","repository":{"id":289119564,"uuid":"970176283","full_name":"lettermint/lettermint-laravel","owner":"lettermint","description":"Official Lettermint Laravel driver","archived":false,"fork":false,"pushed_at":"2026-05-05T08:43:29.000Z","size":93,"stargazers_count":8,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-05-05T10:29:38.224Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lettermint.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-04-21T15:47:44.000Z","updated_at":"2026-05-05T08:43:31.000Z","dependencies_parsed_at":"2025-06-28T21:21:36.291Z","dependency_job_id":"7ac057a2-ec8d-4aa6-bf92-6e0c95fa46ca","html_url":"https://github.com/lettermint/lettermint-laravel","commit_stats":null,"previous_names":["lettermint/lettermint-laravel"],"tags_count":16,"template":false,"template_full_name":"spatie/package-skeleton-laravel","purl":"pkg:github/lettermint/lettermint-laravel","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lettermint%2Flettermint-laravel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lettermint%2Flettermint-laravel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lettermint%2Flettermint-laravel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lettermint%2Flettermint-laravel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lettermint","download_url":"https://codeload.github.com/lettermint/lettermint-laravel/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lettermint%2Flettermint-laravel/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32889971,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-10T13:40:02.631Z","status":"online","status_checked_at":"2026-05-11T02:00:05.975Z","response_time":120,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-03-06T01:36:03.752Z","updated_at":"2026-05-11T09:55:45.289Z","avatar_url":"https://github.com/lettermint.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Official Lettermint driver for Laravel\n\n[![Latest Version on Packagist](https://img.shields.io/packagist/v/lettermint/lettermint-laravel.svg?style=flat-square)](https://packagist.org/packages/lettermint/lettermint-laravel)\n[![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/lettermint/lettermint-laravel/run-tests.yml?branch=main\u0026label=tests\u0026style=flat-square)](https://github.com/lettermint/lettermint-laravel/actions?query=workflow%3Arun-tests+branch%3Amain)\n[![GitHub Code Style Action Status](https://img.shields.io/github/actions/workflow/status/lettermint/lettermint-laravel/fix-php-code-style-issues.yml?branch=main\u0026label=code%20style\u0026style=flat-square)](https://github.com/lettermint/lettermint-laravel/actions?query=workflow%3A\"Fix+PHP+code+style+issues\"+branch%3Amain)\n[![Total Downloads](https://img.shields.io/packagist/dt/lettermint/lettermint-laravel.svg?style=flat-square)](https://packagist.org/packages/lettermint/lettermint-laravel)\n[![Join our Discord server](https://img.shields.io/discord/1305510095588819035?logo=discord\u0026logoColor=eee\u0026label=Discord\u0026labelColor=464ce5\u0026color=0D0E28\u0026cacheSeconds=43200)](https://lettermint.co/r/discord)\n\nEasily integrate [Lettermint](https://lettermint.co) into your Laravel application.\n\n---\n\n## Requirements\n\n- PHP 8.2 or higher\n- Laravel 9 or higher\n\n\n## Installation\n\nYou can install the package via composer:\n\n```bash\ncomposer require lettermint/lettermint-laravel\n```\n\nYou can publish the config file with:\n\n```bash\nphp artisan vendor:publish --tag=\"lettermint-config\"\n```\n\nThis creates a `config/lettermint.php` file where you can add your project and API tokens.\n\n## Configuration\n\n### Setting your project token\n\nAdd your Lettermint project token in your `.env` file. This token is used for sending email through Laravel mail:\n\n```env\nLETTERMINT_PROJECT_TOKEN=your-lettermint-project-token\n```\n\nThe legacy `LETTERMINT_TOKEN` environment variable is still supported, but\n`LETTERMINT_PROJECT_TOKEN` is preferred for new applications.\n\nOr update the `config/lettermint.php` file as needed.\n\n### Setting your API token\n\nAdd your Lettermint API token in your `.env` file when you want to use the Team API from your Laravel application:\n\n```env\nLETTERMINT_API_TOKEN=your-lettermint-api-token\n```\n\n### Add the transport\n\nIn your `config/mail.php`, set the default option to lettermint:\n```php\n        'lettermint' =\u003e [\n            'transport' =\u003e 'lettermint',\n        ],\n```\n\n### Add the service\n\nIn your `config/services.php`, add the Lettermint service:\n```php\n    'lettermint' =\u003e [\n        'token' =\u003e env('LETTERMINT_PROJECT_TOKEN', env('LETTERMINT_TOKEN')),\n        'api_token' =\u003e env('LETTERMINT_API_TOKEN'),\n    ],\n```\n\n### Using the Team API\n\nResolve the PHP SDK API client from Laravel's container:\n\n```php\nuse Lettermint\\Client\\ApiClient;\n\n$projects = app(ApiClient::class)-\u003eprojects-\u003elist();\n$team = app('lettermint.api')-\u003eteam-\u003eretrieve();\n```\n\n### Using Routes\n\nIf 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:\n\n```php\n'lettermint' =\u003e [\n    'transport' =\u003e 'lettermint',\n    'route_id' =\u003e env('LETTERMINT_ROUTE_ID'),\n],\n```\n\n### Multiple mailers with different routes\n\nYou can configure multiple mailers using the same Lettermint transport but with different route IDs:\n\n```php\n// config/mail.php\n'mailers' =\u003e [\n    'lettermint_marketing' =\u003e [\n        'transport' =\u003e 'lettermint',\n        'route_id' =\u003e env('LETTERMINT_MARKETING_ROUTE_ID'),\n    ],\n    'lettermint_transactional' =\u003e [\n        'transport' =\u003e 'lettermint',\n        'route_id' =\u003e env('LETTERMINT_TRANSACTIONAL_ROUTE_ID'),\n    ],\n],\n```\n\nThen use them in your application:\n```php\nMail::mailer('lettermint_marketing')-\u003eto($user)-\u003esend(new MarketingEmail());\nMail::mailer('lettermint_transactional')-\u003eto($user)-\u003esend(new TransactionalEmail());\n```\n\n## Idempotency Support\n\nThe 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.\n\n### Configuration Options\n\nYou can configure idempotency behavior per mailer in your `config/mail.php`:\n\n```php\n'mailers' =\u003e [\n    'lettermint' =\u003e [\n        'transport' =\u003e 'lettermint',\n        'idempotency' =\u003e true, // Enable automatic content-based idempotency\n        'idempotency_window' =\u003e 86400, // Window in seconds (default: 24 hours)\n    ],\n    'lettermint_marketing' =\u003e [\n        'transport' =\u003e 'lettermint',\n        'route_id' =\u003e 'marketing',\n        'idempotency' =\u003e false, // Disable automatic idempotency\n    ],\n],\n```\n\n#### Idempotency Options:\n\n- **`idempotency`**: Enable/disable automatic content-based idempotency\n  - `true`: Generates idempotency keys based on email content\n  - `false` (default): Disables automatic idempotency (user headers still work)\n- **`idempotency_window`**: Time window in seconds for deduplication\n  - Default: `86400` (24 hours to match Lettermint API retention)\n  - Set to match your needs (e.g., `3600` for 1 hour, `300` for 5 minutes)\n  - When set to `86400` or higher, emails with identical content are permanently deduplicated within the API retention period\n\n### Automatic Idempotency\n\nWhen `idempotency` is `true`, the driver generates a unique key based on:\n- Email subject, recipients (to, cc, bcc), and content\n- Sender address (to differentiate between different sending contexts)\n- Time window (if less than 24 hours)\n\nThis ensures:\n- Identical emails are only sent once within the configured time window\n- Retried queue jobs won't create duplicate emails\n- Different emails or the same email after the time window will be sent normally\n\n### Custom Idempotency Keys\n\nYou can override any configuration by setting a custom idempotency key in the email headers:\n\n```php\nMail::send('emails.welcome', $data, function ($message) {\n    $message-\u003eto('user@example.com')\n        -\u003esubject('Welcome!')\n        -\u003egetHeaders()-\u003eaddTextHeader('Idempotency-Key', 'welcome-user-123');\n});\n```\n\n**Priority order** (highest to lowest):\n1. `Idempotency-Key` header in the email (always respected, overrides any config)\n2. Automatic Message-ID (if `idempotency` is `true`)\n3. No idempotency (if `idempotency` is `false`)\n\n**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.\n\n## Tags and Metadata\n\nThe Lettermint Laravel driver supports adding tags and metadata to your emails for better organization, tracking, and analytics.\n\n### Using Tags\n\nTags help you categorize and filter your emails in the Lettermint dashboard. You can add tags using Laravel's native mailable methods:\n\n#### Method 1: Using Laravel's tag() method (Recommended)\n\n```php\nuse App\\Mail\\WelcomeEmail;\nuse Illuminate\\Support\\Facades\\Mail;\n\nMail::send((new WelcomeEmail($user))\n    -\u003etag('onboarding')\n);\n```\n\n#### Method 2: Using the envelope method in your Mailable\n\n```php\nuse Illuminate\\Mail\\Mailables\\Envelope;\n\nclass WelcomeEmail extends Mailable\n{\n    public function envelope(): Envelope\n    {\n        return new Envelope(\n            subject: 'Welcome to our platform!',\n            tags: ['onboarding'], // Only one tag is allowed\n        );\n    }\n}\n```\n\n#### Method 3: Using custom header (backward compatibility)\n\nTo minimise confusion with the way of tagging emails sent via the SMTP relay, the Lettermint Laravel driver also supports the `X-LM-Tag` header.\nThis will be converted to the `TagHeader` envelope method automatically.\n\n```php\nuse Illuminate\\Mail\\Mailables\\Headers;\n\nclass WelcomeEmail extends Mailable\n{\n    public function headers(): Headers\n    {\n        return new Headers(\n            text: [\n                'X-LM-Tag' =\u003e 'onboarding',\n            ],\n        );\n    }\n}\n```\n\n### Using Metadata\n\nMetadata allows you to attach custom key-value pairs to your emails for enhanced tracking and analytics:\n\n#### Method 1: Using Laravel's metadata() method (Recommended)\n\n```php\nMail::send((new OrderConfirmation($order))\n    -\u003emetadata('order_id', $order-\u003eid)\n    -\u003emetadata('customer_id', $order-\u003ecustomer_id)\n);\n```\n\n#### Method 2: Using the envelope method\n\n```php\npublic function envelope(): Envelope\n{\n    return new Envelope(\n        subject: 'Order Confirmation',\n        metadata: [\n            'order_id' =\u003e $this-\u003eorder-\u003eid,\n            'customer_id' =\u003e $this-\u003eorder-\u003ecustomer_id,\n            'order_total' =\u003e $this-\u003eorder-\u003etotal,\n        ],\n    );\n}\n```\n\n### Combining Tags and Metadata\n\nYou can use both tags and metadata together:\n\n```php\nMail::send((new OrderShipped($order))\n    -\u003etag('transactional')\n    -\u003emetadata('order_id', $order-\u003eid)\n    -\u003emetadata('tracking_number', $order-\u003etracking_number)\n);\n```\n\nOr in your mailable:\n\n```php\npublic function envelope(): Envelope\n{\n    return new Envelope(\n        subject: 'Your order has shipped!',\n        tags: ['transactional', 'shipping'],\n        metadata: [\n            'order_id' =\u003e $this-\u003eorder-\u003eid,\n            'tracking_number' =\u003e $this-\u003eorder-\u003etracking_number,\n            'carrier' =\u003e $this-\u003eorder-\u003ecarrier,\n        ],\n    );\n}\n```\n\n### Note on Compatibility\n\n- The driver supports Laravel's native `tag()` and `metadata()` methods (Laravel 9+)\n- The `X-LM-Tag` header is supported for backward compatibility\n- When both `TagHeader` and `X-LM-Tag` are present, the `TagHeader` takes precedence\n\n## Webhooks\n\nThe package provides built-in support for handling Lettermint webhooks with automatic signature verification.\n\n### Configuration\n\nAdd your webhook signing secret to your `.env` file:\n\n```env\nLETTERMINT_WEBHOOK_SECRET=your-webhook-signing-secret\n```\n\nYou can optionally configure the route prefix and timestamp tolerance:\n\n```env\nLETTERMINT_WEBHOOK_PREFIX=lettermint\nLETTERMINT_WEBHOOK_TOLERANCE=300\n```\n\nOr publish the config file and modify the webhooks section:\n\n```php\n// config/lettermint.php\n'webhooks' =\u003e [\n    'secret' =\u003e env('LETTERMINT_WEBHOOK_SECRET'),\n    'prefix' =\u003e env('LETTERMINT_WEBHOOK_PREFIX', 'lettermint'),\n    'tolerance' =\u003e env('LETTERMINT_WEBHOOK_TOLERANCE', 300),\n],\n```\n\n### Webhook Endpoint\n\nThe package automatically registers a webhook endpoint at:\n\n```\nPOST /{prefix}/webhook\n```\n\nBy default, this is `POST /lettermint/webhook`. Configure this URL in your Lettermint dashboard.\n\n### Handling Webhook Events\n\nThe package dispatches Laravel events for each webhook type. Listen to specific events in your `EventServiceProvider` or using closures:\n\n```php\nuse Lettermint\\Laravel\\Events\\MessageDelivered;\nuse Lettermint\\Laravel\\Events\\MessageHardBounced;\nuse Lettermint\\Laravel\\Events\\MessageSpamComplaint;\n\n// In EventServiceProvider\nprotected $listen = [\n    MessageDelivered::class =\u003e [\n        HandleEmailDelivered::class,\n    ],\n    MessageHardBounced::class =\u003e [\n        HandleEmailBounced::class,\n    ],\n];\n\n// Or using closures\nEvent::listen(MessageDelivered::class, function (MessageDelivered $event) {\n    Log::info('Email delivered', [\n        'message_id' =\u003e $event-\u003edata-\u003emessageId,\n        'recipient' =\u003e $event-\u003edata-\u003erecipient,\n        'status_code' =\u003e $event-\u003edata-\u003eresponse-\u003estatusCode,\n    ]);\n});\n\nEvent::listen(MessageHardBounced::class, function (MessageHardBounced $event) {\n    // Handle permanent bounce - consider disabling the recipient\n    $recipient = $event-\u003edata-\u003erecipient;\n    $reason = $event-\u003edata-\u003eresponse-\u003econtent;\n});\n```\n\n### Available Events\n\n| Event Class            | Webhook Type             | Description                      |\n|------------------------|--------------------------|----------------------------------|\n| `MessageCreated`       | `message.created`        | Message accepted for processing  |\n| `MessageSent`          | `message.sent`           | Message sent to recipient server |\n| `MessageDelivered`     | `message.delivered`      | Message successfully delivered   |\n| `MessageHardBounced`   | `message.hard_bounced`   | Permanent delivery failure       |\n| `MessageSoftBounced`   | `message.soft_bounced`   | Temporary delivery failure       |\n| `MessageSpamComplaint` | `message.spam_complaint` | Recipient reported spam          |\n| `MessageFailed`        | `message.failed`         | Processing failure               |\n| `MessageSuppressed`    | `message.suppressed`     | Message suppressed               |\n| `MessageUnsubscribed`  | `message.unsubscribed`   | Recipient unsubscribed           |\n| `MessageInbound`       | `message.inbound`        | Inbound email received           |\n| `WebhookTest`          | `webhook.test`           | Test event from dashboard        |\n\n### Listening to All Events\n\nYou can listen to all webhook events using the base class:\n\n```php\nuse Lettermint\\Laravel\\Events\\LettermintWebhookEvent;\n\nEvent::listen(LettermintWebhookEvent::class, function (LettermintWebhookEvent $event) {\n    Log::info('Webhook received', [\n        'type' =\u003e $event-\u003egetEnvelope()-\u003eevent-\u003evalue,\n        'id' =\u003e $event-\u003egetEnvelope()-\u003eid,\n    ]);\n});\n```\n\n### Event Structure\n\nEach event has two main properties:\n\n- `$event-\u003eenvelope` - Common webhook envelope (id, event type, timestamp)\n- `$event-\u003edata` - Event-specific typed payload\n\n```php\n// Envelope (common to all events)\n$event-\u003eenvelope-\u003eid;        // Webhook event ID (string)\n$event-\u003eenvelope-\u003eevent;     // WebhookEventType enum\n$event-\u003eenvelope-\u003etimestamp; // DateTimeImmutable\n\n// Data (typed per event)\n// For MessageDelivered:\n$event-\u003edata-\u003emessageId;              // string\n$event-\u003edata-\u003erecipient;              // string\n$event-\u003edata-\u003eresponse-\u003estatusCode;   // int\n$event-\u003edata-\u003eresponse-\u003econtent;      // string|null\n$event-\u003edata-\u003emetadata;               // array\n$event-\u003edata-\u003etag;                    // string|null\n```\n\n### Typed Event Data\n\nEach event type has its own typed data class:\n\n| Event                | Data Properties                                                                                        |\n|----------------------|--------------------------------------------------------------------------------------------------------|\n| `MessageDelivered`   | `messageId`, `recipient`, `response`, `metadata`, `tag`                                                |\n| `MessageHardBounced` | `messageId`, `recipient`, `response`, `metadata`, `tag`                                                |\n| `MessageCreated`     | `messageId`, `from`, `to`, `cc`, `bcc`, `subject`, `metadata`, `tag`                                   |\n| `MessageInbound`     | `route`, `messageId`, `from`, `to`, `subject`, `body`, `headers`, `attachments`, `isSpam`, `spamScore` |\n| `WebhookTest`        | `message`, `webhookId`, `timestamp`                                                                    |\n\n### Helper Methods\n\nThe `WebhookEventType` enum provides helper methods:\n\n```php\n$event-\u003eenvelope-\u003eevent-\u003eisBounce();        // true for hard/soft bounces\n$event-\u003eenvelope-\u003eevent-\u003eisDeliveryIssue(); // true for bounces, failed, suppressed\n```\n\n## Testing\n\n```bash\ncomposer test\n```\n\n## Changelog\n\nPlease see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.\n\n## Contributing\n\nPlease see [CONTRIBUTING](CONTRIBUTING.md) for details.\n\n## Security Vulnerabilities\n\nPlease review [our security policy](../../security/policy) on how to report security vulnerabilities.\n\n## Credits\n\n- [Bjarn Bronsveld](https://github.com/bjarn)\n- [All Contributors](../../contributors)\n\n## License\n\nThe MIT License (MIT). Please see [License File](LICENSE.md) for more information.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flettermint%2Flettermint-laravel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flettermint%2Flettermint-laravel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flettermint%2Flettermint-laravel/lists"}