├── .php-cs-fixer.dist.php ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── composer.json ├── config └── web-mailer.php ├── resources └── views │ ├── .gitkeep │ └── index.blade.php ├── routes └── web.php └── src ├── Commands ├── LaravelWebMailerCleanUpCommand.php └── LaravelWebMailerClearAllCommand.php ├── Controllers └── LaravelWebMailController.php ├── LaravelWebMailDto.php ├── LaravelWebMailRepository.php ├── LaravelWebMailerServiceProvider.php └── LaravelWebMailerTransport.php /.php-cs-fixer.dist.php: -------------------------------------------------------------------------------- 1 | in([ 5 | __DIR__ . '/src', 6 | __DIR__ . '/tests', 7 | ]) 8 | ->name('*.php') 9 | ->notName('*.blade.php') 10 | ->ignoreDotFiles(true) 11 | ->ignoreVCS(true); 12 | 13 | return (new PhpCsFixer\Config()) 14 | ->setRules([ 15 | '@PSR12' => true, 16 | 'array_syntax' => ['syntax' => 'short'], 17 | 'ordered_imports' => ['sort_algorithm' => 'alpha'], 18 | 'no_unused_imports' => true, 19 | 'not_operator_with_successor_space' => true, 20 | 'trailing_comma_in_multiline' => true, 21 | 'phpdoc_scalar' => true, 22 | 'unary_operator_spaces' => true, 23 | 'binary_operator_spaces' => true, 24 | 'blank_line_before_statement' => [ 25 | 'statements' => ['break', 'continue', 'declare', 'return', 'throw', 'try'], 26 | ], 27 | 'phpdoc_single_line_var_spacing' => true, 28 | 'phpdoc_var_without_name' => true, 29 | 'class_attributes_separation' => [ 30 | 'elements' => [ 31 | 'method' => 'one', 32 | ], 33 | ], 34 | 'method_argument_space' => [ 35 | 'on_multiline' => 'ensure_fully_multiline', 36 | 'keep_multiple_spaces_after_comma' => true, 37 | ], 38 | 'single_trait_insert_per_statement' => true, 39 | ]) 40 | ->setFinder($finder); 41 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `laravel-web-mailer` will be documented in this file. 4 | 5 | ## 1.0.4 - 2025-02-25 6 | 7 | ### What's Changed 8 | 9 | * Laravel 12.x and PHP 8.3-8.4 Compatibility by @laravel-shift in https://github.com/creagia/laravel-web-mailer/pull/18 10 | 11 | **Full Changelog**: https://github.com/creagia/laravel-web-mailer/compare/1.0.3...1.0.4 12 | 13 | ## 1.0.3 - 2024-03-04 14 | 15 | ### What's Changed 16 | 17 | * Laravel 11.x Compatibility by @laravel-shift in https://github.com/creagia/laravel-web-mailer/pull/12 18 | 19 | ### New Contributors 20 | 21 | * @laravel-shift made their first contribution in https://github.com/creagia/laravel-web-mailer/pull/12 22 | 23 | **Full Changelog**: https://github.com/creagia/laravel-web-mailer/compare/1.0.2...1.0.3 24 | 25 | ## 1.0.2 - 2023-02-15 26 | 27 | ### What's Changed 28 | 29 | - Laravel 10.x compatibility by @dtorras in https://github.com/creagia/laravel-web-mailer/pull/6 30 | 31 | ### New Contributors 32 | 33 | - @dtorras made their first contribution in https://github.com/creagia/laravel-web-mailer/pull/6 34 | 35 | **Full Changelog**: https://github.com/creagia/laravel-web-mailer/compare/1.0.1...1.0.2 36 | 37 | ## 1.0.1 - 2022-12-13 38 | 39 | ### What's Changed 40 | 41 | - Bump dependabot/fetch-metadata from 1.3.3 to 1.3.4 by @dependabot in https://github.com/creagia/laravel-web-mailer/pull/1 42 | - Bump dependabot/fetch-metadata from 1.3.4 to 1.3.5 by @dependabot in https://github.com/creagia/laravel-web-mailer/pull/2 43 | - minor fixes by @xmuntane in https://github.com/creagia/laravel-web-mailer/pull/4 44 | - Bump ramsey/composer-install from 1 to 2 by @dependabot in https://github.com/creagia/laravel-web-mailer/pull/3 45 | 46 | ### New Contributors 47 | 48 | - @dependabot made their first contribution in https://github.com/creagia/laravel-web-mailer/pull/1 49 | - @xmuntane made their first contribution in https://github.com/creagia/laravel-web-mailer/pull/4 50 | 51 | **Full Changelog**: https://github.com/creagia/laravel-web-mailer/compare/1.0.0...1.0.1 52 | 53 | ## 1.0.0 - 2022-08-03 54 | 55 | Initial release 56 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Creagia 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Laravel Web Mailer 2 | This package contains a web mailer which will catch all the sent emails. Then, you can view it visiting the route `/web-inbox`. 3 | The emails will be stored as a file in the storage folder. 4 | 5 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/creagia/laravel-web-mailer.svg?style=flat-square)](https://packagist.org/packages/creagia/laravel-web-mailer) 6 | [![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/creagia/laravel-web-mailer/run-tests.yml?label=tests)](https://github.com/creagia/laravel-web-mailer/actions?query=workflow%3Arun-tests+branch%3Amain) 7 | [![GitHub Code Style Action Status](https://img.shields.io/github/actions/workflow/status/creagia/laravel-web-mailer/php-cs-fixer.yml?label=code%20style)](https://github.com/creagia/laravel-web-mailer/actions?query=workflow%3A"Check+%26+fix+styling"+branch%3Amain) 8 | [![Total Downloads](https://img.shields.io/packagist/dt/creagia/laravel-web-mailer.svg?style=flat-square)](https://packagist.org/packages/creagia/laravel-web-mailer) 9 | 10 |

Inbox screenshot

11 | 12 | ## Requirements 13 | This package requires PHP 8.1 and Laravel 9. If you need compatibility with older versions, 14 | check the [alternatives](#alternatives) section. 15 | 16 | ## Installation 17 | You can install the package via composer: 18 | ```bash 19 | composer require creagia/laravel-web-mailer 20 | ``` 21 | 22 | After that, open your `config/mail.php` file and add the web mailer entry in the `mailers` configuration array. 23 | ```php 24 | 'mailers' => [ 25 | // ... 26 | 'web' => [ 27 | 'transport' => 'web', 28 | ], 29 | ], 30 | ``` 31 | 32 | Finally, you can enable the web mailer setting the defined mailer in your .env file: 33 | ``` 34 | MAIL_MAILER=web 35 | ``` 36 | 37 | We recommend you to publish the configuration file to be able to perform some customizations 38 | ```bash 39 | php artisan vendor:publish --tag="web-mailer-config" 40 | ``` 41 | 42 | ### Inbox URL 43 | The default URL to view the emails is `/web-inbox`. You can change it, adding the below entry to your .env file: 44 | ``` 45 | WEB_MAILER_ROUTE_PREFIX="your-custom-url" 46 | ``` 47 | 48 | ### Route protection 49 | By default, the inbox URL is authorized for everybody who has the link. If you need to add some protection, you can modify the `middleware` array on the `config/web-mailer.php` file. 50 | 51 | ### Delete all stored emails 52 | ```bash 53 | php artisan laravel-web-mailer:clear-all 54 | ``` 55 | 56 | ### Delete stored emails older than N days 57 | ```bash 58 | php artisan laravel-web-mailer:cleanup 59 | ``` 60 | You can run or schedule the command `laravel-web-mailer:cleanup` to delete the emails older than N days. By default, it will delete the emails older than 7 days. You can customize the number of days changing the `delete_emails_older_than_days` parameter on the `config/web-mailer.php` file. 61 | 62 | 63 | ## Testing 64 | ```bash 65 | composer test 66 | ``` 67 | 68 | ## Changelog 69 | Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently. 70 | 71 | 72 | ## Alternatives 73 | - [tkeer/mailbase](https://github.com/tkeer/mailbase) 74 | 75 | ## Contributing 76 | Please see [CONTRIBUTING](.github/CONTRIBUTING.md) for details. 77 | 78 | ## Security Vulnerabilities 79 | Please review [our security policy](../../security/policy) on how to report security vulnerabilities. 80 | 81 | ## Credits 82 | - [Xavier Muntané](https://github.com/xmuntane) 83 | - [All Contributors](../../contributors) 84 | 85 | ## License 86 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 87 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "creagia/laravel-web-mailer", 3 | "description": "Laravel Web Mailer", 4 | "keywords": [ 5 | "creagia", 6 | "laravel", 7 | "laravel-web-mailer", 8 | "mail" 9 | ], 10 | "homepage": "https://github.com/creagia/laravel-web-mailer", 11 | "license": "MIT", 12 | "authors": [ 13 | { 14 | "name": "Xavier Muntané", 15 | "email": "xavier@creagia.com", 16 | "role": "Developer" 17 | } 18 | ], 19 | "require": { 20 | "php": "^8.1", 21 | "spatie/laravel-package-tools": "^1.9.2", 22 | "illuminate/contracts": "^9.0|^10.0|^11.0|^12.0", 23 | "symfony/mime": "^6.1|^7.0" 24 | }, 25 | "require-dev": { 26 | "friendsofphp/php-cs-fixer": "^3.8", 27 | "nunomaduro/collision": "^6.0|^8.0", 28 | "nunomaduro/larastan": "^2.0.1|^3.0", 29 | "orchestra/testbench": "^7.0|^8.0|^9.0|^10.0", 30 | "pestphp/pest": "^1.21|^2.34|^3.7", 31 | "pestphp/pest-plugin-laravel": "^1.1|^2.3|^3.1", 32 | "phpstan/extension-installer": "^1.1", 33 | "phpstan/phpstan-deprecation-rules": "^1.0|^2.0", 34 | "phpstan/phpstan-phpunit": "^1.0|^2.0", 35 | "phpunit/phpunit": "^9.5|^10.5|^11.5.3" 36 | }, 37 | "autoload": { 38 | "psr-4": { 39 | "Creagia\\LaravelWebMailer\\": "src", 40 | "Creagia\\LaravelWebMailer\\Database\\Factories\\": "database/factories" 41 | } 42 | }, 43 | "autoload-dev": { 44 | "psr-4": { 45 | "Creagia\\LaravelWebMailer\\Tests\\": "tests" 46 | } 47 | }, 48 | "scripts": { 49 | "analyse": "vendor/bin/phpstan analyse", 50 | "test": "vendor/bin/pest", 51 | "test-coverage": "vendor/bin/pest --coverage", 52 | "format": "vendor/bin/php-cs-fixer fix --allow-risky=yes" 53 | }, 54 | "config": { 55 | "sort-packages": true, 56 | "allow-plugins": { 57 | "pestphp/pest-plugin": true, 58 | "phpstan/extension-installer": true 59 | } 60 | }, 61 | "extra": { 62 | "laravel": { 63 | "providers": [ 64 | "Creagia\\LaravelWebMailer\\LaravelWebMailerServiceProvider" 65 | ] 66 | } 67 | }, 68 | "minimum-stability": "dev", 69 | "prefer-stable": true 70 | } 71 | -------------------------------------------------------------------------------- /config/web-mailer.php: -------------------------------------------------------------------------------- 1 | [ 6 | /** 7 | * Prefix used by the package routes. 'mails' by default. 8 | */ 9 | 'prefix' => env('WEB_MAILER_ROUTE_PREFIX', 'web-inbox'), 10 | 11 | 'middleware' => [ 12 | // 'web', 13 | // 'auth', 14 | ], 15 | ], 16 | 17 | /* 18 | * The path where the emails will be stored 19 | */ 20 | 'storage_path' => storage_path('web-emails'), 21 | 22 | /* 23 | * To enable this feature, you must schedule 24 | * the command: 'laravel-web-mailer:cleanup' 25 | */ 26 | 'delete_emails_older_than_days' => 7, 27 | ]; 28 | -------------------------------------------------------------------------------- /resources/views/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/creagia/laravel-web-mailer/e63e87642f346543eac13f8eff6ceaf5b17a38e9/resources/views/.gitkeep -------------------------------------------------------------------------------- /resources/views/index.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {{ config('app.name') }} — Web Inbox 7 | 8 | 9 | 10 | 92 | 93 | 94 |
97 | 98 |
99 |

{{ config('app.name') }} — Web Inbox

100 |
101 | 110 |
111 |
112 | 113 |
114 | 115 |
116 |
117 |
There are no emails
118 | @if(config('mail.default') !== 'web') 119 | 122 | @endif 123 |
124 |
125 | 126 | 157 |
158 |
159 |
160 |
Sent at:
161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 201 | 202 | 203 |
From
To
CC
BCC
Reply-To
Attachments 187 | 200 |
204 | 232 |
233 | 234 |
235 |
236 | 237 |
238 |
239 |

240 |                 
241 |
242 |
243 |
244 |
245 |

246 |                 
247 |
248 |

249 |                 
250 |
251 |
252 | 253 |
254 |
255 | 256 | 257 | 258 | -------------------------------------------------------------------------------- /routes/web.php: -------------------------------------------------------------------------------- 1 | middleware(config('web-mailer.route.middleware')) 8 | ->controller(LaravelWebMailController::class) 9 | ->group(function () { 10 | Route::get('/', 'index')->name('laravelWebMailer.index'); 11 | Route::get('/all', 'fetchAll')->name('laravelWebMailer.fetchAll'); 12 | Route::get('/message/{messageId}', 'fetch')->name('laravelWebMailer.fetch'); 13 | Route::get('/message/{messageId}/attachment/{index}', 'downloadAttachment')->name('laravelWebMailer.downloadAttachment'); 14 | Route::delete('/all-messages', 'destroy')->name('laravelWebMailer.destroy'); 15 | }); 16 | -------------------------------------------------------------------------------- /src/Commands/LaravelWebMailerCleanUpCommand.php: -------------------------------------------------------------------------------- 1 | comment("Deleting all stored emails older than {$numberOfDays} days..."); 20 | 21 | $currentTime = now(); 22 | 23 | $laravelWebMailRepository 24 | ->all() 25 | ->filter( 26 | fn (LaravelWebMailDto $laravelWebMailDto) => $laravelWebMailDto->sentAt->diffInDays($currentTime) > $numberOfDays 27 | ) 28 | ->each(fn (LaravelWebMailDto $laravelWebMailDto) => $laravelWebMailRepository->delete($laravelWebMailDto->messageId)); 29 | 30 | $this->comment('All done'); 31 | 32 | return self::SUCCESS; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Commands/LaravelWebMailerClearAllCommand.php: -------------------------------------------------------------------------------- 1 | comment('Deleting all stored emails...'); 18 | 19 | $laravelWebMailRepository 20 | ->all() 21 | ->each(fn (LaravelWebMailDto $laravelWebMailDto) => $laravelWebMailRepository->delete($laravelWebMailDto->messageId)); 22 | 23 | $this->comment('All done'); 24 | 25 | return self::SUCCESS; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Controllers/LaravelWebMailController.php: -------------------------------------------------------------------------------- 1 | laravelWebMailRepository = app(LaravelWebMailRepository::class); 19 | } 20 | 21 | public function index(): View 22 | { 23 | return view('web-mailer::index'); 24 | } 25 | 26 | public function fetchAll(): JsonResponse 27 | { 28 | $mails = $this->laravelWebMailRepository 29 | ->all() 30 | ->map(function (LaravelWebMailDto $laravelWebMailDto) { 31 | return (object)[ 32 | 'messageId' => $laravelWebMailDto->messageId, 33 | 'subject' => $laravelWebMailDto->subject, 34 | 'to' => $laravelWebMailDto->to, 35 | 'diffDate' => $laravelWebMailDto->sentAt->diffForHumans(null, null, true), 36 | 'isRead' => $laravelWebMailDto->isRead, 37 | 'fetchRoute' => route('laravelWebMailer.fetch', $laravelWebMailDto->messageId), 38 | 'hasAttachments' => count($laravelWebMailDto->attachments) > 0, 39 | ]; 40 | }) 41 | ->values() 42 | ->toArray(); 43 | 44 | return response()->json($mails); 45 | } 46 | 47 | public function fetch(string $messageId): JsonResponse 48 | { 49 | $laravelWebMailDto = $this->laravelWebMailRepository->find($messageId, markAsRead: true); 50 | abort_unless($laravelWebMailDto instanceof LaravelWebMailDto, 404, 'Message not found'); 51 | 52 | $attachments = collect($laravelWebMailDto->attachments) 53 | ->map(function (DataPart $dataPart, $index) use ($messageId) { 54 | return (object)[ 55 | 'filename' => $dataPart->getFilename(), 56 | 'downloadRoute' => route('laravelWebMailer.downloadAttachment', [$messageId, $index]), 57 | ]; 58 | }) 59 | ->toArray(); 60 | 61 | return response()->json((object)[ 62 | 'sentAtFormatted' => $laravelWebMailDto->sentAt->format('Y-m-d H:i'), 63 | 'eml' => $this->laravelWebMailRepository->findEml($messageId), 64 | 'attachments' => $attachments, 65 | 'messageId' => $laravelWebMailDto->messageId, 66 | 'htmlBody' => $laravelWebMailDto->htmlBody, 67 | 'textBody' => nl2br($laravelWebMailDto->textBody ?? ''), 68 | 'subject' => $laravelWebMailDto->subject, 69 | 'isRead' => $laravelWebMailDto->isRead, 70 | 'headers' => $laravelWebMailDto->headers, 71 | 'from' => $laravelWebMailDto->from, 72 | 'to' => $laravelWebMailDto->to, 73 | 'replyTo' => $laravelWebMailDto->replyTo, 74 | 'cc' => $laravelWebMailDto->cc, 75 | 'bcc' => $laravelWebMailDto->bcc, 76 | ]); 77 | } 78 | 79 | public function downloadAttachment(string $messageId, int $attachmentIndex): StreamedResponse 80 | { 81 | $content = $this->laravelWebMailRepository->find($messageId); 82 | abort_unless($content instanceof LaravelWebMailDto, 404, 'Message not found'); 83 | 84 | /** @var ?DataPart $attachment */ 85 | $attachment = $content->attachments[$attachmentIndex] ?? null; 86 | abort_if(is_null($attachment), 404, 'Attachment not found'); 87 | 88 | return response()->streamDownload( 89 | function () use ($attachment) { 90 | echo $attachment->getBody(); 91 | }, 92 | $attachment->getFilename() 93 | ); 94 | } 95 | 96 | public function destroy(): JsonResponse 97 | { 98 | $this->laravelWebMailRepository 99 | ->all() 100 | ->each(fn (LaravelWebMailDto $laravelWebMailDto) => $this->laravelWebMailRepository->delete($laravelWebMailDto->messageId)); 101 | 102 | return response()->json(); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/LaravelWebMailDto.php: -------------------------------------------------------------------------------- 1 | $to 14 | * @param array $replyTo 15 | * @param array $cc 16 | * @param array $bcc 17 | * @param array $attachments 18 | */ 19 | public function __construct( 20 | public readonly string $messageId, 21 | public readonly string $from, 22 | public readonly array $to, 23 | public readonly array $replyTo, 24 | public readonly array $cc, 25 | public readonly array $bcc, 26 | public readonly string $headers, 27 | public readonly string $subject, 28 | public readonly ?string $textBody, 29 | public readonly ?string $htmlBody, 30 | public readonly Carbon $sentAt, 31 | public readonly array $attachments, 32 | public bool $isRead = false, 33 | ) { 34 | } 35 | 36 | public static function fromEmail(string $messageId, Email $email): self 37 | { 38 | return new LaravelWebMailDto( 39 | messageId: $messageId, 40 | from: $email->getFrom()[0]->toString(), 41 | to: collect($email->getTo())->map(fn (Address $address) => $address->toString())->toArray(), 42 | replyTo: collect($email->getReplyTo())->map(fn (Address $address) => $address->toString())->toArray(), 43 | cc: collect($email->getCc())->map(fn (Address $address) => $address->toString())->toArray(), 44 | bcc: collect($email->getBcc())->map(fn (Address $address) => $address->toString())->toArray(), 45 | headers: $email->getPreparedHeaders()->toString(), 46 | subject: $email->getSubject() ?? '', 47 | textBody: ($email->getTextBody()) ? (string)$email->getTextBody() : null, 48 | htmlBody: ($email->getHtmlBody()) ? (string)$email->getHtmlBody() : null, 49 | sentAt: ($email->getDate()) ? Carbon::createFromImmutable($email->getDate()) : now(), 50 | attachments: $email->getAttachments(), 51 | ); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/LaravelWebMailRepository.php: -------------------------------------------------------------------------------- 1 | ensureEmailsDirectoryExists(); 20 | 21 | $this->filesystem->put( 22 | self::serializedEmailPath($laravelWebMailDto->messageId), 23 | serialize($laravelWebMailDto) 24 | ); 25 | 26 | $this->filesystem->put( 27 | self::emlPath($laravelWebMailDto->messageId), 28 | $sentMessage->toString() 29 | ); 30 | } 31 | 32 | public function delete(string $messageId): void 33 | { 34 | $this->filesystem->delete(self::serializedEmailPath($messageId)); 35 | $this->filesystem->delete(self::emlPath($messageId)); 36 | } 37 | 38 | /** 39 | * @return Collection 40 | */ 41 | public function all(): Collection 42 | { 43 | $filenamePattern = config('web-mailer.storage_path') . DIRECTORY_SEPARATOR . '*.serialized'; 44 | 45 | return collect($this->filesystem->glob($filenamePattern)) 46 | ->map(fn (string $filePath) => unserialize($this->filesystem->get($filePath))) 47 | ->sortByDesc(fn (LaravelWebMailDto $laravelWebMailDto) => $laravelWebMailDto->sentAt); 48 | } 49 | 50 | public function find(string $messageId, bool $markAsRead = false): ?LaravelWebMailDto 51 | { 52 | /** @var LaravelWebMailDto $laravelWebMailDto */ 53 | $laravelWebMailDto = unserialize( 54 | $this->filesystem->get(self::serializedEmailPath($messageId)) 55 | ); 56 | 57 | if ($markAsRead) { 58 | $laravelWebMailDto = $this->markEmailAsRead($laravelWebMailDto); 59 | } 60 | 61 | return $laravelWebMailDto; 62 | } 63 | 64 | public function findEml(string $messageId): ?string 65 | { 66 | try { 67 | return $this->filesystem->get(self::emlPath($messageId)); 68 | } catch (FileNotFoundException) { 69 | return null; 70 | } 71 | } 72 | 73 | private function ensureEmailsDirectoryExists(): void 74 | { 75 | $this->filesystem->ensureDirectoryExists(config('web-mailer.storage_path')); 76 | 77 | $this->filesystem->put( 78 | config('web-mailer.storage_path') . DIRECTORY_SEPARATOR . '.gitignore', 79 | '*' . PHP_EOL . '!.gitignore' 80 | ); 81 | } 82 | 83 | private static function serializedEmailPath(string $messageId): string 84 | { 85 | return config('web-mailer.storage_path') . DIRECTORY_SEPARATOR . "{$messageId}.serialized"; 86 | } 87 | 88 | private static function emlPath(string $messageId): string 89 | { 90 | return config('web-mailer.storage_path') . DIRECTORY_SEPARATOR . "{$messageId}.eml"; 91 | } 92 | 93 | private function markEmailAsRead(LaravelWebMailDto $laravelWebMailDto): LaravelWebMailDto 94 | { 95 | if ($laravelWebMailDto->isRead) { 96 | return $laravelWebMailDto; 97 | } 98 | 99 | $laravelWebMailDto->isRead = true; 100 | $this->filesystem->put( 101 | self::serializedEmailPath($laravelWebMailDto->messageId), 102 | serialize($laravelWebMailDto) 103 | ); 104 | 105 | return $laravelWebMailDto; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/LaravelWebMailerServiceProvider.php: -------------------------------------------------------------------------------- 1 | name('laravel-web-mailer') 22 | ->hasConfigFile() 23 | ->hasViews() 24 | ->hasRoute('web') 25 | ->hasCommands([ 26 | LaravelWebMailerClearAllCommand::class, 27 | LaravelWebMailerCleanUpCommand::class, 28 | ]); 29 | } 30 | 31 | public function packageRegistered(): void 32 | { 33 | $this->app->afterResolving('mail.manager', function (MailManager $mailManager) { 34 | $mailManager->extend('web', fn (array $config = []) => app(LaravelWebMailerTransport::class)); 35 | }); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/LaravelWebMailerTransport.php: -------------------------------------------------------------------------------- 1 | getOriginalMessage(); 22 | $email = MessageConverter::toEmail($originalMessage); 23 | 24 | $laravelWebMailDto = LaravelWebMailDto::fromEmail($message->getMessageId(), $email); 25 | 26 | $this->laravelWebMailRepository->store( 27 | sentMessage: $message, 28 | laravelWebMailDto: $laravelWebMailDto, 29 | ); 30 | } 31 | 32 | public function __toString(): string 33 | { 34 | return 'web'; 35 | } 36 | } 37 | --------------------------------------------------------------------------------