zanysoft/mail-tracker is a Laravel package for logs and tracks all outgoing emails from laravel.
It currently has 2 GitHub stars and 278 downloads on Packagist (latest version 2.0).
Install it with composer require zanysoft/mail-tracker.
Discover more Laravel packages by zanysoft
or browse all Laravel packages to compare alternatives.
Last updated
MailTracker will hook into all outgoing emails from Laravel and inject a tracking code into it. It will also store the rendered email in the database. There is also an interface to view sent emails.
First, upgrade to version 2.0 by running:
composer require zanysoft/mail-tracker ~2.0
If you are updating from an earlier version, you will need to update the config file and run the new migrations. For best results, make a backup copy of config/mail-tracker.php and the views in resources/views/vendor/emailTrackingViews (if they exists) to restore any values you have customized, then delete that file and run
php artisan vendor:publish --provider="ZanySoft\MailTracker\MailTrackerServiceProvider" --force
php artisan migrate
Via Composer
$ composer require zanysoft/mail-tracker
Publish the config file and migration
$ php artisan vendor:publish --provider="ZanySoft\MailTracker\MailTrackerServiceProvider"
Run the migration
php artisan migrate
Note: If you would like to use a different connection to store your models,
you should update the mail-tracker.php config entry connection before running the migrations.
If you would like to use your own migrations, you can skip this library migrations by calling MailTracker::ignoreMigrations(). For example:
// In AppServiceProvider
public function register()
{
MailTracker::ignoreMigrations();
}
Once installed, all outgoing mail will be logged to the database. The following config options are available in config/mail-tracker.php:
content database field. Do not forget update it's type from text if you need to make it longer.If you do not wish to have an email tracked, then you can add the X-No-Track header to your message. Put any random string into this header to prevent the tracking from occurring. The header will be removed from the email prior to being sent.
\Mail::send('email.test', [], function ($message) {
// ... other settings here
$message->getHeaders()->addTextHeader('X-No-Track',Str::random(10));
});
By default, the content of an e-mail is stored in the content column in the database so that the e-mail can be viewed after it has been sent.
If a lot of emails are sent, this can consume a lot of memory and slow down the database overall. It is possible to specify in the configuration that the content should be saved to a file in the file system.
'log-content-strategy' => 'filesystem',
'tracker-filesystem' => null
'tracker-filesystem-folder' => 'mail-tracker',
To use the filesystem you need to change the log-content-strategy from database to filesystem.
You can specify the disk with tracker-filesystem and the folder it should store the file in with tracker-filesystem-folder.
In some cases you want to override the built-in models. You can do so easily for example in you AppServiceProvider with
MailTracker::useSentEmailModel(YourOwnSentEmailModel::class);
MailTracker::useSentEmailUrlClickedModel(YourOwnSentEmailUrlClickedModel::class);
Your model should implement to SentEmailModel or SentEmailUrlClickedModel interface. This package provides traits to easily implement your own models but not have to reimplement or copy existing code.
use Illuminate\Database\Eloquent\Model;
use ZanySoft\MailTracker\Concerns\IsSentEmailModel;
use ZanySoft\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',
];
}
If you have a specific email that you do not want to track, you can add the X-No-Track header to the email. This will prevent the email from being tracked. The header will be removed from the email prior to being sent.
In laravel 9 onwards you can introduce a headers method to your Mailable class. This will stop the tracking pixel/click tracking from applying to the Mailable
public function headers()
{
return [
'X-No-Track' => Str::random(10),
];
}
Some mail servers might scan emails before they deliver which can trigger the tracking pixel, or even clicked links. You can add an event listener to the ValidActionEvent to handle this.
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;
}
}
}
Ensure you add the listener to the ValidActionEvent in your EventServiceProvider, if you aren't using automatic event discovery.
When an email is sent, viewed, or a link is clicked, its tracking information is counted in the database using the ZanySoft\MailTracker\Model\SentEmail model. This processing is done via dispatched jobs to the queue in order to prevent the database from being overwhelmed in an email blast situation. You may choose the queue that these events are dispatched via the mail-tracker.tracker-queue config setting, or leave it null to use the default queue. By using a non-default queue, you can prioritize application-critical tasks above these tracking tasks.
You may want to do additional processing on these events, so an event is fired in these cases:
sent_email contains the SentEmail modelsent_email contains the SentEmail modelip_address contains the IP address that was used to trigger the eventsent_email contains the SentEmail modelip_address contains the IP address that was used to trigger the eventlink_url contains the clicked URLIf you are using the Amazon SNS notification system, these events are fired so you can do additional processing.
sent_email contains the SentEmail modelemail_address contains the specific address that was used to trigger the eventsent_email contains the SentEmail modelemail_address contains the specific address that was used to trigger the eventbounce_sub_type and diagnostic_code to determine if you want to do additional processing when this event is received.)
sent_email contains the SentEmail modelemail_address contains the specific address that was used to trigger the eventTo install an event listener, you will want to create a file like the following:
<?php
namespace App\Listeners;
use ZanySoft\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...
}
}
<?php
namespace App\Listeners;
use ZanySoft\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...
}
}
Then you must register the events you want to act on in your \App\Providers\EventServiceProvider $listen array:
/**
* The event listener mappings for the application.
*
* @var array
*/
protected $listen = [
'ZanySoft\MailTracker\Events\EmailSentEvent' => [
'App\Listeners\EmailSent',
],
'ZanySoft\MailTracker\Events\ViewEmailEvent' => [
'App\Listeners\EmailViewed',
],
'ZanySoft\MailTracker\Events\LinkClickedEvent' => [
'App\Listeners\EmailLinkClicked',
],
'ZanySoft\MailTracker\Events\EmailDeliveredEvent' => [
'App\Listeners\EmailDelivered',
],
'ZanySoft\MailTracker\Events\ComplaintMessageEvent' => [
'App\Listeners\EmailComplaint',
],
'ZanySoft\MailTracker\Events\PermanentBouncedMessageEvent' => [
'App\Listeners\BouncedEmail',
],
];
Often times you may need to link a sent email to another model. The best way to handle this is to add a header to your outgoing email that you can retrieve in your event listener. Here is an example:
/**
* 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('[email protected]', 'From Name');
$message->sender('[email protected]', 'Sender Name');
$message->to($email, $name);
$message->subject($subject);
// Create a custom header that we can later retrieve
$message->getHeaders()->addTextHeader("X-MODEL", "Model Name");
$message->getHeaders()->addTextHeader('X-Model-ID',$model->id);
});
and then in your event listener:
public function handle(EmailSentEvent $event)
{
$tracker = $event->sent_email;
$model_id = $event->sent_email->getHeader('X-Model-ID');
$model_name = $event->sent_email->getHeader('X-Model');
$model = app("App\\$model_name")->find($model_id);
// Perform your tracking/linking tasks on $model knowing the SentEmail object
}
Note that the headers you are attaching to the email are actually going out with the message, so do not store any data that you wouldn't want to expose to your email recipients.
The following exceptions may be thrown. You may add them to your ignore list in your exception handler, or handle them as you wish.
If you use Amazon SES, you can add some additional information to your tracking. To set up the SES callbacks, first set up SES notifications under your domain in the SES control panel. Then subscribe to the topic by going to the admin panel of the notification topic and creating a subscription for the URL you copied from the admin page. The system should immediately respond to the subscription request. If you like, you can use multiple subscriptions (i.e. one for delivery, one for bounces). See above for events that are fired on a failed message. For added security, it is recommended to set the topic ARN into the mail-tracker config.
When you run the php artisan vendor:publish command, simple views will add to your resources/views/vendor/emailTrakingViews that you can customize.
MailTracker comes with a built-in administration area. The default configuration that is published with the package puts it behind the can:see-sent-emails middleware; you may create a gate for this rule or change it to use one of your own. You may also change the default prefix as well as disable the admin routes completely.
The route name is 'mailTracker_Index'. The standard admin panel route is located at /email-manager. You can use route names to include them into your existing admin menu. You can customize your route in the config file. You can see all sent emails, total opens, total urls clicks, show individuals emails and show the urls clicked details.
All views (email tamplates, panel) can be customized in resources/views/vendor/emailTrakingViews.
If you discover any security related issues, please [email protected] instead of using the issue tracker.
The MIT License (MIT). Please see License File for more information.