nem0's avatar
Level 1

Save sent emails to eml files

Is there a way to store copies of emails that are sent via SMTP in Laravel as files such as .eml (including attachements, recipients, etc.)?

I know that there is the render function on Mailables (https://laravel.com/docs/5.8/mail#rendering-mailables) but it only prints the html body of the message without recipients and attachements.

I also stumbled upon https://github.com/themsaid/laravel-mail-preview/ which includes the option to store sent emails as eml files but the plugin is apparently only usable for debugging/previews (instead of sending emails).

I would appreciate any ideas or suggestions!

Thanks!

0 likes
7 replies
mvd's avatar

Hi @nem0,

I don't know where you want to use it for but is it not an option to add a bcc address for each e-mail?

nem0's avatar
Level 1

Hey, using BCC is not a real option. I need to store a copy of the sent emails in an external application (I can upload files to this application via a SOAP interface)

davewood's avatar

I, too, want to get access to a eml version of the emails my app is sending. Any help how that could be accomplished is appreciated.

davewood's avatar

painful realization that $mailable->render() doesnt work if you run your test using Mail::fake()

davewood's avatar

painful realization #2 ... Mailable::withSwiftMessage executes the callback and passes $message. but $message doesnt have the body set to the rendered blade view. instead you just dont have the body available at this point.

davewood's avatar

Solution:

you can listen to the LogSentMessage event

diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php
index 723a290..f7568ec 100644
--- a/app/Providers/EventServiceProvider.php
+++ b/app/Providers/EventServiceProvider.php
@@ -18,6 +18,9 @@ class EventServiceProvider extends ServiceProvider
         Registered::class => [
             SendEmailVerificationNotification::class,
         ],
+       'Illuminate\Mail\Events\MessageSent' => [
+           'App\Listeners\LogSentMessage',
+       ],
     ];

after adding these 3 lines run php artisan event:generate

this should create the file app/Listeners/LogSentMessage.php

inside the handle function you can access the complete msg -> $event->message->toString();

https://laravel.com/docs/6.x/mail#events

ataub2qf's avatar

If someone still is looking here. This works for me:

The event handler:

//App/Providers/EventServiceProvider.php
<?php

namespace App\Providers;

use App\Listeners\SentEmailListener;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Mail\Events\MessageSent;
use Illuminate\Support\Facades\Event;

class EventServiceProvider extends ServiceProvider
{
	/**
	 * The event to listener mappings for the application.
	 *
	 * @var array<class-string, array<int, class-string>>
	 */
	protected $listen = [
		MessageSent::class => [
			SentEmailListener::class,
		],
	];

And the listener:

//App/Listeners/SentEmailListener.php
<?php

namespace App\Listeners;

use Illuminate\Mail\Events\MessageSent;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;

class SentEmailListener
{
	private $recipients;
	private $subject;

	public function handle(MessageSent $event)
	{
		$message = $event->message;
		$this->subject = $message->getSubject();

		$this->recipients = $event->sent->getEnvelope()->getRecipients();
		$this->recipients = implode(', ', array_map(function(\Symfony\Component\Mime\Address $r){
			return $r->getAddress();
		}, $this->recipients));

		$this->logMail($event);
		$this->storeMail($event);
	}

	public function logMail(MessageSent $event)
	{
		Log::debug('E-Mail sent to '. $this->recipients . ': ' . $this->subject);
	}

	// https://pipo.blog/articles/20211203-laravel-mailer-log-eml
	public function storeMail(MessageSent $event)
	{
		$messageId = $this->recipients . '_' . Str::slug($this->subject);
		Storage::disk('emails')->put(
			sprintf('%s_%s.eml', now()->format('Y-m-d_H-i-s_u'), $messageId),
			$event->message->toString()
		);
	}
}

And the storage definition in config/filesystems.php

<?php
// ...
'disks' => [

    
	// ...

	'emails' => [
        'driver'     => 'local',
        'root'       => storage_path('logs/emails'),
    ],
],

Please or to participate in this conversation.