From 713e7d276d401817383fc56c51a90af512c1bc5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alo=C3=AFs=20Micard?= Date: Tue, 9 Nov 2021 19:31:40 +0100 Subject: [PATCH] New laravel dynamic emails blog post Closes: #6 --- ...laravel-dynamic-smtp-mail-configuration.md | 280 ++++++++++++++++++ static/img/laravel-mail-internals.png | Bin 0 -> 27961 bytes 2 files changed, 280 insertions(+) create mode 100644 content/posts/laravel-dynamic-smtp-mail-configuration.md create mode 100644 static/img/laravel-mail-internals.png diff --git a/content/posts/laravel-dynamic-smtp-mail-configuration.md b/content/posts/laravel-dynamic-smtp-mail-configuration.md new file mode 100644 index 0000000..ff6d861 --- /dev/null +++ b/content/posts/laravel-dynamic-smtp-mail-configuration.md @@ -0,0 +1,280 @@ ++++ +title = "Laravel dynamic SMTP mail configuration" +date = "2021-11-09" +author = "Aloïs Micard" +authorTwitter = "" #do not include @ cover = "" +tags = ["Laravel", "PHP", "Tutorial"] +keywords = ["Laravel", "SMTP", "Dynamic", "PHP", "Tutorial"] +description = "How to use dynamic SMTP credentials with Laravel." +showFullContent = false ++++ + +Hello friend... + +It has been a while. + +I have been very busy lately with work, open source and *life* that I didn't find the energy to write a blog post. +Despite having some good ideas, I wasn't really in the mood. + +Hopefully, I now have the energy and the subject to make a good blog post: let's talk +about [Laravel](https://laravel.com/) and emails! + +# 1. Laravel and SMTP + +## 1.1. Configuration + +Laravel SMTP [Mail](https://laravel.com/docs/8.x/mail) support is truly awesome and work out-of-the-box without +requiring anything more than a few env variables: + +```text +MAIL_MAILER=smtp +MAIL_HOST=mail1.example.org +MAIL_PORT=587 +MAIL_USERNAME=demo@example.org +MAIL_PASSWORD=foo +MAIL_ENCRYPTION=tls +MAIL_FROM_ADDRESS=no-reply@example.org +MAIL_FROM_NAME=Demo App +``` + +> Note: The initial setup only requires these environment variables because the smtp mailer is already configured in `config/mail.php`. + +## 1.2. Creating an email + +Once everything is configured, creating an email is as simple as running this command: + +```shell +php artisan make:mail Greetings +``` + +This command will generate a sample email in `app/Mail/Greetings` and you'll just need to design it afterwards. + +## 1.3. Sending an email + +Sending an email to a user with Laravel can be either done: + +- using `\Illuminate\Notifications\RoutesNotifications::notify`: + +```php +$user->notify(new Greetings()); +``` + +- or using `\Illuminate\Support\Facades\Notification::send`: + +```php +Notification::send($users, new Greetings()); +``` + +> Note: the later syntax is especially useful when bulk sending emails. + +See how simple it is? ~~I wonder what would be the limitations.~~ + +Eh! What if we need to 'whitelabelize' our application. :-) + +--- + +# 2. Dynamic SMTP configuration + +In our scenario, we have the need to [whitelabelize](https://en.wikipedia.org/wiki/White-label_product) our application: +each `User` will belongs to a `Provider` that will have custom SMTP settings. So when sending email to a user we need to +configure dynamically the SMTP credentials to use depending on the `$user->provider`. + +**Can Laravel help us doing so?** + +After a bit of googling and reading the official documentation, there's no out-of-the-box support for dynamic SMTP +configuration, certainly because there would be 100x way of doing it, each way depending on your exact use-case. + +**So, we're screwed?** + +Not yet, because Laravel allows us to tweak almost **anything**, so we just need to find our way. + +## 2.1. Designing the models + +Here's a quick visualization of our models: + +```php +/** + * @property Provider $provider + */ +class User extends Model +{ + public function provider(): BelongsTo + { + return $this->belongsTo(Provider::class); + } +} +``` + +For the `User` model there's nothing special: we only link the user to a `Provider`. + +```php +/** + * @property array $mail_configuration + * @property Provider $provider + */ +class Provider +{ + protected $casts = [ + 'mail_configuration' => 'encrypted:array' + ]; + + public function users(): HasMany + { + return $this->hasMany(User::class); + } +} +``` + +The `Provider` model has many `Users` and has a `mail_configuration` field which is encrypted and that will contain all +the SMTP credentials. + +## 2.2. Digging down the internals + +Now that our models are ready, we must find a way to use the provider configuration to send the email. Let's dig down +in Laravel source code to understand how emails works: + +Remember the two-ways of sending emails? + +- `\Illuminate\Notifications\RoutesNotifications::notify` +- `\Illuminate\Support\Facades\Notification::send` + +What we need to do is find the common path between these two methods, and see if we can override some +behavior in there. + +![](/img/laravel-mail-internals.png) + +As you can see here, the methods share the same execution path that end up +calling `\Illuminate\Notifications\Channels\MailChannel::send`. So how can we hook up into this path? + +The answer lies in `\Illuminate\Notifications\NotificationSender::sendToNotifiable`: + +```php +protected function sendToNotifiable($notifiable, $id, $notification, $channel) +{ + if (! $notification->id) { + $notification->id = $id; + } + + if (! $this->shouldSendNotification($notifiable, $notification, $channel)) { + return; + } + + $response = $this->manager->driver($channel)->send($notifiable, $notification); + + $this->events->dispatch( + new NotificationSent($notifiable, $notification, $channel, $response) + ); +} +``` + +As you can see this method is looking for a driver to use with the `$channel` and finally calls the `send()` +method. So what we can do is registering a special SMTP driver that will use dynamic SMTP settings. Fortunately +registering a custom driver is a common use-case and there's a straightforward way. + +## 2.3. Creating a custom MailChannel + +```php +class ProviderMailChannel extends MailChannel +{ + public function send($notifiable, Notification $notification) + { + // TODO: override the SMTP configuration + parent::send($notifiable, $notification); + } +} +``` + +## 2.4. Registering the ProviderMailChannel + +All we need to know is extend (i.e: register a custom driver creator) for the `mail` channel. +This way when an email is sent it will be sent using the `ProviderMailChannel`. + +```php +class AppServiceProvider extends ServiceProvider +{ + public function boot() + { + /** @var ChannelManager $channelManager */ + $channelManager = $this->app->get(ChannelManager::class); + $channelManager->extend('mail', function (Application $application) { + return new ProviderMailChannel($application->get('mail.manager'), $application->get(Markdown::class)); + }); + } +} +``` + +## 2.5. Creating a custom Mailer + +Now that we are hooked up into the mail sending flow, we need to actually send the email. For doing so we need to instantiate +custom `\Illuminate\Mail\Mailer` instance that will be configured using the provider settings. To register such dynamic +configurable service we will use the power of +the [Service container](https://laravel.com/docs/8.x/container#binding-basics). + +```php +class AppServiceProvider extends ServiceProvider +{ + public function register() + { + // When running in testing environment then return the mocked mail implementation + if (env('APP_ENV') === 'testing') { + $this->app->singleton('custom.mailer', MailFake::class); + return; + } + + // Register a custom mailer named `custom.mailer` that will receive his configuration dynamically + $this->app->bind('custom.mailer', function ($app, $parameters) { + $transport = new Swift_SmtpTransport($parameters['host'], $parameters['port']); + $transport->setUsername($parameters['username']); + $transport->setPassword($parameters['password']); + $transport->setEncryption($parameters['encryption']); + + $mailer = new Mailer('', $app->get('view'), new Swift_Mailer($transport), $app->get('events')); + $mailer->alwaysFrom($from_address, $from_name); + + return $mailer; + }); + } + + public function boot() + { + /** @var ChannelManager $channelManager */ + $channelManager = $this->app->get(ChannelManager::class); + $channelManager->extend('mail', function (Application $application) { + return new ProviderMailChannel($application->get('mail.manager'), $application->get(Markdown::class)); + }); + } +} +``` + +Now we can instantiate this custom Mailer by doing the following: + +```php +$mailer = app()->make('custom.mailer', $configuration); +// do something with $mailer +``` + +Where `$configuration` is the custom SMTP configuration. + +## 2.6. Plug the custom Mailer into the ProviderMailChannel + +Finally, all we need to do is to read the `Provider` mail configuration +and use it to instantiate our `custom.mailer` and then, use it to send the actual email. + +```php +class ProviderMailChannel extends MailChannel +{ + public function send($notifiable, Notification $notification) + { + $message = $notification->toMail($notifiable); + + $mailer = app()->make('custom.mailer', $notifiable->provider->mail_configuration); + $message->send($mailer); + } +} +``` + +# 3. Conclusion + +That all folks. You are now capable of sending email using dynamic SMTP credentials based on the use-case. + +Happy hacking! \ No newline at end of file diff --git a/static/img/laravel-mail-internals.png b/static/img/laravel-mail-internals.png new file mode 100644 index 0000000000000000000000000000000000000000..4be6dd7af63e3f307206bdbdf1bebd58709659ee GIT binary patch literal 27961 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