Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

bionary's avatar

Event Listeners on Sent Mail

I'm having trouble wrapping my head around how event listeners work with mailables. I currently dispatch jobs from models when certain model attributes are saved. (for example: $article->status == 'submitted') That creates a job, that sends an email notification.

This works fine, but as I added more of these email notifications I realize that my event listener for "messageSent" is getting triggered for the wrong classes.

class EventServiceProvider extends ServiceProvider
{
    protected $listen = [
        Registered::class => [
            SendEmailVerificationNotification::class,
        ],
        MessageSent::class => [
            NotificationEmailSentListener::class,
        ],
    ];
...

To ignore other event that also send mail I have had to add: if(isset($event->data['notificationItems'])) { to the file below to ignore all but the targeted $event. I'm simply looking for a variable that can help identify the class that triggered the event. This feels like there is a better or more proper way to do this.

class NotificationEmailSentListener
{
    public function __construct()
    {
    }

    public function handle(MessageSent $event): void
    {
        if(isset($event->data['notificationItems'])) {
            foreach ($event->data['notificationItems'] as $notificationItem) {
                $notificationItem->sent_at = now();
                $notificationItem->save();
            }
        }
    }
}

I understand that I am adding a listener via MessageSent::class => [... but is there a way to add a listener to JUST the specific classes I want and not this global messageSent ?

I realize that I may be missing a very large understanding of how this all works so I'm open to hearing solutions. btw: my code works just fine, I'm just wondering if there is a more proper way?

0 likes
1 reply
LaryAI's avatar
Level 58

To address your issue of handling specific mail events without triggering the global MessageSent event, you can create custom events for each specific mail notification. This way, you can listen to these custom events instead of the global MessageSent event.

Here's a step-by-step solution:

  1. Create Custom Events: Create custom events for each type of email notification you want to handle. For example, let's create an event for a notification email.

    // app/Events/NotificationEmailSent.php
    namespace App\Events;
    
    use Illuminate\Mail\Events\MessageSent;
    
    class NotificationEmailSent extends MessageSent
    {
        // You can add additional properties or methods if needed
    }
    
  2. Dispatch Custom Events: Dispatch these custom events in your job or wherever you are sending the email. For example:

    // app/Jobs/SendNotificationEmail.php
    namespace App\Jobs;
    
    use App\Events\NotificationEmailSent;
    use Illuminate\Bus\Queueable;
    use Illuminate\Contracts\Queue\ShouldQueue;
    use Illuminate\Foundation\Bus\Dispatchable;
    use Illuminate\Queue\InteractsWithQueue;
    use Illuminate\Queue\SerializesModels;
    use Illuminate\Support\Facades\Mail;
    use App\Mail\YourMailable;
    
    class SendNotificationEmail implements ShouldQueue
    {
        use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
    
        public function __construct()
        {
            // Constructor logic
        }
    
        public function handle()
        {
            $mailable = new YourMailable();
            Mail::send($mailable);
    
            // Dispatch the custom event
            event(new NotificationEmailSent($mailable));
        }
    }
    
  3. Listen to Custom Events: Update your EventServiceProvider to listen to these custom events.

    // app/Providers/EventServiceProvider.php
    namespace App\Providers;
    
    use App\Events\NotificationEmailSent;
    use App\Listeners\NotificationEmailSentListener;
    use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
    
    class EventServiceProvider extends ServiceProvider
    {
        protected $listen = [
            NotificationEmailSent::class => [
                NotificationEmailSentListener::class,
            ],
        ];
    
        public function boot()
        {
            parent::boot();
        }
    }
    
  4. Handle Custom Events: Update your listener to handle the custom event.

    // app/Listeners/NotificationEmailSentListener.php
    namespace App\Listeners;
    
    use App\Events\NotificationEmailSent;
    
    class NotificationEmailSentListener
    {
        public function __construct()
        {
        }
    
        public function handle(NotificationEmailSent $event): void
        {
            if (isset($event->data['notificationItems'])) {
                foreach ($event->data['notificationItems'] as $notificationItem) {
                    $notificationItem->sent_at = now();
                    $notificationItem->save();
                }
            }
        }
    }
    

By creating and dispatching custom events, you can ensure that your listeners are only triggered for the specific mail notifications you are interested in, avoiding the need to filter out unwanted events. This approach provides a cleaner and more maintainable solution.

Please or to participate in this conversation.