spatie/laravel-mailcoach-postmark-feedback
Add-on for spatie/laravel-mailcoach to process Postmark email feedback for your campaigns. Handles Postmark event/webhook feedback so Mailcoach can track bounces, complaints, and delivery issues automatically.
Installation:
composer require spatie/laravel-mailcoach-postmark-feedback
Publish the config file:
php artisan vendor:publish --provider="Spatie\MailcoachPostmarkFeedback\MailcoachPostmarkFeedbackServiceProvider"
Configuration:
spatie/laravel-mailcoach is installed and configured..env:
POSTMARK_API_TOKEN=your_postmark_token_here
config/mailcoach-postmark-feedback.php:
'webhook_secret' => env('MAILCOACH_POSTMARK_FEEDBACK_WEBHOOK_SECRET'),
'postmark_api_token' => env('POSTMARK_API_TOKEN'),
First Use Case:
Webhook Setup:
routes/web.php:
Route::post('/mailcoach/postmark-feedback', [\Spatie\MailcoachPostmarkFeedback\Http\Controllers\PostmarkFeedbackController::class, 'handle']);
web) and ensure it’s accessible via Postmark’s IP ranges or a secret.Processing Feedback:
Message Opened and Message Clicked events.use Spatie\Mailcoach\Models\Campaign;
use Spatie\Mailcoach\Models\Subscriber;
$campaign = Campaign::find($id);
$subscriber = $campaign->subscribers()->where('email', $email)->first();
Custom Logic:
Spatie\MailcoachPostmarkFeedback\Processors\FeedbackProcessor class.namespace App\Services;
use Spatie\MailcoachPostmarkFeedback\Processors\FeedbackProcessor;
class CustomFeedbackProcessor extends FeedbackProcessor
{
public function handleOpened($campaign, $subscriber, $eventData)
{
// Custom logic here
parent::handleOpened($campaign, $subscriber, $eventData);
}
}
AppServiceProvider:
$this->app->bind(
\Spatie\MailcoachPostmarkFeedback\Processors\FeedbackProcessor::class,
App\Services\CustomFeedbackProcessor::class
);
Batch Processing:
$this->app->bind(
\Spatie\MailcoachPostmarkFeedback\Processors\FeedbackProcessor::class
)->when(Queue::class)->needs(\Spatie\MailcoachPostmarkFeedback\Processors\FeedbackProcessor::class);
Webhook Secret Mismatch:
webhook_secret in config/mailcoach-postmark-feedback.php matches the secret configured in Postmark’s webhook settings.403 Forbidden errors if the secret is incorrect.Duplicate Feedback:
unique() or database constraints to avoid duplicate records:
$exists = \DB::table('mailcoach_feedback')->where('event_uuid', $eventData['MessageID'])->exists();
if (!$exists) {
// Process feedback
}
Timezone Issues:
config/app.php) matches to avoid misaligned logs or reports.Missing Subscribers:
if (!$subscriber) {
\Log::warning("Subscriber not found for email: {$email}");
return;
}
Enable Logging:
config/mailcoach-postmark-feedback.php:
'log_processed_events' => env('MAILCOACH_POSTMARK_FEEDBACK_LOG_EVENTS', false),
storage/logs/laravel.log for processed events.Test Webhooks Locally:
handle endpoint to Postmark for testing:
ngrok http 8000
Postmark Event Validation:
X-Postmark-Signature header matches the expected HMAC-SHA256 signature:
$signature = hash_hmac('sha256', $rawBody, env('POSTMARK_API_TOKEN'));
if (!hash_equals($request->header('X-Postmark-Signature'), $signature)) {
abort(403, 'Invalid signature');
}
Custom Feedback Models:
mailcoach_feedback table or create a pivot table for additional metadata:
Schema::create('mailcoach_feedback_extended', function (Blueprint $table) {
$table->id();
$table->foreignId('feedback_id')->constrained('mailcoach_feedback');
$table->string('custom_field')->nullable();
$table->timestamps();
});
Event Dispatching:
event(new \App\Events\FeedbackProcessed($campaign, $subscriber, $eventData));
Event::listen(\App\Events\FeedbackProcessed::class, function ($event) {
// Trigger analytics, notifications, etc.
});
Rate Limiting:
throttle middleware:
Route::post('/mailcoach/postmark-feedback', [/* ... */])->middleware('throttle:60,1');
How can I help you explore Laravel packages today?