spatie/mailcoach-sdk-php
PHP SDK for the Mailcoach API (self-hosted v6+ and Mailcoach Cloud). Manage email lists, subscribers, and campaigns: create and send campaigns, send tests, and browse paginated resources with an easy next() workflow.
Installation:
composer require spatie/mailcoach-sdk-php guzzlehttp/guzzle
Initialize Client:
use Spatie\MailcoachSdk\Mailcoach;
$mailcoach = new Mailcoach(
env('MAILCOACH_API_KEY'),
env('MAILCOACH_API_ENDPOINT') // e.g., 'https://your-mailcoach-instance.app/api'
);
First Use Case: Fetch and iterate through all email lists (paginated):
$emailLists = $mailcoach->emailLists();
foreach ($emailLists as $list) {
echo $list->name;
}
// Handle pagination
while ($emailLists->next()) {
foreach ($emailLists as $list) {
echo $list->name;
}
}
Mailcoach → Settings → API Tokens.EmailList, Subscriber, Campaign, and Automation classes.next(), results(), and total() for large datasets.Bulk Subscriber Management:
// Add subscribers from a CSV
$csv = collect(file('subscribers.csv'));
foreach ($csv->skip(1) as $row) {
$mailcoach->createSubscriber('list-uuid', [
'email' => $row[0],
'first_name' => $row[1],
]);
}
Tagging Logic:
// Tag subscribers based on custom logic
$subscribers = $mailcoach->emailList('list-uuid')->subscribers(['tag' => 'active']);
foreach ($subscribers as $subscriber) {
if ($subscriber->last_opened_at > now()->subDays(7)) {
$subscriber->addTags(['engaged']);
}
}
Dynamic Campaign Creation:
// Create a campaign with template fields
$campaign = $mailcoach->createCampaign([
'email_list_uuid' => 'list-uuid',
'name' => 'Weekly Digest',
'template_uuid' => 'template-uuid',
'fields' => [
'title' => 'Your Weekly Updates',
'content' => '# Hello ' . $subscriber->first_name,
],
]);
Scheduling with Laravel:
// Schedule a campaign to send at a specific time
$campaign->sendAt(\Carbon\Carbon::now()->addHours(2));
Service Provider Binding:
// app/Providers/MailcoachServiceProvider.php
public function register()
{
$this->app->singleton(Mailcoach::class, function ($app) {
return new Mailcoach(
config('mailcoach.api_key'),
config('mailcoach.api_endpoint')
);
});
}
Event-Driven Workflows:
// Trigger automation on user signup
event(new UserRegistered($user));
// In listener:
$mailcoach->triggerAutomation('welcome-automation-uuid', [$subscriber->uuid]);
Batch Processing:
$subscribers = $mailcoach->emailList('list-uuid')->subscribers();
while ($subscribers->next()) {
foreach ($subscribers as $subscriber) {
// Process in batches (e.g., 100 at a time)
if ($subscriber->isDirty()) {
$subscriber->save();
}
}
}
Cursor-Based Pagination (for large datasets):
$cursor = null;
do {
$subscribers = $mailcoach->emailList('list-uuid')->subscribers(['cursor' => $cursor]);
foreach ($subscribers as $subscriber) {
// Process
}
$cursor = $subscribers->nextUrl(); // Update cursor
} while ($cursor);
API Rate Limiting:
Spatie\MailcoachSdk\Exceptions\RateLimitedException.try {
$campaign->send();
} catch (RateLimitedException $e) {
sleep($e->retryAfter);
retry();
}
Pagination Edge Cases:
next() returns null before looping:
while ($subscribers = $subscribers->next()) { // Correct
// ...
}
total() to log progress for large datasets.Subscriber Email Quirks:
+ (e.g., user+tag@example.com) may fail to fetch.$subscribers = $mailcoach->subscribers('list-uuid', ['email' => urlencode('user+tag@example.com')]);
Campaign Fields:
$template = $mailcoach->template('template-uuid');
dd($template->fields); // Inspect required fields
Enable Guzzle Debugging:
$mailcoach = new Mailcoach($apiKey, $endpoint, [
'debug' => true,
'handler' => GuzzleHttp\HandlerStack::create(new \GuzzleHttp\Handler\CurlHandler())
]);
Log API Responses:
$mailcoach->getHttpClient()->getEmitter()->attach(
new \GuzzleHttp\Middleware::tap(function ($request, $response, $next) {
\Log::debug('Mailcoach API Response', [
'status' => $response->getStatusCode(),
'body' => (string) $response->getBody(),
]);
})
);
Custom HTTP Client: Override the default Guzzle client for middleware (e.g., auth, logging):
$mailcoach = new Mailcoach($apiKey, $endpoint, [
'http_client' => new \GuzzleHttp\Client([
'headers' => ['X-Custom-Header' => 'value'],
]),
]);
Resource Decorators:
Extend resource classes (e.g., Subscriber) to add custom methods:
class CustomSubscriber extends \Spatie\MailcoachSdk\Resources\Subscriber
{
public function isActive()
{
return $this->status === 'subscribed' && $this->unsubscribed_at === null;
}
}
Note: Requires patching the SDK or using a decorator pattern.
Webhook Handling: For automation triggers, validate subscriber UUIDs:
$validUuids = $mailcoach->subscribers()->pluck('uuid');
if (!collect($triggerData)->every(fn ($uuid) => in_array($uuid, $validUuids))) {
throw new \InvalidArgumentException('Invalid subscriber UUIDs');
}
Self-Hosted vs. Cloud:
https://mailcoach.app/api./api (e.g., https://your-instance.com/api).Environment Variables:
.env:
MAILCOACH_API_KEY=your_key_here
MAILCOACH_API_ENDPOINT=https://your-instance.com/api
Template UUIDs:
$templates = $mailcoach->templates();
Batch Operations:
chunk() for large subscriber updates:
$subscribers->chunk(50)->each(function ($chunk) {
foreach ($chunk as $subscriber) {
$subscriber->addTags(['bulk-tag']);
$subscriber->save();
}
});
Lazy Loading:
// Bad: Loads all 10,000 subscribers
$allSubscribers = $mailcoach->emailList('list-uuid')->subscribers()->results();
// Good: Process page-by-page
$subscribers = $mailcoach->emailList('list-uuid')->subscribers();
while ($subscribers->next()) {
foreach ($subscribers as $subscriber) {
// Process one page
}
}
How can I help you explore Laravel packages today?