-
-
Save MatteoOreficeIT/2c8f061e81a20fa96b8176efd97dbac5 to your computer and use it in GitHub Desktop.
<?php | |
/** | |
* Inspired from | |
* 1. https://github.com/laravel/framework/blob/5.6/src/Illuminate/Mail/TransportManager.php | |
* 2. https://github.com/laravel/framework/blob/5.6/src/Illuminate/Mail/MailServiceProvider.php | |
* | |
* A service provider to register a custom mailer with Dynamic Options ( determined at Dependency Injection Container resolve-time ) | |
* | |
* 1. resolve-time options: host, port, user, password, secure: [tls,ssl] could be determined at DI container resolve-time | |
* 2. global options in mail.dynamic config file | |
* | |
* Define in mail.php such as structure for global options | |
* | |
* 'dynamic' => [ | |
* 'auth_mode' => 'plain', | |
* 'timeout' => 2, | |
* 'stream' => [ | |
* 'ssl'=> [ | |
* 'verify_peer' => false, | |
* 'verify_peer_name' => false, | |
* ] | |
* ] | |
* ], | |
*/ | |
namespace App\Providers; | |
use Illuminate\Foundation\Application; | |
use Illuminate\Mail\Mailer; | |
use Illuminate\Mail\TransportManager; | |
use Swift_SmtpTransport as SmtpTransport; | |
use Swift_Mailer; | |
use Illuminate\Support\Arr; | |
use Illuminate\Support\Str; | |
use Illuminate\Support\ServiceProvider; | |
class DynamicMailerServiceProvider extends ServiceProvider | |
{ | |
/** | |
* You need to implement this method to return custom options | |
* allowed key: host, port, user, password, secure: [tls,ssl] | |
* @return array | |
*/ | |
abstract protected function getDynamicOptions(); | |
/** | |
* Indicates if loading of the provider is deferred so the getDynamicOptions() will be called late | |
* in the code when you request app('myapp.dynamic.mailer') | |
* | |
* @var bool | |
*/ | |
protected $defer = true; | |
/** | |
* Register the service provider. | |
* | |
* @return void | |
*/ | |
public function register() | |
{ | |
$this->registerSwiftMailer(); | |
$this->registerIlluminateMailer(); | |
} | |
/** | |
* Register the Illuminate mailer instance. | |
* | |
* @return void | |
*/ | |
protected function registerIlluminateMailer() | |
{ | |
$this->app->singleton('myapp.dynamic.mailer', function ($app) { | |
// Once we have create the mailer instance, we will set a container instance | |
// on the mailer. This allows us to resolve mailer classes via containers | |
// for maximum testability on said classes instead of passing Closures. | |
$mailer = new Mailer( | |
$app['view'], $app['myapp.dynamic.swift.mailer'], $app['events'] | |
); | |
// if ($app->bound('queue')) { | |
// $mailer->setQueue($app['queue']); | |
// } | |
// Next we will set all of the global addresses on this mailer, which allows | |
// for easy unification of all "from" addresses as well as easy debugging | |
// of sent messages since they get be sent into a single email address. | |
foreach (['from', 'reply_to', 'to'] as $type) { | |
$this->setGlobalAddress($mailer, $app->make('config')->get('mail'), $type); | |
} | |
return $mailer; | |
}); | |
} | |
/** | |
* Set a global address on the mailer by type. | |
* | |
* @param \Illuminate\Mail\Mailer $mailer | |
* @param array $config | |
* @param string $type | |
* @return void | |
*/ | |
protected function setGlobalAddress($mailer, array $config, $type) | |
{ | |
$address = Arr::get($config, $type); | |
if (is_array($address) && isset($address['address'])) { | |
$mailer->{'always'.Str::studly($type)}($address['address'], $address['name']); | |
} | |
} | |
/** | |
* Register the Swift Mailer instance. | |
* | |
* @return void | |
*/ | |
public function registerSwiftMailer() | |
{ | |
$this->registerSwiftTransport(); | |
// Once we have the transporter registered, we will register the actual Swift | |
// mailer instance, passing in the transport instances, which allows us to | |
// override this transporter instances during app start-up if necessary. | |
$this->app->singleton('myapp.dynamic.swift.mailer', function ($app) { | |
return new Swift_Mailer($app['myapp.dynamic.swift.transport']->driver('dynamicSmtpSettings')); | |
}); | |
} | |
/** | |
* Register the Swift Transport instance. | |
* | |
* @return void | |
*/ | |
protected function registerSwiftTransport() | |
{ | |
$this->app->singleton('myapp.dynamic.swift.transport', function ($app) { | |
return tap(new TransportManager($app),function($tm){ | |
$tm->extend('dynamicSmtpSettings',function(Application $app){ | |
// store global options in config/mail-dynamic.php | |
$globalOptions = config('mail.dynamic'); | |
// retrieve dynamic options at DI make time | |
$dynamicConfig = $this->getDynamicOptions(); | |
// The Swift SMTP transport instance will allow us to use any SMTP backend | |
// for delivering mail such as Sendgrid, Amazon SES, or a custom server | |
// a developer has available. We will just pass this configured host. | |
$transport = SmtpTransport::newInstance( | |
$dynamicConfig['host'], | |
$dynamicConfig['port'] | |
); | |
if (!empty($dynamicConfig['secure'])) { | |
$transport->setEncryption($dynamicConfig['secure']); | |
} | |
// Once we have the transport we will check for the presence of a username | |
// and password. If we have it we will set the credentials on the Swift | |
// transporter instance so that we'll properly authenticate delivery. | |
if ($dynamicConfig['mail_autent']) { | |
$transport->setUsername($dynamicConfig['user']); | |
$transport->setPassword($dynamicConfig['password']); | |
} | |
/** | |
* @see https://goo.gl/9R13we | |
*/ | |
if (isset($globalOptions['auth_mode'])) { | |
$transport->setAuthMode($globalOptions['auth_mode']); | |
} | |
if (isset($globalOptions['timeout'])) { | |
$transport->setTimeout($globalOptions['timeout']); | |
} | |
// Next we will set any stream context options specified for the transport | |
// and then return it. The option is not required any may not be inside | |
// the configuration array at all so we'll verify that before adding. | |
if (isset($globalOptions['stream'])) { | |
$transport->setStreamOptions($globalOptions['stream']); | |
} | |
return $transport; | |
}); | |
}); | |
}); | |
} | |
/** | |
* Get the services provided by the provider. | |
* | |
* @return array | |
*/ | |
public function provides() | |
{ | |
return [ | |
'myapp.dynamic.mailer', 'myapp.dynamic.swift.mailer', 'myapp.dynamic.swift.transport' | |
]; | |
} | |
} |
@MatteoOreficeIT
Hi,I have a question in this code,what is the impact of bind and singleton
https://gist.github.com/MatteoOreficeIT/2c8f061e81a20fa96b8176efd97dbac5#file-dynamicmailerserviceprovider-php-L136
https://github.com/MatteoOreficeIT/laravel-dynamic-mailer/blob/master/app/Providers/AbstractDynamicMailerServiceProvider.php#L131
My understanding is that the bind function will generate multiple class objects in the loop, which may affect the memory
Hi @j7550155 , We did it because the base laravel implementation allows to settle only one mailer in a app
- we want have the chance to obtain a mailer class but with different settings extracted from a domain model ( client db record ), every client has a factory smtp server with different settings
- see CustomMailer provider in https://github.com/MatteoOreficeIT/laravel-dynamic-mailer
- in our applications we have scripts that inject only one smtp mail at time, not in a loop
- if you want you can use the documented-in-source-code-only Container::forgetInstance to deallocate binded instance in a loop
- remember php needs in some circunstances to call gc_collect_cycles to cleanup memory
How should this run, a little bit of documentation would be great.
Classes defined as abstract may not be instantiated, and any class that contains at least one abstract method must also be abstract.
Your class is not abstract but contains an abstract function, so it results in a fatal error.
Sorry @MarioPerini visit https://github.com/MatteoOreficeIT/laravel-dynamic-mailer for a down-to-earth example !
Hi, Sorry but I could not make it before
See an improved demo project, it is not a composer package but you can easily C&P classes from it
https://github.com/MatteoOreficeIT/laravel-dynamic-mailer