silvershop-suite / newsletter-campaignmonitor
Campaign Monitor ESP adapter for silvershop-suite/newsletter: syncs subscribers to a Campaign Monitor list via a thin Guzzle client, with a webhook back to the local list.
Package info
github.com/silvershop-suite/silvershop-newsletter-campaignmonitor
Type:silverstripe-vendormodule
pkg:composer/silvershop-suite/newsletter-campaignmonitor
Requires
- php: ^8.3
- guzzlehttp/guzzle: ^7
- silvershop-suite/newsletter: dev-main
- silverstripe/cms: ^6
- silverstripe/framework: ^6
Requires (Dev)
- cambis/silverstan: ^2.1
- phpunit/phpunit: ^11.3
- silverstripe/sqlite3: ^4
- squizlabs/php_codesniffer: ^3.7
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-19 19:54:39 UTC
README
Campaign Monitor ESP adapter for
silvershop-suite/newsletter. It implements the core's
NewsletterProvider contract with a thin Guzzle client (no heavy official SDK) and maps subscriber changes to
the Campaign Monitor API v3.3, plus a webhook back to the local list.
The core owns capture, consent and double opt-in; this adapter just syncs confirmed subscribers to a Campaign Monitor list and keeps the local status in step via webhooks.
Requirements
silvershop-suite/newsletterdev-main(the core — not on Packagist, see Installation)guzzlehttp/guzzle^7silverstripe/framework^6,silverstripe/cms^6, PHP 8.3 / 8.4
silvershop-suite/newsletter hard-requires symbiote/silverstripe-queuedjobs, so the queued sync runner comes in
transitively.
Installation
silvershop-suite/newsletter is an RVXD module (not published to Packagist), so it is resolved from a composer
repositories entry. The shipped composer.json uses the VCS form:
"repositories": [ { "type": "vcs", "url": "https://github.com/RVXD/silvershop-newsletter.git" } ]
Then:
composer require silvershop-suite/newsletter-campaignmonitor:dev-main
(A private newsletter repo needs a GitHub token with repo scope, e.g. composer config -g github-oauth.github.com <token>.)
Local development (core not yet pushed)
When you are developing both modules side by side and silvershop-suite/newsletter isn't published yet, point the
adapter at your local checkout with a path repository instead of (or in addition to) the VCS entry — this is
how the dev site and the standalone clean-room resolve it:
"repositories": [ { "type": "path", "url": "../silvershop-newsletter" } ]
Configuration
Credentials come from the environment (.env):
SS_CAMPAIGNMONITOR_API_KEY="your-api-key"
SS_CAMPAIGNMONITOR_LIST_ID="your-list-id"
SS_CAMPAIGNMONITOR_WEBHOOK_SECRET="optional-shared-secret"
Then make Campaign Monitor the active provider:
SilverShop\Newsletter\Provider\NewsletterProviderRegistry: active: campaignmonitor
Optionally map subscription merge fields to Campaign Monitor custom fields (which must already exist on the list — Name/first+surname is sent natively):
SilverShop\Newsletter\CampaignMonitor\CampaignMonitorProvider: custom_field_map: Locale: '[locale]'
Configure the Campaign Monitor list as SINGLE opt-in. The core already performs double opt-in (it emails the subscriber a confirm link and only syncs them once confirmed). If the Campaign Monitor list is also set to confirmed opt-in, subscribers would receive a second confirmation email. Single opt-in avoids the double-confirm.
How it maps
| Operation | Campaign Monitor API v3.3 |
|---|---|
| subscribe / update | POST subscribers/{listid}.json (add-or-update; Resubscribe: true) |
| unsubscribe | POST subscribers/{listid}/unsubscribe.json |
full resync (sake tasks:NewsletterResync --run) |
add-or-update for every locally-subscribed record |
Authentication is HTTP Basic with the API key as the username.
Webhook (Campaign Monitor → local)
Point a Campaign Monitor webhook at:
https://your-shop.example/newsletter/webhook/campaignmonitor
(append ?secret=<SS_CAMPAIGNMONITOR_WEBHOOK_SECRET> if you set a secret). The core's webhook controller calls
this adapter's verifyWebhook() + parseWebhook(), which map Campaign Monitor events to the local status:
| Campaign Monitor event | Local status |
|---|---|
| Subscribe | Subscribed |
| Update | Subscribed |
| Deactivate / Unsubscribe | Unsubscribed |
| Bounce | Bounced |
Development
composer install composer run lint # phpcs (PSR-12) composer run stan # phpstan (cambis/silverstan, level 5) composer run test # phpunit — uses a FakeCampaignMonitorClient, no live HTTP
License
BSD-3-Clause.
Credits
Built and maintained by Remy Vaartjes (remy@xd.nl) — part of the SilverShop-Suite.