Lightweight email marketing and newsletter plugin for Craft CMS 5. Manage subscribers, send campaigns, and track delivery — all natively within your control panel.
| Feature | Free | Lite ($49) | Pro ($79) |
|---|---|---|---|
| Subscriber management | ✓ | ✓ | ✓ |
| Mailing lists | 1 | Unlimited | Unlimited |
| CSV import/export | ✓ | ✓ | ✓ |
| Queue-based sending | 100/mo | Unlimited | Unlimited |
| Twig email templates | ✓ | ✓ | ✓ |
| Unsubscribe handling (RFC 8058) | ✓ | ✓ | ✓ |
| Basic send tracking | ✓ | ✓ | ✓ |
| Craft User sync | — | ✓ | ✓ |
| Open/click analytics | — | ✓ | ✓ |
| Delivery dashboard | — | ✓ | ✓ |
| Custom transports (SES, Mailgun, etc.) | — | ✓ | ✓ |
| Drip sequences / automation | — | — | ✓ |
| A/B subject line testing | — | — | ✓ |
| Dynamic segments | — | — | ✓ |
| Webhook integrations | — | — | ✓ |
| REST API | — | — | ✓ |
- Craft CMS 5.0+
- PHP 8.2+
composer require justinholtweb/craft-dispatch
php craft plugin/install dispatchAll settings are available in the control panel under Dispatch → Settings, or you can configure them via config/dispatch.php:
<?php
return [
'defaultFromName' => 'My Site',
'defaultFromEmail' => 'hello@example.com',
'defaultReplyToEmail' => '',
'sendBatchSize' => 50,
'sendRateLimit' => 0,
'enableTracking' => true,
'trackOpens' => true,
'trackClicks' => true,
];Subscribers are a custom element type with full field layout support. Create them via the CP or programmatically:
use justinholtweb\dispatch\elements\Subscriber;
use justinholtweb\dispatch\Plugin;
$subscriber = new Subscriber();
$subscriber->email = 'user@example.com';
$subscriber->firstName = 'Jane';
$subscriber->lastName = 'Doe';
Craft::$app->getElements()->saveElement($subscriber);
// Add to a mailing list
Plugin::getInstance()->subscribers->subscribe($subscriber->id, $listId);use justinholtweb\dispatch\elements\MailingList;
$list = new MailingList();
$list->name = 'Weekly Newsletter';
$list->handle = 'weeklyNewsletter';
Plugin::getInstance()->lists->create($list);Campaigns use Twig templates for email content. The template receives campaign, subscriber, and unsubscribeUrl variables:
{# Your email template #}
<h1>{{ campaign.subject }}</h1>
<p>Hi {{ subscriber.firstName ?? 'there' }},</p>
{{ content|raw }}
<p><a href="{{ unsubscribeUrl }}">Unsubscribe</a></p>Send a campaign programmatically:
Plugin::getInstance()->campaigns->send($campaignId);Upload a CSV with at minimum an email column. Optional columns: firstName (or first_name), lastName (or last_name). Imports are processed in the background via the queue.
Every email includes List-Unsubscribe and List-Unsubscribe-Post headers per RFC 8058, enabling one-click unsubscribe in supporting email clients. A subscriber preference center is also available at /dispatch/preferences.
When enabled, Dispatch injects a 1×1 tracking pixel for opens and rewrites links for click tracking. All tracking URLs are HMAC-signed to prevent spoofing. View results on the Dashboard tab.
Configure sending via Amazon SES, Mailgun, Postmark, or SendGrid under Settings → Transport. The default craft transport uses your existing Craft email configuration.
Dispatch accepts inbound webhooks for bounce and complaint processing:
POST /dispatch/webhook/ses
POST /dispatch/webhook/mailgun
POST /dispatch/webhook/postmark
POST /dispatch/webhook/sendgrid
Set a webhookSecret in your settings for HMAC signature verification.
Authenticate with a Bearer token (using your webhookSecret):
# List subscribers
curl -H "Authorization: Bearer YOUR_TOKEN" https://example.com/dispatch/api/v1/subscribers
# Subscribe
curl -X POST -H "Authorization: Bearer YOUR_TOKEN" \
-d "email=user@example.com&list=weeklyNewsletter" \
https://example.com/dispatch/api/v1/subscribe
# Unsubscribe
curl -X POST -H "Authorization: Bearer YOUR_TOKEN" \
-d "email=user@example.com" \
https://example.com/dispatch/api/v1/unsubscribe
# Campaign stats
curl -H "Authorization: Bearer YOUR_TOKEN" \
https://example.com/dispatch/api/v1/stats?campaignId=123| Method | Endpoint | Description |
|---|---|---|
| GET | /dispatch/api/v1/subscribers |
List subscribers |
| POST | /dispatch/api/v1/subscribers |
Create subscriber |
| GET | /dispatch/api/v1/lists |
List mailing lists |
| GET | /dispatch/api/v1/campaigns |
List campaigns |
| GET | /dispatch/api/v1/stats?campaignId= |
Campaign statistics |
| POST | /dispatch/api/v1/subscribe |
Subscribe an email to a list |
| POST | /dispatch/api/v1/unsubscribe |
Unsubscribe an email |
| Permission | Description |
|---|---|
dispatch:accessPlugin |
Access the Dispatch CP section |
dispatch:manageCampaigns |
Create/edit/delete campaigns |
dispatch:sendCampaigns |
Trigger campaign sends |
dispatch:manageSubscribers |
Create/edit/delete subscribers |
dispatch:importSubscribers |
Import subscribers via CSV |
dispatch:manageLists |
Create/edit/delete mailing lists |
dispatch:viewDashboard |
View analytics dashboard |
dispatch:manageSettings |
Modify plugin settings |
Dispatch fires events you can listen to in a custom module or plugin:
use justinholtweb\dispatch\elements\Campaign;
use justinholtweb\dispatch\events\CampaignEvent;
use justinholtweb\dispatch\events\SubscriberEvent;
use justinholtweb\dispatch\events\TrackingEvent;
use justinholtweb\dispatch\services\Tracker;
use yii\base\Event;
// Before a campaign sends
Event::on(Campaign::class, 'beforeSend', function (CampaignEvent $event) {
// $event->campaign
});
// After a campaign sends
Event::on(Campaign::class, 'afterSend', function (CampaignEvent $event) {
// $event->campaign
});
// On email open (Lite+)
Event::on(Tracker::class, Tracker::EVENT_ON_OPEN, function (TrackingEvent $event) {
// $event->campaignId, $event->subscriberId
});
// On link click (Lite+)
Event::on(Tracker::class, Tracker::EVENT_ON_CLICK, function (TrackingEvent $event) {
// $event->campaignId, $event->subscriberId, $event->url
});This plugin is released under the Craft License.