somehow-digital / craft-lettermint
Lettermint Mailer Adapter for Craft CMS.
Package info
github.com/somehow-digital/craft-lettermint
Type:craft-plugin
pkg:composer/somehow-digital/craft-lettermint
Requires
- php: ^8.2
- craftcms/cms: ^5.8.0
- lettermint/symfony-mailer: ^1.1.0
Requires (Dev)
- craftcms/phpstan: dev-main
- pestphp/pest: ^3.0 || ^4.0
- phpstan/phpstan: ^2.1
- roave/security-advisories: dev-latest
- symplify/easy-coding-standard: ^13.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-11-04 20:37:07 UTC
README
Lettermint for Craft CMS
Provides a Lettermint integration for Craft CMS.
| Feature | Standard | Pro |
|---|---|---|
| Mail transport with route and tags | ✓ | ✓ |
| Utility with usage and checks | ✓ | |
| Webhooks as Craft events | ✓ | |
| Route and tags per site | ✓ |
Requirements
- Craft CMS 5.8.0+
- PHP 8.2+
Installation
Plugin Store: open the Plugin Store in the Control Panel, search for “Lettermint” and click Install.
Composer:
composer require somehow-digital/craft-lettermint ./craft plugin/install lettermint
Setup
- Go to Settings → Email.
- Set Transport Type to Lettermint.
- Fill in the settings below and click Save.
| Setting | Required | Description |
|---|---|---|
| Project API Token | ✓ | From your projects page under “API Token”. |
| Route Slug | A custom route. Blank uses the default transactional route. | |
| Tags | Tags for all emails, e.g. environment=production, campaign=welcome. |
Important
The System Email Address must use a domain configured in Lettermint.
Tip
All settings can use environment variables.
Tag names and values may only contain letters, digits, _ and -.
Pro Edition
Pro settings
| Setting | Description |
|---|---|
| Team API Token | Enables features using the Team API. Team owners create it in the dashboard under Manage team → “API Tokens”. |
| Project | ID of the project the Project API Token belongs to (Lettermint can't tell). Suggested once the team token is accepted. Leave blank if the team has only one project. |
| Webhook Secret | Signing secret (whsec_…) of a webhook. Blank turns the endpoint off. |
| Sites | Route slug and tags per site. |
Utility
Open Utilities → Lettermint for an overview of your team.
| Section | Shows |
|---|---|
| Team | Plan and number of projects, domains and members |
| Usage | Emails sent this billing period vs. plan |
| Tokens | Whether the Project and Team API Tokens are accepted |
| Project | Default route, emails and deliverability (28 days), plus checks |
| Statistics | Sent, delivered, hard bounces, spam complaints, opens and clicks (28 days), with a daily chart |
| Projects | Delivery mode, routes, domains, emails and deliverability of each project |
| Domains | Verification status |
The project checks verify that:
- the project is live,
- the System Email Address domain belongs to it and is verified,
- the route slugs of the adapter and all sites are outgoing routes of it.
Good to know:
- The token status of the Project API Token works without a Team API Token.
- Sections the token can't read are hidden with a notice.
- Access is controlled by the Utilities → Lettermint user permission.
Webhooks
Receive Lettermint webhook events (deliveries, bounces, complaints, …) as Craft events.
Setup
- In the dashboard, create a webhook with the endpoint URL shown below the Webhook Secret setting (e.g.
https://example.com/actions/lettermint/webhook) and choose its events. - Paste its signing secret into Webhook Secret.
Usage
use SomehowDigital\Craft\Lettermint\Webhooks; use SomehowDigital\Craft\Lettermint\events\WebhookEvent; use yii\base\Event; Event::on(Webhooks::class, Webhooks::EVENT_RECEIVE_WEBHOOK, function (WebhookEvent $event) { if ($event->type === Webhooks::TYPE_MESSAGE_HARD_BOUNCED) { $event->payload->id; // delivery ID $event->payload->data; // event data, e.g. `recipient` } });
Each documented type has a TYPE_* constant, e.g. TYPE_MESSAGE_DELIVERED, TYPE_MESSAGE_SPAM_COMPLAINT, TYPE_SUPPRESSION_ADDED. The dashboard's test delivery is TYPE_WEBHOOK_TEST. Types Lettermint adds later fire the event too.
Behavior
| Situation | Response | Lettermint retries? |
|---|---|---|
| Valid signature, handlers succeed | 200 |
— |
| Invalid signature or older than 5 minutes | 401 |
No |
| A handler throws an exception | 500 |
Yes, for up to ~14 hours |
| No response within 30 seconds | — | Yes |
Tip
- Deliveries may arrive more than once — deduplicate using
$event->payload->id, which stays the same across retries. - Keep handlers fast; push longer work to the queue.
- Deliveries are received even while the system is offline.
Per-site routes and tags
Set a Route Slug and Tags for each site in the Sites table. The site is determined from the message (e.g. a user's affiliated site) or the current request. Both can use environment variables.
| Route Slug | Tags | |
|---|---|---|
| Site value | Replaces the adapter's route | Merged with the adapter's tags; same names are replaced |
| Not set | Adapter's route is used | Adapter's tags are used |
X-LM-Options header on the message |
Takes precedence | Replaces site and adapter tags |
| Limit | — | Max. 20 tags combined |
Example: adapter environment=production, site=default + site site=shop → environment=production, site=shop.