├── .styleci.yml ├── .gitignore ├── .editorconfig ├── sonar-project.properties ├── .github └── dependabot.yml ├── composer.json ├── LICENSE ├── phpunit.xml ├── .appveyor.yml ├── src └── MailFailer.php ├── tests └── MailFailureTest.php └── README.md /.styleci.yml: -------------------------------------------------------------------------------- 1 | preset: psr2 2 | 3 | finder: 4 | exclude: 5 | - "vendor" 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | composer.lock 2 | vendor 3 | junit-logfile.xml 4 | clover.xml 5 | .scannerwork 6 | *.cache 7 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | indent_style = space 8 | indent_size = 4 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | 14 | [*.yml] 15 | indent_style = space 16 | indent_size = 2 17 | -------------------------------------------------------------------------------- /sonar-project.properties: -------------------------------------------------------------------------------- 1 | sonar.projectKey=rogervila_laravel-email-failer 2 | sonar.organization=rogervila-github 3 | sonar.host.url=https://sonarcloud.io 4 | sonar.sources=. 5 | sonar.exclusions=vendor/**, tests/** 6 | sonar.coverage.exclusions=vendor/**, tests/** 7 | sonar.php.tests.reportPath=junit-logfile.xml 8 | sonar.php.coverage.reportPaths=clover.xml 9 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | # Maintain dependencies for GitHub Actions 9 | - package-ecosystem: github-actions 10 | directory: "/" 11 | schedule: 12 | interval: "daily" 13 | # Maintain dependencies for composer 14 | - package-ecosystem: composer 15 | directory: "/" 16 | schedule: 17 | interval: "daily" 18 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rogervila/laravel-email-failer", 3 | "description": "Helper class for testing Laravel Mail Failures", 4 | "keywords": [ 5 | "laravel mail failure", 6 | "laravel mail error" 7 | ], 8 | "type": "library", 9 | "license": "MIT", 10 | "authors": [ 11 | { 12 | "name": "Roger Vilà", 13 | "email": "rogervila@me.com" 14 | } 15 | ], 16 | "config": { 17 | "optimize-autoloader": true, 18 | "preferred-install": "dist", 19 | "sort-packages": true 20 | }, 21 | "autoload": { 22 | "psr-4": { 23 | "LaravelEmailFailer\\": "src/" 24 | } 25 | }, 26 | "autoload-dev": { 27 | "psr-4": { 28 | "Tests\\": "tests/" 29 | } 30 | }, 31 | "require": { 32 | "laravel/framework": "^11.0" 33 | }, 34 | "require-dev": { 35 | "laravel/pint": "^1.16", 36 | "orchestra/testbench": "^9.0", 37 | "phpunit/phpunit": "^10.0 || ^11.0" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Roger Vilà 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | tests 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | ./src 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /.appveyor.yml: -------------------------------------------------------------------------------- 1 | build: false 2 | version: appveyor-{branch}-{build} 3 | shallow_clone: false 4 | clone_folder: C:\projects\app 5 | 6 | environment: 7 | matrix: 8 | - php_ver: 8.2.0 9 | - php_ver: 8.3.0 10 | 11 | init: 12 | - SET PATH=C:\tools\php;%PATH% 13 | 14 | install: 15 | - ps: Set-Service wuauserv -StartupType Manual 16 | - IF NOT EXIST C:\tools\php (choco install --yes --allow-empty-checksums php --version %php_ver% --params '/InstallDir:C:\tools\php') 17 | - cd C:\tools\php 18 | - copy php.ini-production php.ini 19 | - echo date.timezone="UTC" >> php.ini 20 | - echo memory_limit=512M >> php.ini 21 | - echo extension_dir=ext >> php.ini 22 | - echo extension=php_curl.dll >> php.ini 23 | - echo extension=php_fileinfo.dll >> php.ini 24 | - echo extension=php_openssl.dll >> php.ini 25 | - echo extension=php_mbstring.dll >> php.ini 26 | - IF NOT EXIST C:\tools\composer.phar (cd C:\tools && appveyor DownloadFile https://getcomposer.org/composer.phar) 27 | - php C:\tools\composer.phar --version 28 | - cd C:\projects\app 29 | 30 | before_test: 31 | - cd C:\projects\app 32 | - php C:\tools\composer.phar update --optimize-autoloader --no-interaction --no-progress --prefer-stable --no-ansi 33 | - php C:\tools\composer.phar info -D | sort 34 | 35 | test_script: 36 | - cd C:\projects\app 37 | - vendor\bin\pint --test 38 | - vendor\bin\phpunit --no-coverage 39 | -------------------------------------------------------------------------------- /src/MailFailer.php: -------------------------------------------------------------------------------- 1 | make(MailManager::class)); 27 | } 28 | 29 | /** 30 | * Send a new message using a view. 31 | * 32 | * @param Mailable|string|array $view 33 | * @param \Closure|string|null $callback 34 | * @return void 35 | * 36 | * @throws TransportException 37 | */ 38 | public function send($view, array $data = [], $callback = null) 39 | { 40 | try { 41 | if ($view instanceof Mailable) { 42 | foreach ($view->to as $to) { 43 | array_push($this->failedRecipients, $to['address']); 44 | } 45 | } 46 | 47 | throw new TransportException('Connection could not be established with host "1.2.3.4:1234": stream_socket_client(): Unable to connect to 1.2.3.4:1234 (Connection refused)'); 48 | } catch (Throwable $e) { 49 | throw new TransportException($e->getMessage()); 50 | } 51 | } 52 | 53 | /** 54 | * Get the array of failed recipients. 55 | * 56 | * @return array 57 | */ 58 | public function failures() 59 | { 60 | return $this->failedRecipients; 61 | } 62 | 63 | public static function bind(?Application $app = null): self 64 | { 65 | Mail::swap($instance = new self($app)); 66 | 67 | return $instance; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /tests/MailFailureTest.php: -------------------------------------------------------------------------------- 1 | expectException(TransportException::class); 19 | $this->expectExceptionMessage('Connection could not be established with host "1.2.3.4:1234": stream_socket_client(): Unable to connect to 1.2.3.4:1234 (Connection refused)'); 20 | 21 | $address = 'foo@foo.foo'; 22 | $mailer = MailFailer::bind(); 23 | 24 | $mailable = new FakeMailable; 25 | $mailable->subject('test')->to($address); 26 | 27 | $mailer->send($mailable); 28 | } 29 | 30 | public function testMailFailuresContainsAddress() 31 | { 32 | try { 33 | $address = 'foo@foo.foo'; 34 | $mailer = MailFailer::bind(); 35 | 36 | $mailable = new FakeMailable; 37 | $mailable->subject('test')->to($address); 38 | 39 | $mailer->send($mailable); 40 | } catch (TransportException) { 41 | $this->assertTrue(in_array($address, $mailer->failures())); 42 | } 43 | } 44 | 45 | public function testMailFailuresContainsMultipleAddresses() 46 | { 47 | try { 48 | $addresses = ['foo@foo.foo', 'bar@bar.bar']; 49 | $mailer = MailFailer::bind(); 50 | 51 | $mailable = new FakeMailable; 52 | $mailable->subject('test')->to($addresses); 53 | 54 | $mailer->send($mailable); 55 | } catch (TransportException) { 56 | $this->assertCount(0, array_diff($addresses, $mailer->failures())); 57 | } 58 | } 59 | 60 | public function testFacadeSwap() 61 | { 62 | MailFailer::bind(); 63 | 64 | $addresses = ['foo@foo.foo', 'bar@bar.bar']; 65 | $mailable = new FakeMailable; 66 | $mailable->subject('test')->to($addresses); 67 | 68 | try { 69 | Mail::send($mailable); 70 | } catch (TransportException) { 71 | $this->assertCount(0, array_diff($addresses, Mail::failures())); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Laravel Email Failer

2 | 3 | [![Build Status](https://travis-ci.org/rogervila/laravel-email-failer.svg?branch=master)](https://travis-ci.org/rogervila/laravel-email-failer) 4 | [![Build status](https://ci.appveyor.com/api/projects/status/4jvwpqfea2x9h95j/branch/master?svg=true)](https://ci.appveyor.com/project/roger-vila/laravel-email-failer/branch/master) 5 | [![StyleCI](https://github.styleci.io/repos/195772522/shield?branch=master)](https://github.styleci.io/repos/195772522) 6 | [![Latest Stable Version](https://poser.pugx.org/rogervila/laravel-email-failer/v/stable)](https://packagist.org/packages/rogervila/laravel-email-failer) 7 | [![Total Downloads](https://poser.pugx.org/rogervila/laravel-email-failer/downloads)](https://packagist.org/packages/rogervila/laravel-email-failer) 8 | [![License](https://poser.pugx.org/rogervila/laravel-email-failer/license)](https://packagist.org/packages/rogervila/laravel-email-failer) 9 | [![MadeWithLaravel.com shield](https://madewithlaravel.com/storage/repo-shields/2217-shield.svg)](https://madewithlaravel.com/p/laravel-email-failer/shield-link) 10 | 11 | # Laravel Email Failer 12 | 13 | ```sh 14 | composer require --dev rogervila/laravel-email-failer 15 | ``` 16 | 17 | ## About 18 | 19 | Trigger email failures to assert what happens on your Laravel Application when an email fails to send 20 | 21 | ## Usage 22 | 23 | Once MailFailer instance is binded, all emails will fail. This helps to assert that your application Mail exceptions are handled correctly (ie: mark the email address as invalid) 24 | 25 | ```php 26 | class MyService 27 | { 28 | public static function sendEmail() 29 | { 30 | \Illuminate\Support\Facades\Mail::send(...); 31 | } 32 | } 33 | 34 | public function test_happy_path() 35 | { 36 | Mail::fake(); 37 | 38 | MyService::sendEmail(); 39 | 40 | Mail::assertSent(MyMailable::class); 41 | } 42 | 43 | public function test_email_failures() 44 | { 45 | $this->expectException(TransportException::class); 46 | 47 | \LaravelEmailFailer\MailFailer::bind(); 48 | 49 | MyService::sendEmail(); 50 | 51 | Mail::assertNotSent(MyMailable::class); 52 | 53 | dump(Mail::failures()); 54 | // Assert here what happens when the email has failed 55 | } 56 | 57 | ``` 58 | 59 | 60 | ## License 61 | 62 | Laravel Email Failer is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT). 63 | 64 | 65 | Icon made by Darius Dan from www.flaticon.com is licensed by CC 3.0 BY 66 | --------------------------------------------------------------------------------