Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

A package to keep track of outgoing emails in your Laravel application.

License

NotificationsYou must be signed in to change notification settings

stefanzweifel/laravel-sends

Repository files navigation

Latest Version on Packagistrun-testsCheck & fix stylingTotal Downloads

This package helps you to keep track of outgoing emails in your Laravel application. In addition, you can associate Models to the sent out emails.

Here are a few short examples what you can do:

// An email is sent to $user. The passed $product and $user models will be// associated with the sent out email generated by the `ProductReviewMail` mailable.Mail::to($user)->send(newProductReviewMail($product,$user));

In your application, you can then fetch all sent out emails for the user or the product.

$user->sends()->get();$product->sends()->get();

Or you can fetch all sent out emails for the given Mailable class.

Send::forMailClass(ProductReviewMail::class)->get();

EachSend-model holds the following information:

  • FQN of mailable class
  • subject
  • from address
  • reply to address
  • to address
  • cc adresses
  • bcc adresses

Additionally, thesends-table has the following columns which can be filled by your own application (learn more).

  • delivered_at
  • last_opened_at
  • opens
  • clicks
  • last_clicked_at
  • complained_at
  • bounced_at
  • permanent_bounced_at
  • rejected_at

Installation

You can install the package via composer:

composer require wnx/laravel-sends

Then, publish and run the migrations:

php artisan vendor:publish --tag="sends-migrations"php artisan migrate

Optionally, you can publish the config file with:

php artisan vendor:publish --tag="sends-config"

This is the contents of the published config file:

return [/*     * The fully qualified class name of the `Send` model.     */'send_model' => \Wnx\Sends\Models\Send::class,/**     * If set to true, the content of sent mails is saved to the database.     */'store_content' =>env('SENDS_STORE_CONTENT',false),'headers' => [/**         * Header containing the encrypted FQN of the mailable class.         */'mail_class' =>env('SENDS_HEADERS_MAIL_CLASS','X-Laravel-Mail-Class'),/**         * Header containing an encrypted JSON object with information which         * Eloquent models are associated with the mailable class.         */'models' =>env('SENDS_HEADERS_MAIL_MODELS','X-Laravel-Mail-Models'),/**         * Header containing unique ID of the sent out mailable class.         * Set this to `Message-ID`, if you want to use the Message ID as the unique ID identifing the sent mail.         */'send_uuid' =>env('SENDS_HEADERS_SEND_UUID','X-Laravel-Send-UUID'),    ],];

Usage

After the installation is done, update your applicationsEventServiceProvider to listen to theMessageSent event. Add theStoreOutgoingMailListener-class as a listener.

// app/Providers/EventServiceProvider.phpprotected$listen = [// ...    \Illuminate\Mail\Events\MessageSent::class => [        \Wnx\Sends\Listeners\StoreOutgoingMailListener::class,    ],]

The metadata ofall outgoing emails created by mailables or notifications is now being stored in thesends-table. (Note that you can only associate models to mailables; but not to notifiations)

Read further to learn how to store the name and how to associate models with a Mailable class.

Store Mailable class name on Send Model

By default the Event Listener stores the mails subject and the recipient adresses. That's nice, but we can do better.It can be beneficial for your application to know which Mailable class triggered the sent email.

To store this information, add theStoreMailables-trait to your Mailable classes like below. You now have access to a couple of helper methods.

Depending on how you write Mailables, there a different ways to use these new methods.Call thestoreClassName-method inside thebuild-method of your Mailable.

class ProductReviewMailextends Mailable{use SerializesModels;use StoreMailables;publicfunction__construct(publicUser$user,publicProduct$product)    {    }publicfunctionbuild()    {return$this            ->storeClassName()            ->view('emails.products.review')            ->subject("$this->product->name waits for your review");    }}

If you use the Mailable syntax introduced in Laravel v9.35, you can either use$this->storeClassName() in theheaders-method or pass$this->getMailClassHeader()->toArray() to theHeader object.

class ProductReviewMailextends Mailable{use SerializesModels;use StoreMailables;publicfunction__construct(publicUser$user,publicProduct$product    ) { }// .../**     * @return \Illuminate\Mail\Mailables\Headers     */publicfunctionheaders()    {// Call storeClassName() and let the package take care of adding the// header to the outgoing mail.$this->storeClassName();// Or – if you want more control – use the getMailClassHeader() method// to get a Header instance and merge it with your own headers.returnnewHeaders(            text: ['X-Custom-Header' =>'Custom Value',                ...$this->getMailClassHeader()->toArray(),            ],        );    }}

The method will add aX-Laravel-Mail-Class-header to the outgoing email containing the fully qualified name (FQN) of the Mailable class as an encrypted string. (eg.App\Mails\ProductReviewMail). Update theSENDS_HEADERS_MAIL_CLASS-env variable to adjust the header name. (See config for details).

The package's event listener will then look for the header, decrypt the value and store it in the database.

Associate Sends with Related Models

Now that you already keep track of all outgoing emails, wouldn't it be great if you could access the records from an associated Model?In the example above we send aProductReviewMail to a user. Wouldn't it be great to see how many emails you have sent for a givenProduct-model?

To achieve this, you have to add theHasSends-interface and theHasSendsTrait trait to your models.

useWnx\Sends\Contracts\HasSends;useWnx\Sends\Support\HasSendsTrait;class Productextends Modelimplements HasSends{use HasSendsTrait;}

You can now call theassociateWith()-method within thebuild()-method. Pass the Models you want to associate with the Mailable class to the method as arguments. Instead of passing the Models as arguments, you can also pass them as an array.

class ProductReviewMailextends Mailable{use SerializesModels;use StoreMailables;publicfunction__construct(privateUser$user,privateProduct$product    ) { }publicfunctionbuild()    {return$this            ->storeClassName()            ->associateWith($this->product)// ->associateWith([$this->product])            ->view('emails.products.review')            ->subject("$this->user->name,$this->product->name waits for your review");    }}

If you're using the Mailable syntax introduced in Laravel v9.35, you can callassociateWith() orgetMailModelsHeader() in theheaders-method too.

class ProductReviewMailextends Mailable{use SerializesModels;use StoreMailables;publicfunction__construct(privateUser$user,privateProduct$product    ) { }// .../**     * @return \Illuminate\Mail\Mailables\Headers     */publicfunctionheaders()    {// Call associateWith() and the package automatically associates the public// properties with this mailable.$this->associateWith($this->user);$this->associateWith([$this->product]);// Or – if you want more control – use the getMailModelsHeader() method// to get a Header instance and merge it with your own headers.returnnewHeaders(            text: ['X-Custom-Header' =>'Custom Value',                ...$this->getMailModelsHeader($this->user)->toArray(),                ...$this->getMailModelsHeader([$this->product])->toArray(),            ],        );    }}

You can now access the sent out emails from the product'ssends-relationship.

$product->sends()->get();

Automatically associate Models with Mailables

If you do not pass an argument to theassociateWith-method, the package will automatically associate all public properties which implement theHasSends-interface with the Mailable class. 🪄

In the example below, theProductReviewMail-Mailable will automatically be associated with the$product Model, asProduct implements theHasSends interface. The$user model will be ignored, as it's declared as a private property.

class ProductReviewMailextends Mailable{use SerializesModels;use StoreMailables;publicfunction__construct(privateUser$user,publicProduct$product    ) { }publicfunctionbuild()    {return$this            ->associateWith()            ->view('emails.products.review')            ->subject("$this->user->name,$this->product->name waits for your review");    }}

If you're using the Mailable syntax introduced in Laravel v9.35, you can callassociateWith() orgetMailModelsHeader() in theheaders-method.

class ProductReviewMailextends Mailable{use SerializesModels;use StoreMailables;publicfunction__construct(privateUser$user,publicProduct$product    ) { }// .../**     * @return \Illuminate\Mail\Mailables\Headers     */publicfunctionheaders()    {// Call associateWith() and the package automatically associates the public// properties with this mailable.$this->associateWith();// Or – if you want more control – use the getMailModelsHeader() method// to get a Header instance and merge it with your own headers.returnnewHeaders(            text: ['X-Custom-Header' =>'Custom Value',                ...$this->getMailModelsHeader()->toArray(),            ],        );    }}

Attach custom Message ID to Mails

If you're sending emails through AWS SES or a similar service, you might want to identify the sent email in the future (for example when a webhook for the "Delivered"-event is sent to your application).

The package comes with an event listener helping you here. Update the EventServiceProvider to listen to theMessageSending event and add theAttachSendUuidListener as a listener.AX-Laravel-Message-UUID header will be attached to all outgoing emails. The header contains a UUID value. (This value can not be compared to theMessage-ID defined inRFC 2392)
You can then use the value ofX-Laravel-Message-UUID or$send->uuid later in your application.

// app/Providers/EventServiceProvider.phpprotected$listen = [// ...    \Illuminate\Mail\Events\MessageSending::class => [        \Wnx\Sends\Listeners\AttachSendUuidListener::class,    ],]

(If you want to store the value ofMessage-ID in your database, do not add the event listener but update theSENDS_HEADERS_SEND_UUID-env variable toMessage-ID. TheStoreOutgoingMailListener will then store theMessage-ID in the database.)

Store Content of Mails

By default, the package does not store the content of sent out emails. By setting thesends.store_content configuration value totrue, the body of all outgoing mails is stored in thecontent-column in thesends database table.

/** * If set to true, the contet of sent mails is saved to the database. */'store_content' => true,
SENDS_STORE_CONTENT=true

Customize Attributes stored in Send Models

If you need to store more attributes with yourSend-model, you can extend theStoreOutgoingMailListener and override thegetSendAttributes-method.

For example, let's say we would like to store anaudience-value with each sent out email. We create a new Event Listener calledCustomStoreOutgoingMailListener and use the class as Listener to theMessageSent-event.

OurEventServiceProvider would look like this.

// app/Providers/EventServiceProvider.phpprotected$listen = [// ...    \Illuminate\Mail\Events\MessageSent::class => [        \App\Listeners\CustomStoreOutgoingMailListener::class,    ],]

The Listener itself would look like the code below. We extendWnx\Sends\Listeners\StoreOutgoingMailListener and overridegetSendAttributes. We merge the$defaultAttributes with our custom attributes we want to store. In the example below we store anaudience value.

<?phpnamespaceApp\Listeners;useIlluminate\Mail\Events\MessageSent;useWnx\Sends\Listeners\StoreOutgoingMailListener;class CustomStoreOutgoingMailListenerextends StoreOutgoingMailListener{protectedfunctiongetSendAttributes(MessageSent$event,array$defaultAttributes):array    {returnarray_merge($defaultAttributes, ['audience' =>$this->getAudience($event),        ]);    }

Prune Send Models

By default,Send-models are kept forever in your database. If your application sends thousands of emails per day, you might want to prune records after a couple of days or months.

To do that, use theprunable feature of Laravel.

Create a newSend-model in yourapp/Models that extendsWnx\Sends\Models\Send.Then add thePrunable-trait and set up theprunable()-method to your liking. The example below deletes allSend-models older than 1 month.

// app/Models/Send.phpnamespaceApp\Models;useIlluminate\Database\Eloquent\Prunable;useWnx\Sends\Models\SendasBaseSend;class Sendextends BaseSend{use Prunable;publicfunctionprunable()    {returnstatic::where('created_at','<=',now()->subMonth());    }}

Optionally you can also update the configuration, so that the package internally uses your Send model.

// config/sends.php/* * The fully qualified class name of the send model. */'send_model' => \App\Models\Send::class,

Further Usage of thesends-table

As you might have noticed, thesends-table comes with more columns than that are currently filled by the package. This is by design.

You are encouraged to write your own application logic to fill these currently empty columns. For example, if you're sending emails through AWS SES, I highly encourage you to use therenoki-co/laravel-aws-webhooks package to handle AWS SNS webhooks.

A controller that handles the "Delivered" event might look like this.

class AwsSnsSesWebhookControllerextends SesWebhook {protectedfunctiononDelivery(array$message)    {$uuidHeader =collect(Arr::get($message,'mail.headers', []))            ->firstWhere('name',config('sends.headers.send_uuid'));if ($uuidHeader ===null) {return;        }$send = Send::forUuid($uuidHeader['value'])->first();if ($send ===null) {return;        }$send->delivered_at =now();$send->save();    }}

Testing

composertest

Changelog

Please seeCHANGELOG for more information on what has changed recently.

Contributing

Please seeCONTRIBUTING for details.

Security Vulnerabilities

Please reviewour security policy on how to report security vulnerabilities.

Credits

License

The MIT License (MIT). Please seeLicense File for more information.

About

A package to keep track of outgoing emails in your Laravel application.

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Sponsor this project

 

Contributors5


[8]ページ先頭

©2009-2025 Movatter.jp