henryavila/email-tracking
最新稳定版本:v7.0.0
Composer 安装命令:
composer require henryavila/email-tracking
包简介
Track e-mail delivery with Mailgun Hooks. All data are stored in the database on Email model
README 文档
README
Track email delivery, opens, clicks, and more using Mailgun webhooks. All data is stored in your database for easy querying and analytics.
✨ Features
- 📧 Complete Email Tracking - Track sent, delivered, opened, clicked, bounced, and failed emails
- 🔗 Model Association - Link emails to any Eloquent model (User, Order, Invoice, etc.)
- 🎯 Email Categorization - Classify emails by type (transactional, marketing, notifications, etc.)
- 📊 Built-in Analytics - Query delivery rates, open rates, click rates by email type
- 🪝 Mailgun Webhooks - Automatic event processing from Mailgun
- 🔒 Secure Webhooks - Signature verification for webhook security
- 💾 Database Storage - All email data stored in your database
- 🧪 Fully Tested - Comprehensive test suite included
- 📱 Laravel 11+ & 12 - Modern Laravel support with latest features
📋 Requirements
- PHP 8.2, 8.3, or 8.4 (PHP 8.5 support planned for v7.1.0)
- Laravel 11.0 or higher (Laravel 11 LTS and Laravel 12 supported)
- Mailgun account
📊 Code Coverage
This package maintains high test coverage with comprehensive unit and integration tests. All new features are fully tested before release.
📦 Installation
1. Install via Composer
composer require henryavila/email-tracking
2. Publish and Run Migrations
php artisan vendor:publish --tag="email-tracking-migrations"
php artisan migrate
3. Publish Configuration (Optional)
php artisan vendor:publish --tag="email-tracking-config"
4. Configure Mailgun
Setup Laravel Mail with Mailgun driver. See Laravel Mail Documentation.
Add to your .env file:
MAIL_MAILER=mailgun MAILGUN_DOMAIN=yourdomain.com MAILGUN_SECRET=key-99999999999999999999999999999999
5. Setup Mailgun Webhook
In your Mailgun dashboard, add a webhook pointing to:
https://yourdomain.com/webhooks/mailgun
⚙️ Configuration
Register Event Listener
The package needs to listen for sent emails to track them.
Add to AppServiceProvider::boot():
public function boot(): void { \Illuminate\Support\Facades\Event::listen( events: \Illuminate\Mail\Events\MessageSent::class, listener: \HenryAvila\EmailTracking\Listeners\LogEmailSentListener::class ); }
Configuration File
The published config file (config/email-tracking.php) allows customization:
return [ /** * Database connection for Email model (optional) * If null, uses default connection */ 'email-db-connection' => null, /** * Save HTML body of sent emails */ 'log-body-html' => true, /** * Save text body of sent emails */ 'log-body-txt' => true, ];
🚀 Usage
Basic Mailable with Tracking
Extend TrackableMail instead of Laravel's Mailable:
use HenryAvila\EmailTracking\Mail\TrackableMail; class OrderShippedMail extends TrackableMail { public function __construct($order) { $viewData = [ 'order' => $order, 'trackingNumber' => $order->tracking_number, ]; parent::__construct($order, 'emails.order-shipped', $viewData); } }
Send the email:
$order = Order::find(1); Mail::to($order->customer)->send(new OrderShippedMail($order));
The email will be automatically tracked and linked to the $order model.
Trackable Notifications
For notifications, use TrackableNotificationMailMessage:
use HenryAvila\EmailTracking\Notifications\TrackableNotificationMailMessage; class OrderShippedNotification extends Notification { public function __construct(protected Order $order) { } public function toMail($notifiable): MailMessage { return (new TrackableNotificationMailMessage($this->order)) ->subject('Your order has been shipped!') ->line('Your order #' . $this->order->number . ' is on its way.') ->action('Track Shipment', url('/orders/' . $this->order->id)) ->line('Thank you for your purchase!'); } }
Email Type Classification (v7.0.0+)
Categorize emails for better organization and analytics.
1. Create Email Type Enum
<?php namespace App\Enums; enum EmailType: string { case TRANSACTIONAL = 'transactional'; case MARKETING = 'marketing'; case NOTIFICATION = 'notification'; case ADMINISTRATIVE = 'administrative'; case SYSTEM = 'system'; }
2. Implement in Mailable
use App\Enums\EmailType; use HenryAvila\EmailTracking\Mail\TrackableMail; class OrderConfirmationMail extends TrackableMail { protected function getEmailType(): EmailType { return EmailType::TRANSACTIONAL; } }
3. Query by Type
use App\Models\Email; // Get all transactional emails $transactional = Email::where('email_type', 'transactional')->get(); // Add convenient scopes to your Email model Email::transactional()->delivered()->get(); // Analytics by type $stats = Email::select('email_type') ->selectRaw('count(*) as total, sum(opened) as opens') ->groupBy('email_type') ->get();
Learn more: See Email Type Classification Documentation for complete guide with examples.
Querying Emails
use HenryAvila\EmailTracking\Models\Email; // Get all emails for a model $order = Order::find(1); $emails = $order->emails; // Requires ModelWithEmailsSenderTrait on Order model // Query email status $delivered = Email::whereNotNull('delivered_at')->get(); $opened = Email::where('opened', '>', 0)->get(); $clicked = Email::where('clicked', '>', 0)->get(); $failed = Email::whereNotNull('failed_at')->get(); // Get recent emails $recentEmails = Email::orderBy('created_at', 'desc')->limit(10)->get(); // Search by recipient $userEmails = Email::where('to', 'like', '%user@example.com%')->get();
Email Analytics
// Delivery rate $totalSent = Email::count(); $delivered = Email::whereNotNull('delivered_at')->count(); $deliveryRate = ($delivered / $totalSent) * 100; // Open rate $opened = Email::where('opened', '>', 0)->count(); $openRate = ($opened / $delivered) * 100; // Click rate $clicked = Email::where('clicked', '>', 0)->count(); $clickRate = ($clicked / $delivered) * 100;
🪝 Webhook Events
When Mailgun processes an email event (delivered, opened, clicked, etc.), the EmailWebhookProcessed event is dispatched.
Listening to Webhook Events
Create a listener:
<?php namespace App\Listeners; use HenryAvila\EmailTracking\Events\EmailWebhookProcessed; use HenryAvila\EmailTracking\Events\Email\DeliveredEmailEvent; use HenryAvila\EmailTracking\Events\Email\OpenedEmailEvent; class MailgunWebhookProcessedListener { public function handle(EmailWebhookProcessed $event): void { match ($event->emailEvent::class) { DeliveredEmailEvent::class => $this->handleDelivered($event->emailEvent), OpenedEmailEvent::class => $this->handleOpened($event->emailEvent), // Add other events as needed default => null, }; } private function handleDelivered(DeliveredEmailEvent $event): void { // Your custom logic when email is delivered $email = $event->email; logger()->info("Email delivered to {$email->to}"); } private function handleOpened(OpenedEmailEvent $event): void { // Your custom logic when email is opened $email = $event->email; logger()->info("Email opened by {$email->to}"); } }
Register the listener in EventServiceProvider:
protected $listen = [ \HenryAvila\EmailTracking\Events\EmailWebhookProcessed::class => [ \App\Listeners\MailgunWebhookProcessedListener::class, ], ];
Available Event Types
AcceptedEmailEvent- Email accepted for deliveryDeliveredEmailEvent- Email successfully deliveredOpenedEmailEvent- Email opened by recipientClickedEmailEvent- Link clicked in emailPermanentFailureEmailEvent- Permanent delivery failure (bounce)TemporaryFailureEmailEvent- Temporary delivery issueSpamComplaintsEmailEvent- Marked as spamUnsubscribeEmailEvent- Unsubscribe request
🔧 Advanced Usage
Model Association
Add the trait to models that send emails:
use HenryAvila\EmailTracking\Traits\ModelWithEmailsSenderTrait; class Order extends Model { use ModelWithEmailsSenderTrait; }
Now you can access emails:
$order = Order::find(1); $emails = $order->emails; // All emails sent for this order
Custom Email Model
Extend the base Email model to add your own methods:
namespace App\Models; use App\Enums\EmailType; use Illuminate\Database\Eloquent\Builder; class Email extends \HenryAvila\EmailTracking\Models\Email { protected function casts(): array { return array_merge(parent::casts(), [ 'email_type' => EmailType::class, ]); } public function scopeTransactional(Builder $query): Builder { return $query->where('email_type', EmailType::TRANSACTIONAL); } public function scopeDelivered(Builder $query): Builder { return $query->whereNotNull('delivered_at'); } public function scopeRecent(Builder $query, int $days = 7): Builder { return $query->where('created_at', '>=', now()->subDays($days)); } }
Use your custom model by binding it in a service provider:
$this->app->bind( \HenryAvila\EmailTracking\Models\Email::class, \App\Models\Email::class );
📚 Documentation
- Email Type Classification Guide - Complete guide for email categorization
- Changelog - Version history and upgrade guides
🧪 Testing
composer test
📝 Changelog
Please see CHANGELOG for more information on what has changed recently.
🤝 Contributing
Please see CONTRIBUTING for details.
🔒 Security Vulnerabilities
Please review our security policy on how to report security vulnerabilities.
🙏 Credits
📄 License
The MIT License (MIT). Please see License File for more information.
💡 Upgrade Guides
Upgrading to 7.0.0 from 6.x - BREAKING CHANGES
Version 7.0.0 drops support for PHP 8.1 and Laravel 9-10.
Requirements
- PHP 8.2+ (was 8.1+)
- Laravel 11+ (was 9+)
Why This Change?
Laravel 10 has reached end-of-life and contains known security vulnerabilities. This major version ensures your application uses secure, actively maintained Laravel versions.
Migration Path
# 1. Update your Laravel application to 11.x first composer require laravel/framework:^11.0 # 2. Update PHP to 8.2 or higher (if needed) # 3. Update email-tracking package composer require henryavila/email-tracking:^7.0
Code Changes Required
If you were using Laravel 10's EventServiceProvider pattern, migrate to Laravel 11's AppServiceProvider:
Before (Laravel 10):
// EventServiceProvider protected $listen = [ \Illuminate\Mail\Events\MessageSent::class => [ \HenryAvila\EmailTracking\Listeners\LogEmailSentListener::class, ], ];
After (Laravel 11):
// AppServiceProvider::boot() \Illuminate\Support\Facades\Event::listen( events: \Illuminate\Mail\Events\MessageSent::class, listener: \HenryAvila\EmailTracking\Listeners\LogEmailSentListener::class );
Testing
The package now uses:
- Pest 3.x for testing
- PHPUnit 11.x as test runner
- PHPStan Level 4 for static analysis
All tests pass on PHP 8.2, 8.3, 8.4, and 8.5 with Laravel 11 and 12.
Upgrading to 6.2.0 from earlier versions (Legacy)
Note: If you're on v6.x, upgrade directly to v7.0.0 using the guide above.
A new migration was added to track email events.
php artisan vendor:publish --tag="email-tracking-migrations"
php artisan migrate
🆘 Support
⭐ Show Your Support
Give a ⭐️ if this project helped you!
统计信息
- 总下载量: 3.21k
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 7
- 点击次数: 0
- 依赖项目数: 1
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2023-08-10