generated from spatie/package-skeleton-laravel
-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
TobMoeller
committed
Sep 29, 2024
1 parent
ffea7ba
commit 0a1813c
Showing
10 changed files
with
310 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,9 +5,28 @@ | |
[![GitHub Code Style Action Status](https://img.shields.io/github/actions/workflow/status/tobmoeller/laravel-mail-allowlist/fix-php-code-style-issues.yml?branch=main&label=code%20style&style=flat-square)](https://github.com/tobmoeller/laravel-mail-allowlist/actions?query=workflow%3A"Fix+PHP+code+style+issues"+branch%3Amain) | ||
[![Total Downloads](https://img.shields.io/packagist/dt/tobmoeller/laravel-mail-allowlist.svg?style=flat-square)](https://packagist.org/packages/tobmoeller/laravel-mail-allowlist) | ||
|
||
This package enables your Laravel application to filter recipients of outgoing emails by domain or specific email addresses through a configurable allowlist. Ideal for staging environments, it ensures that only approved recipients receive emails. Recipients not matching the allowlist are removed from the email, and if no valid "to" recipients remain, the email is stopped altogether, preventing unintended email delivery. | ||
This package provides a customizable middleware pipeline for email messages, allowing you to filter, modify, and inspect emails before they are sent. | ||
|
||
Additionally, the package now supports a customizable middleware pipeline, allowing you to control the existing functionality and implement additional logic for outgoing emails. You can add your own middleware to modify, inspect, or control email messages. | ||
**Key Features:** | ||
|
||
- **Recipient Allowlist Filtering:** | ||
- Filter outgoing email recipients based on a configurable allowlist of domains and specific email addresses. | ||
- Ideal for staging and testing environments to prevent unintended emails from reaching unintended recipients. | ||
- Automatically removes recipients not matching the allowlist from the "To", "Cc", and "Bcc" fields. | ||
- If no valid recipients remain after filtering, the email is canceled to prevent unintended delivery. | ||
|
||
- **Add Global Recipients:** | ||
- Set default or global "To", "Cc", and "Bcc" recipients via configuration. | ||
- Ensure certain recipients always receive emails, such as administrators, audit logs, or monitoring addresses. | ||
|
||
- **Customizable Middleware Pipeline:** | ||
- Utilize a middleware pipeline similar to Laravel's HTTP middleware, but for outgoing emails. | ||
- Add, remove, or reorder middleware to control the processing of emails. | ||
|
||
- **Custom Middleware Support:** | ||
- Create your own middleware to implement custom logic for outgoing emails. | ||
- Modify email content, set headers, add attachments, or perform any email transformation needed. | ||
- Middleware can inspect emails, log information, or integrate with other services. | ||
|
||
> **Important Note:** | ||
> | ||
|
@@ -43,6 +62,11 @@ MAIL_ALLOWLIST_ALLOWED_DOMAINS="foo.com;bar.com" | |
# Define a semicolon separated list of allowed emails | ||
MAIL_ALLOWLIST_ALLOWED_EMAILS="[email protected];[email protected]" | ||
# Define a semicolon separated list of globally added emails | ||
MAIL_ALLOWLIST_GLOBAL_TO="[email protected];[email protected]" | ||
MAIL_ALLOWLIST_GLOBAL_CC="[email protected];[email protected]" | ||
MAIL_ALLOWLIST_GLOBAL_BCC="[email protected];[email protected]" | ||
``` | ||
|
||
### Customizing the Middleware Pipeline | ||
|
@@ -54,6 +78,9 @@ The package processes outgoing emails through a middleware pipeline, allowing yo | |
ToFilter::class; | ||
CcFilter::class; | ||
BccFilter::class; | ||
AddGlobalTo::class, | ||
AddGlobalCc::class, | ||
AddGlobalBcc::class, | ||
EnsureRecipients::class; | ||
], | ||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,8 @@ | ||
<?php | ||
|
||
use TobMoeller\LaravelMailAllowlist\MailMiddleware\Addresses\AddGlobalBcc; | ||
use TobMoeller\LaravelMailAllowlist\MailMiddleware\Addresses\AddGlobalCc; | ||
use TobMoeller\LaravelMailAllowlist\MailMiddleware\Addresses\AddGlobalTo; | ||
use TobMoeller\LaravelMailAllowlist\MailMiddleware\Addresses\BccFilter; | ||
use TobMoeller\LaravelMailAllowlist\MailMiddleware\Addresses\CcFilter; | ||
use TobMoeller\LaravelMailAllowlist\MailMiddleware\Addresses\EnsureRecipients; | ||
|
@@ -16,12 +19,15 @@ | |
* Can be either a class-string or an instance. Class-strings will | ||
* be instantiated through Laravel's service container | ||
* | ||
* All middleware has to implement the MailMiddlewareContract | ||
* All middleware must implement the MailMiddlewareContract | ||
*/ | ||
'middleware' => [ | ||
ToFilter::class, | ||
CcFilter::class, | ||
BccFilter::class, | ||
AddGlobalTo::class, | ||
AddGlobalCc::class, | ||
AddGlobalBcc::class, | ||
EnsureRecipients::class, | ||
], | ||
|
||
|
@@ -36,14 +42,41 @@ | |
* Can either be a singular domain string, | ||
* a semicolon separated list of domains or | ||
* an array of domain strings | ||
* | ||
* e.g. | ||
* 'bar.com' | ||
* 'foo.com;bar.com;...' | ||
* ['foo.com', 'bar.com'] | ||
*/ | ||
'domains' => env('MAIL_ALLOWLIST_ALLOWED_DOMAINS'), | ||
|
||
/** | ||
* Can either be a singular email address string, | ||
* a semicolon separated list of email addresses or | ||
* an array of email address strings | ||
* an array of email address strings (only in config). | ||
* | ||
* e.g. | ||
* '[email protected]' | ||
* '[email protected];[email protected];...' | ||
* ['foo.com', 'bar.com'] | ||
*/ | ||
'emails' => env('MAIL_ALLOWLIST_ALLOWED_EMAILS'), | ||
], | ||
|
||
/** | ||
* Define global recipients to be added to every mail sent. | ||
* Each one can either be a singular email address string, | ||
* a semicolon separated list of email addresses or | ||
* an array of email address strings (only in config) | ||
* | ||
* e.g. | ||
* '[email protected]' | ||
* '[email protected];[email protected];...' | ||
* ['foo.com', 'bar.com'] | ||
*/ | ||
'global' => [ | ||
'to' => env('MAIL_ALLOWLIST_GLOBAL_TO'), | ||
'cc' => env('MAIL_ALLOWLIST_GLOBAL_CC'), | ||
'bcc' => env('MAIL_ALLOWLIST_GLOBAL_BCC'), | ||
], | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<?php | ||
|
||
namespace TobMoeller\LaravelMailAllowlist\MailMiddleware\Addresses; | ||
|
||
use Closure; | ||
use TobMoeller\LaravelMailAllowlist\Facades\LaravelMailAllowlist; | ||
use TobMoeller\LaravelMailAllowlist\MailMiddleware\MailMiddlewareContract; | ||
use TobMoeller\LaravelMailAllowlist\MailMiddleware\MessageContext; | ||
|
||
class AddGlobalBcc implements MailMiddlewareContract | ||
{ | ||
public function handle(MessageContext $messageContext, Closure $next): mixed | ||
{ | ||
if (! empty($bcc = LaravelMailAllowlist::globalBccEmailList())) { | ||
$messageContext->getMessage()->addBcc(...$bcc); | ||
} | ||
|
||
return $next($messageContext); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<?php | ||
|
||
namespace TobMoeller\LaravelMailAllowlist\MailMiddleware\Addresses; | ||
|
||
use Closure; | ||
use TobMoeller\LaravelMailAllowlist\Facades\LaravelMailAllowlist; | ||
use TobMoeller\LaravelMailAllowlist\MailMiddleware\MailMiddlewareContract; | ||
use TobMoeller\LaravelMailAllowlist\MailMiddleware\MessageContext; | ||
|
||
class AddGlobalCc implements MailMiddlewareContract | ||
{ | ||
public function handle(MessageContext $messageContext, Closure $next): mixed | ||
{ | ||
if (! empty($cc = LaravelMailAllowlist::globalCcEmailList())) { | ||
$messageContext->getMessage()->addCc(...$cc); | ||
} | ||
|
||
return $next($messageContext); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<?php | ||
|
||
namespace TobMoeller\LaravelMailAllowlist\MailMiddleware\Addresses; | ||
|
||
use Closure; | ||
use TobMoeller\LaravelMailAllowlist\Facades\LaravelMailAllowlist; | ||
use TobMoeller\LaravelMailAllowlist\MailMiddleware\MailMiddlewareContract; | ||
use TobMoeller\LaravelMailAllowlist\MailMiddleware\MessageContext; | ||
|
||
class AddGlobalTo implements MailMiddlewareContract | ||
{ | ||
public function handle(MessageContext $messageContext, Closure $next): mixed | ||
{ | ||
if (! empty($to = LaravelMailAllowlist::globalToEmailList())) { | ||
$messageContext->getMessage()->addTo(...$to); | ||
} | ||
|
||
return $next($messageContext); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,9 @@ | |
use Illuminate\Support\Facades\Event; | ||
use TobMoeller\LaravelMailAllowlist\Facades\LaravelMailAllowlist; | ||
use TobMoeller\LaravelMailAllowlist\Listeners\MessageSendingListener; | ||
use TobMoeller\LaravelMailAllowlist\MailMiddleware\Addresses\AddGlobalBcc; | ||
use TobMoeller\LaravelMailAllowlist\MailMiddleware\Addresses\AddGlobalCc; | ||
use TobMoeller\LaravelMailAllowlist\MailMiddleware\Addresses\AddGlobalTo; | ||
use TobMoeller\LaravelMailAllowlist\MailMiddleware\Addresses\BccFilter; | ||
use TobMoeller\LaravelMailAllowlist\MailMiddleware\Addresses\CcFilter; | ||
use TobMoeller\LaravelMailAllowlist\MailMiddleware\Addresses\EnsureRecipients; | ||
|
@@ -26,6 +29,9 @@ | |
ToFilter::class, | ||
CcFilter::class, | ||
BccFilter::class, | ||
AddGlobalTo::class, | ||
AddGlobalCc::class, | ||
AddGlobalBcc::class, | ||
EnsureRecipients::class, | ||
]); | ||
}); | ||
|
@@ -100,3 +106,33 @@ | |
'expected' => [], | ||
], | ||
]); | ||
|
||
it('returns the global to/cc/bcc email lists', function (mixed $value, mixed $expected) { | ||
Config::set('mail-allowlist.global.to', $value); | ||
Config::set('mail-allowlist.global.cc', $value); | ||
Config::set('mail-allowlist.global.bcc', $value); | ||
|
||
expect(LaravelMailAllowlist::globalToEmailList()) | ||
->toBe($expected) | ||
->and(LaravelMailAllowlist::globalCcEmailList()) | ||
->toBe($expected) | ||
->and(LaravelMailAllowlist::globalBccEmailList()) | ||
->toBe($expected); | ||
})->with([ | ||
[ | ||
'value' => ['[email protected]', '[email protected]'], | ||
'expected' => ['[email protected]', '[email protected]'], | ||
], | ||
[ | ||
'value' => '[email protected];[email protected]', | ||
'expected' => ['[email protected]', '[email protected]'], | ||
], | ||
[ | ||
'value' => '[email protected]', | ||
'expected' => ['[email protected]'], | ||
], | ||
[ | ||
'value' => null, | ||
'expected' => [], | ||
], | ||
]); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
<?php | ||
|
||
use Illuminate\Support\Facades\Config; | ||
use Symfony\Component\Mime\Address; | ||
use Symfony\Component\Mime\Email; | ||
use TobMoeller\LaravelMailAllowlist\MailMiddleware\Addresses\AddGlobalBcc; | ||
use TobMoeller\LaravelMailAllowlist\MailMiddleware\MessageContext; | ||
|
||
it('adds global bcc addresses and continues the pipeline', function () { | ||
Config::set('mail-allowlist.global.bcc', ['[email protected]', '[email protected]']); | ||
$mail = new Email; | ||
$context = new MessageContext($mail); | ||
|
||
$middlewareReturn = (new AddGlobalBcc)->handle($context, fn () => '::next_response::'); | ||
|
||
$addresses = $mail->getBcc(); | ||
expect($addresses) | ||
->toHaveCount(2) | ||
->each->toBeInstanceOf(Address::class) | ||
->and($addresses[0]) | ||
->getAddress()->toBe('[email protected]') | ||
->and($addresses[1]) | ||
->getAddress()->toBe('[email protected]') | ||
->and($middlewareReturn) | ||
->toBe('::next_response::'); | ||
}); | ||
|
||
it('does not add an address if config is empty and continues the pipeline', function () { | ||
Config::set('mail-allowlist.global.bcc', []); | ||
$mail = new Email; | ||
$context = new MessageContext($mail); | ||
|
||
$middlewareReturn = (new AddGlobalBcc)->handle($context, fn () => '::next_response::'); | ||
|
||
$addresses = $mail->getBcc(); | ||
expect($addresses) | ||
->toBeEmpty() | ||
->and($middlewareReturn) | ||
->toBe('::next_response::'); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
<?php | ||
|
||
use Illuminate\Support\Facades\Config; | ||
use Symfony\Component\Mime\Address; | ||
use Symfony\Component\Mime\Email; | ||
use TobMoeller\LaravelMailAllowlist\MailMiddleware\Addresses\AddGlobalCc; | ||
use TobMoeller\LaravelMailAllowlist\MailMiddleware\MessageContext; | ||
|
||
it('adds global cc addresses and continues the pipeline', function () { | ||
Config::set('mail-allowlist.global.cc', ['[email protected]', '[email protected]']); | ||
$mail = new Email; | ||
$context = new MessageContext($mail); | ||
|
||
$middlewareReturn = (new AddGlobalCc)->handle($context, fn () => '::next_response::'); | ||
|
||
$addresses = $mail->getCc(); | ||
expect($addresses) | ||
->toHaveCount(2) | ||
->each->toBeInstanceOf(Address::class) | ||
->and($addresses[0]) | ||
->getAddress()->toBe('[email protected]') | ||
->and($addresses[1]) | ||
->getAddress()->toBe('[email protected]') | ||
->and($middlewareReturn) | ||
->toBe('::next_response::'); | ||
}); | ||
|
||
it('does not add an address if config is empty and continues the pipeline', function () { | ||
Config::set('mail-allowlist.global.cc', []); | ||
$mail = new Email; | ||
$context = new MessageContext($mail); | ||
|
||
$middlewareReturn = (new AddGlobalCc)->handle($context, fn () => '::next_response::'); | ||
|
||
$addresses = $mail->getCc(); | ||
expect($addresses) | ||
->toBeEmpty() | ||
->and($middlewareReturn) | ||
->toBe('::next_response::'); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
<?php | ||
|
||
use Illuminate\Support\Facades\Config; | ||
use Symfony\Component\Mime\Address; | ||
use Symfony\Component\Mime\Email; | ||
use TobMoeller\LaravelMailAllowlist\MailMiddleware\Addresses\AddGlobalTo; | ||
use TobMoeller\LaravelMailAllowlist\MailMiddleware\MessageContext; | ||
|
||
it('adds global to addresses and continues the pipeline', function () { | ||
Config::set('mail-allowlist.global.to', ['[email protected]', '[email protected]']); | ||
$mail = new Email; | ||
$context = new MessageContext($mail); | ||
|
||
$middlewareReturn = (new AddGlobalTo)->handle($context, fn () => '::next_response::'); | ||
|
||
$to = $mail->getTo(); | ||
expect($to) | ||
->toHaveCount(2) | ||
->each->toBeInstanceOf(Address::class) | ||
->and($to[0]) | ||
->getAddress()->toBe('[email protected]') | ||
->and($to[1]) | ||
->getAddress()->toBe('[email protected]') | ||
->and($middlewareReturn) | ||
->toBe('::next_response::'); | ||
}); | ||
|
||
it('does not add an address if config is empty and continues the pipeline', function () { | ||
Config::set('mail-allowlist.global.to', []); | ||
$mail = new Email; | ||
$context = new MessageContext($mail); | ||
|
||
$middlewareReturn = (new AddGlobalTo)->handle($context, fn () => '::next_response::'); | ||
|
||
$to = $mail->getTo(); | ||
expect($to) | ||
->toBeEmpty() | ||
->and($middlewareReturn) | ||
->toBe('::next_response::'); | ||
}); |