No answer so here is my solution. Others may find this useful.
Use ->extend as above to create a custom Transport driver. Make this driver act as a resolver. When ->send() is called, resolve the transport property and delegate to the driver that you set.
Example:
/**
* {@inheritdoc}
*/
public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null)
{
// forward this on to the declared transport (driver)
return $this->transport->send($message, $failedRecipients);
}
/**
* Change the mail driver at run-time
*/
public function setDriver($driver, $config = [])
{
if (is_string($driver) && $driver != 'smtp') {
$driver = new $driver($this->client, $config['secret'], $config['endpoint'] ?? null);
$this->transport = $driver;
}
// set to smtp driver
if ($driver === 'smtp') {
$this->transport = $this->createSmtpDriver();
}
if (!($this->transport instanceof \Swift_Transport)) {
$name = get_class($this->transport);
throw new \Swift_TransportException("$name not found or is not an instance of \Swift_Transport");
}
return $this;
}
And, finally if I want a specific set of Mailable's to use a different transport (Maybe admin emails don't want to be run through SendGrid)
use App\Mail\Transport\SmtpDriver;
class AdminEmailError extends Mailable
{
use Queueable, SerializesModels, SmtpDriver;
...
}
trait SmtpDriver
{
/**
* Send the message using the given mailer.
*
* @param \Illuminate\Contracts\Mail\Mailer $mailer
* @return void
*/
public function send(MailerContract $mailer)
{
// if we are using our custom Transport Router, set the driver to use smtp
$transport = $mailer->getSwiftMailer()->getTransport();
if (method_exists($transport, 'setDriver')) {
$transport->setDriver('smtp');
}
parent::send($mailer);
}
}