oriceon / mail-tracker
记录和追踪Laravel发出的所有电子邮件
Requires
- php: ^8.2
- aws/aws-php-sns-message-validator: ^1.8
- aws/aws-sdk-php: ^3.258
- guzzlehttp/guzzle: ^7.2
- illuminate/support: ^10.0|^11.0
Requires (Dev)
- mockery/mockery: ^1.4.4
- orchestra/testbench: ^8.0
- phpunit/phpunit: ^9.5.10
Suggests
- fedeisas/laravel-mail-css-inliner: Automatically inlines CSS into all outgoing mail.
README
Mail Tracker会拦截Laravel发出的所有电子邮件,并在其中注入跟踪代码。它还会将渲染后的电子邮件存储到数据库中。
安装
通过Composer
composer require oriceon/mail-tracker
发布配置文件和迁移文件
php artisan vendor:publish --provider="OriceOn\MailTracker\MailTrackerServiceProvider"
运行迁移
php artisan migrate
注意:如果您想使用不同的连接来存储模型,请在运行迁移之前更新mail-tracker.php配置中的connection
。
如果您想使用自己的迁移,可以通过调用MailTracker::ignoreMigrations()
来跳过此库的迁移。例如
// In AppServiceProvider public function boot() { MailTracker::ignoreMigrations(); }
使用方法
安装完成后,所有发出的邮件都会记录到数据库中。以下配置选项在config/mail-tracker.php中可用
- name:设置您的应用名称。
- inject-pixel:设置为true,将跟踪像素注入所有发出的HTML电子邮件。
- track-links:设置为true,将所有锚点href链接重写为包含跟踪链接。该链接将用户带回您的网站,然后记录点击后将其重定向到最终目的地。
- expire-days:电子邮件应保留在数据库中的天数。如果您发送大量邮件,您可能希望它们最终过期。将其设置为0以从不从数据库中清除旧电子邮件。
- route:跟踪URL的路由信息。根据需要设置前缀和中件。
如果您不希望跟踪某些电子邮件,则可以在消息中添加X-No-Track
标题。这将阻止跟踪电子邮件。标题将在发送之前从电子邮件中删除。
\Mail::send('email.test', [], function ($message) { // ... other settings here $message->getHeaders()->addTextHeader('X-No-Track', Str::random(10)); });
将邮件内容存储在文件系统中
默认情况下,电子邮件的内容存储在数据库中的message
列中,以便在发送后查看电子邮件。如果发送了大量电子邮件,这可能会消耗大量内存并减慢数据库的整体速度。可以在配置中指定将内容保存到文件系统中的文件。
'log-message-strategy' => 'filesystem', 'tracker-filesystem' => null 'tracker-filesystem-folder' => 'mail-tracker',
要使用文件系统,需要将log-message-strategy
从database
更改为filesystem
。可以使用tracker-filesystem
指定磁盘,并使用tracker-filesystem-folder
指定文件存储的文件夹。
覆盖模型
在某些情况下,您可能想覆盖内置模型。您可以在AppServiceProvider
中轻松实现,例如
MailTracker::useSentEmailModel(YourOwnSentEmailModel::class); MailTracker::useSentEmailClickModel(YourOwnSentEmailClickModel::class);
您的模型应该实现SentEmailModel
或SentEmailClickModel
接口。此包提供特性以轻松实现自己的模型,而不必重写或复制现有代码。
use Illuminate\Database\Eloquent\Model; use OriceOn\MailTracker\Concerns\IsSentEmailModel; use OriceOn\MailTracker\Contracts\SentEmailModel; class OwnEmailSentModel extends Model implements SentEmailModel { use IsSentEmailModel; protected static $unguarded = true; protected $casts = [ 'meta' => 'collection', 'opened_at' => 'datetime', 'clicked_at' => 'datetime', ]; }
跳过特定电子邮件的跟踪
如果您有不想跟踪的特定电子邮件,则可以向电子邮件添加X-No-Track
标题。这将阻止跟踪电子邮件。标题将在发送之前从电子邮件中删除。
从Laravel 9开始,您可以向Mailable类中添加一个headers方法,这将阻止跟踪像素/点击跟踪应用于Mailable
public function headers() { return [ 'X-No-Track' => Str::random(10), ]; }
跳过反病毒/垃圾邮件过滤器的打开/点击跟踪
一些邮件服务器可能会在投递之前扫描电子邮件,这可能会触发跟踪像素,甚至点击链接。您可以通过添加事件监听器来处理ValidActionEvent。
class ValidUserListener { public function handle(ValidActionEvent $event) { if (in_array(request()->userAgent(), ['Mozilla/5.0', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.246 Mozilla/5.0']) { $event->skip = true; } } }
确保您已将监听器添加到EventServiceProvider中的ValidActionEvent
,如果您没有使用自动事件发现。
关于开发测试的说明
许多人报告说在测试期间跟踪像素不起作用。跟踪像素的问题在于电子邮件客户端正在连接到您的网站以记录查看情况。为了实现这一点,图像必须在客户端可见,并且客户端必须能够连接到您的服务器。
当您处于开发环境(例如使用Valet的.test
域名或只有您的计算机知道的另一个域名)时,您必须在计算机上有一个电子邮件客户端。进一步复杂化的是,Gmail和一些其他基于Web的电子邮件客户端不会直接连接到图像,而是通过代理连接。那个代理不会与您的.test
域名建立连接,因此无法正确跟踪电子邮件。我始终建议在发送电子邮件时在任何开发环境中使用mailtrap.io。这不仅解决了问题(mailtrap.io在电子邮件中不使用代理服务转发图像),而且还保护您免于意外从测试环境发送真实电子邮件。
事件
当发送、查看电子邮件或点击链接时,其跟踪信息将通过OriceOn\MailTracker\Model\SentEmail模型在数据库中计数。为了防止在电子邮件轰炸情况下数据库被压垮,此处理是通过派发的作业到队列中完成的。您可以选择通过mail-tracker.tracker-queue
配置设置来派发这些事件所使用的队列,或者将其留为null
以使用默认队列。通过使用非默认队列,您可以优先考虑应用程序关键任务,而不仅仅是这些跟踪任务。
您可能想要对这些事件进行附加处理,因此在这种情况下会触发事件
- OriceOn\MailTracker\Events\EmailSentEvent
- 公共属性
sent_email
包含SentEmail
模型
- 公共属性
- OriceOn\MailTracker\Events\ViewEmailEvent
- 公共属性
sent_email
包含SentEmail
模型 - 公共属性
ip_address
包含触发事件的IP地址
- 公共属性
- OriceOn\MailTracker\Events\LinkClickedEvent
- 公共属性
sent_email
包含SentEmail
模型 - 公共属性
ip_address
包含触发事件的IP地址 - 公共属性
link_url
包含点击的URL
- 公共属性
如果您使用的是Amazon SNS通知系统,这些事件会触发,以便您可以进行附加处理。
- OriceOn\MailTracker\Events\EmailDeliveredEvent(当您收到“消息已投递”事件时,您可能想在数据库中将电子邮件标记为“良好”或“已投递”)
- 公共属性
sent_email
包含SentEmail
模型 - 公共属性
email_address
包含触发事件的特定地址
- 公共属性
- OriceOn\MailTracker\Events\ComplaintMessageEvent(当您收到投诉时,例如标记为“垃圾邮件”,您可能想从数据库中删除电子邮件)
- 公共属性
sent_email
包含SentEmail
模型 - 公共属性
email_address
包含触发事件的特定地址
- 公共属性
- OriceOn\MailTracker\Events\PermanentBouncedMessageEvent(当您收到永久性退回时,您可能想将电子邮件标记为不良或从数据库中删除)OriceOn\MailTracker\Events\TransientBouncedMessageEvent(当您收到暂时性退回时。检查事件的公共属性中的
bounce_sub_type
和diagnostic_code
以确定在接收到此事件时是否要进行附加处理。)- 公共属性
sent_email
包含SentEmail
模型 - 公共属性
email_address
包含触发事件的特定地址
- 公共属性
要安装事件监听器,您需要创建一个如下所示的文件
<?php namespace App\Listeners; use OriceOn\MailTracker\Events\ViewEmailEvent; class EmailViewed { /** * Create the event listener. * * @return void */ public function __construct() { // } /** * Handle the event. * * @param ViewEmailEvent $event * @return void */ public function handle(ViewEmailEvent $event) { // Access the model using $event->sent_email // Access the IP address that triggered the event using $event->ip_address } }
<?php namespace App\Listeners; use OriceOn\MailTracker\Events\PermanentBouncedMessageEvent; class BouncedEmail { /** * Create the event listener. * * @return void */ public function __construct() { // } /** * Handle the event. * * @param PermanentBouncedMessageEvent $event * @return void */ public function handle(PermanentBouncedMessageEvent $event) { // Access the email address using $event->email_address } }
然后您必须在App\Providers\EventServiceProvider的$listen数组中注册您想要处理的事件
/** * The event listener mappings for the application. * * @var array */ protected $listen = [ 'OriceOn\MailTracker\Events\EmailSentEvent' => [ 'App\Listeners\EmailSent', ], 'OriceOn\MailTracker\Events\ViewEmailEvent' => [ 'App\Listeners\EmailViewed', ], 'OriceOn\MailTracker\Events\LinkClickedEvent' => [ 'App\Listeners\EmailLinkClicked', ], 'OriceOn\MailTracker\Events\EmailDeliveredEvent' => [ 'App\Listeners\EmailDelivered', ], 'OriceOn\MailTracker\Events\ComplaintMessageEvent' => [ 'App\Listeners\EmailComplaint', ], 'OriceOn\MailTracker\Events\PermanentBouncedMessageEvent' => [ 'App\Listeners\BouncedEmail', ], ];
传递数据到事件监听器
通常情况下,您可能需要将发送的电子邮件链接到另一个模型。处理此问题的最佳方法是向您的出站电子邮件添加一个标题,您可以在事件监听器中检索它。以下是一个示例
/** * Send an email and do processing on a model with the email */ \Mail::send('email.test', [], function ($message) use($email, $subject, $name, $model) { $message->from('from@johndoe.com', 'From Name'); $message->sender('sender@johndoe.com', 'Sender Name'); $message->to($email, $name); $message->subject($subject); // Create a custom header that we can later retrieve $message->getHeaders()->addTextHeader('X-Model-ID',$model->id); });
然后在您的事件监听器中
public function handle(EmailSentEvent $event)
{
$tracker = $event->sent_email;
$model_id = $event->sent_email->getHeader('X-Model-ID');
$model = Model::find($model_id);
// Perform your tracking/linking tasks on $model knowing the SentEmail object
}
请注意,您附加到电子邮件的标题实际上会随消息一起发送出去,因此不要存储任何您不想向电子邮件收件人公开的数据。
异常
以下异常可能会抛出。您可以在异常处理器中将它们添加到忽略列表,或者按需处理。
- OriceOn\MailTracker\Exceptions\BadUrlLink - URL链接出现问题。基本上,系统无法正确解析URL链接以发送重定向。
Amazon SES功能
如果您使用Amazon SES,您可以在跟踪中添加一些附加信息。要设置SES回调,首先在SES控制面板中设置您的域下的SES通知。然后通过访问通知主题的管理员面板并为您从管理员页面复制的URL创建订阅来订阅主题。系统应立即响应该订阅请求。如果您喜欢,您可以使用多个订阅(例如,一个用于投递,一个用于退回)。有关在失败消息上触发的事件,请参见上面的内容。为了增加安全性,建议将主题ARN设置到mail-tracker配置中。
贡献
请参阅CONTRIBUTING和CONDUCT以获取详细信息。
安全
如果您发现任何与安全相关的问题,请通过电子邮件oriceon@gmail.com报告,而不是使用问题跟踪器。
鸣谢
感谢原作者,这是一个基于https://github.com/jdavidbakr/mail-tracker的工作。
许可证
MIT许可证(MIT)。有关更多信息,请参阅许可证文件。