A Statamic addon for sending entries out through pluggable channels. Pick an entry in the control panel, run the Send It action, choose a channel, and go.
The first channel creates a Mailchimp campaign from the entry. A built-in mailer channel sends the entry through Laravel's configured mailer so you can test-send before committing to a real campaign. The channel layer is designed so additional providers — Postmark lists, SMS, WhatsApp — can be added without touching the action.
composer require abigah/send-itPublish the config (optional):
php artisan vendor:publish --tag=send-it-configSet the relevant environment variables:
# Default channel used when none is chosen
SEND_IT_CHANNEL=mailchimp
# Mailchimp
SEND_IT_MAILCHIMP_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-us21
SEND_IT_MAILCHIMP_AUDIENCE_ID=abc123
# Optional: the audience's default sender in Mailchimp is used when blank
SEND_IT_MAILCHIMP_FROM_NAME="Abigah"
SEND_IT_MAILCHIMP_REPLY_TO=hello@abigah.com
# Create drafts by default; flip to send immediately
SEND_IT_MAILCHIMP_SEND_IMMEDIATELY=false
# Mailer (test send) — uses your app's default mailer
SEND_IT_MAILER_TO=you@example.comThe Mailchimp server prefix (e.g. us21) is derived from the API key suffix
automatically; override it with SEND_IT_MAILCHIMP_SERVER_PREFIX if needed.
By default the campaign/email body comes from the entry's content field
(its augmented HTML). Change the source field per channel via
config/send-it.php.
Only the variables marked required need setting for a channel to appear in the Send It action; the rest have the defaults shown.
General
| Variable | Default | Purpose |
|---|---|---|
SEND_IT_CHANNEL |
mailchimp |
Channel selected when the action opens |
SEND_IT_SCHEDULE_STORE |
storage/app/send-it/scheduled-sends.json |
Where scheduled sends are kept |
Mailchimp
| Variable | Default | Purpose |
|---|---|---|
SEND_IT_MAILCHIMP_ENABLED |
true |
Turn the channel off with false |
SEND_IT_MAILCHIMP_API_KEY |
required | API key, ending in the server prefix (-us21) |
SEND_IT_MAILCHIMP_AUDIENCE_ID |
required | Audience (list) id campaigns go to |
SEND_IT_MAILCHIMP_SERVER_PREFIX |
from the API key | Only if the key has no suffix |
SEND_IT_MAILCHIMP_FROM_NAME |
the audience's default | Sender name on campaigns |
SEND_IT_MAILCHIMP_REPLY_TO |
the audience's default from address | Reply-to address on campaigns |
SEND_IT_MAILCHIMP_SEND_IMMEDIATELY |
false |
Pre-select "Send immediately" instead of "Save as draft" |
Campaigns created through Mailchimp's API don't pick up the audience's default sender on their own, so Send It looks it up (Audience → Settings → Audience name and defaults) whenever the from name or reply-to is blank.
Mailer (test sends)
| Variable | Default | Purpose |
|---|---|---|
SEND_IT_MAILER_ENABLED |
true |
Turn the channel off with false |
SEND_IT_MAILER_TO |
none | Default recipient(s) for test sends |
SEND_IT_MAILER_FROM_ADDRESS |
MAIL_FROM_ADDRESS |
From address |
SEND_IT_MAILER_FROM_NAME |
MAIL_FROM_NAME |
From name |
Email layout (used by Mailchimp and the mailer)
| Variable | Default | Purpose |
|---|---|---|
SEND_IT_EMAIL_LOGO_URL |
none | Absolute URL of the logo at the top |
SEND_IT_EMAIL_LOGO_WIDTH |
160 |
Logo width in pixels |
SEND_IT_EMAIL_SITE_NAME |
APP_NAME |
Logo alt text, or shown in place of a logo |
SEND_IT_EMAIL_SITE_URL |
APP_URL |
Where the logo links |
SEND_IT_EMAIL_AUTHOR_FIELD |
author |
Entry field for the byline |
SEND_IT_EMAIL_DATE_FORMAT |
F j, Y |
Date format in the byline |
SEND_IT_EMAIL_GREETING |
Hi {first_name}, |
Greeting under the title; empty to remove |
SEND_IT_EMAIL_GREETING_FALLBACK |
friend |
Used when there's no first name |
SEND_IT_EMAIL_COMPANY |
APP_NAME |
Name in the copyright line |
SEND_IT_EMAIL_FOOTER_TEXT |
none | Extra footer line |
SEND_IT_EMAIL_FOOTER_ADDRESS |
none | Mailing address in the footer |
SEND_IT_EMAIL_UNSUBSCRIBE_URL |
# |
Mailer only; Mailchimp uses its own link |
SEND_IT_EMAIL_UPDATE_PREFERENCES_URL |
none | Mailer only; Mailchimp uses its own link |
Apple push notifications (see below)
| Variable | Default | Purpose |
|---|---|---|
SEND_IT_APNS_ENABLED |
false |
Turn the channel on with true |
SEND_IT_APNS_TEAM_ID |
required | Apple Developer team id |
SEND_IT_APNS_KEY_ID |
required | The auth key's id |
SEND_IT_APNS_PRIVATE_KEY_PATH |
one of three | Path to the .p8 file |
SEND_IT_APNS_PRIVATE_KEY_BASE64 |
one of three | The .p8 contents, base64-encoded |
SEND_IT_APNS_PRIVATE_KEY |
one of three | The .p8 contents, newlines as \n |
SEND_IT_APNS_TOPIC |
required | The app's bundle id |
SEND_IT_APNS_BODY_FIELD |
excerpt |
Entry field for the message when none is typed |
SEND_IT_APNS_TEST_TOKEN |
none | Default device for test sends |
SEND_IT_APNS_TEST_ENVIRONMENT |
sandbox |
APNs server for an unregistered test token |
SEND_IT_APNS_CONCURRENCY |
20 |
Parallel requests to APNs |
SEND_IT_APNS_QUEUE |
default queue | Queue for the send job |
SEND_IT_APNS_DEVICES_ROUTE |
api/push/devices |
Device registration route; empty to disable |
SEND_IT_APNS_DEVICES_STORE |
storage/app/send-it/push-devices.json |
Where devices are kept |
- In the control panel, select one or more entries in a collection listing.
- Run the Send It action.
- Choose a channel (Mailchimp or the mailer test send), optionally set a subject, and confirm.
For Mailchimp, choose a Delivery mode:
- Save as draft (default) — create the campaign in Mailchimp for review.
- Send a test — create a draft campaign titled "Test: …" and send Mailchimp's test email to the addresses in Send test to. Recipients don't need to be on the audience or have Mailchimp access. Mailchimp limits how many tests an account can send per day.
- Send immediately — send as soon as the action runs.
- Schedule for later — pick a date and time; the send happens then.
The schedule field is shown in your own timezone, but the time is stored and
sent in the site timezone (config('app.timezone')). The
SEND_IT_MAILCHIMP_SEND_IMMEDIATELY env var just sets which mode is selected by
default.
Scheduling runs on the Laravel side, not Mailchimp's native scheduler:
-
The chosen send is recorded in
storage/app/send-it/scheduled-sends.json(configurable viaSEND_IT_SCHEDULE_STORE). -
The addon registers a
send-it:run-scheduledcommand to run every minute via Laravel's scheduler. Make sureschedule:runis in your cron:* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1 -
When a send is due, the command publishes the entry (and, for dated collections that hide future-dated entries, brings the date forward to now so it's live) and then creates and sends the Mailchimp campaign immediately.
Because the campaign is built when the scheduler fires, it always uses the entry's latest content.
Tools → Send It shows which channels are ready, the number of registered push devices, upcoming scheduled sends and how recent ones went. Super users see it automatically; give other roles the View Send It permission. The page uses Statamic 6's control panel components.
Channel content is wrapped in an Antlers email layout before sending — a
responsive, email-client-safe shell with the logo centered at the top and a
footer (copyright, address, unsubscribe link). Configure it under the email
key in config/send-it.php (logo URL/width, site name, footer text/address,
unsubscribe URL).
Customise the markup by publishing the view:
php artisan vendor:publish --tag=send-it-views
# resources/views/vendor/send-it/default-email/layout.antlers.htmlPoint email.layout at your own view, or set it to null to send content
unwrapped.
The Apple push notification channel sends an entry as a push notification to every app install that has registered with the site. It uses an APNs auth key, so one key covers iOS, iPadOS, macOS and watchOS. Watches receive the notification through the paired iPhone.
SEND_IT_APNS_ENABLED=true
SEND_IT_APNS_TEAM_ID=ABCDE12345 # Apple Developer team id
SEND_IT_APNS_KEY_ID=XYZ9876543 # the auth key's id
SEND_IT_APNS_PRIVATE_KEY_PATH=storage/app/apns/AuthKey_XYZ9876543.p8
# …or base64 of the .p8 file (base64 -i AuthKey_XYZ9876543.p8):
# SEND_IT_APNS_PRIVATE_KEY_BASE64=LS0tLS1CRUdJTi…
# …or inline, with \n for newlines:
# SEND_IT_APNS_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nMIG…\n-----END PRIVATE KEY-----"
SEND_IT_APNS_TOPIC=com.example.app # the app's bundle id
SEND_IT_APNS_TEST_TOKEN= # optional default for test sendsRegistered devices are kept in a JSON file, keyed by token, at
storage/app/send-it/push-devices.json by default. No database is needed. To
have the list backed up with your content, point it at a git-tracked folder:
SEND_IT_APNS_DEVICES_STORE=/path/to/site/content/send-it/push-devices.jsonWrites are locked, so concurrent registrations are safe. A device is only
rewritten when something changes (last_seen is a date), so the file doesn't
churn in git.
Registering devices. Apps register by POSTing JSON to /api/push/devices
(token, plus optional platform, environment (sandbox or production),
app_version, locale, timezone and first_name). To unregister, send
DELETE /api/push/devices/{token}. The route is throttled. Change or disable it
with send-it.channels.apns.devices.route.
Sending. Choose Apple push notification in the Send It action. The
title is the Subject, or the entry title if Subject is empty. The message is
what you type; if you leave it blank, it comes from the entry's excerpt field
(SEND_IT_APNS_BODY_FIELD), or from the start of its content. When tapped
can open the entry's page, which is sent as a url key in the payload. It can
also send an app-specific action, configured under
send-it.channels.apns.actions. There are three delivery options:
- Test: send to one device. Sends right away to one token and shows Apple's response.
- Send to all devices now. Queues a job that sends to every registered
device in parallel batches. Devices that Apple reports as gone
(
Unregistered,BadDeviceToken) are removed. - Schedule for later. Uses the same scheduler as Mailchimp. The entry is published when the send goes out.
Devices built from Xcode register as sandbox. TestFlight and App Store builds
register as production. Each device is sent to the matching APNs server.
Silent pushes. To wake every installed app in the background, for example so it can refresh a feed, dispatch a background push from your own code:
dispatch(\Abigah\SendIt\Jobs\SendPushNotification::background(['feed' => 'news'], 'News feed'));It sends {"aps":{"content-available":1}, "feed":"news"} with
apns-push-type: background at priority 5, with no alert, sound or badge.
iOS throttles these, so send no more than a few an hour.
Implement Abigah\SendIt\Contracts\Channel and register it from any service
provider:
app(\Abigah\SendIt\Channels\ChannelManager::class)
->extend('postmark', fn ($app) => new PostmarkChannel(config('send-it.channels.postmark')));Configured channels automatically appear in the Send It action's channel picker.
MIT