Symfony Mailer it’s a cool way for sending emails from PHP applications. It has a bunch of predefined transports that allow you to send emails through SMTP, Sendgrid, SES, … and may more options. But sometimes we need to do something special that hasn’t been done before.

There is a way to easily create your own custom transport factory which will allow us to do anything required before creating the actual transport. For example I needed to get the AWS SES credentials.

The new factory needs to implement Symfony\Component\Mailer\Transport\TransportFactoryInterface. To remove some boilerplate you can even extend from Symfony\Component\Mailer\Transport\AbstractTransportFactory which will simplify the new factory:

final class CustomTransportFactory extends AbstractTransportFactory
{
    public function create(Dsn $dsn): TransportInterface
    {
        // create and return the transport
    }

    protected function getSupportedSchemes(): array
    {
        return ['custom_schema'];
    }
}

Finally, declare the new factory in setting tag the tag mailer.transport_factory with one of the following methods:

# config/services.yaml
mailer.transport_factory.custom:
    class: App\CustomTransportFactory
    parent: mailer.transport_factory.abstract
    tags:
      - {name: mailer.transport_factory}
<!-- config/services.xml -->
<service id="mailer.transport_factory.custom" class="App\CustomTransportFactory" parent="mailer.transport_factory.abstract">
    <tag name="mailer.transport_factory"/>
</service>
// config/services.php
$services->set('mailer.transport_factory.custom', App\CustomTransportFactory::class)
          ->parent('mailer.transport_factory.abstract')
          ->tag('mailer.transport_factory');

I opened a pull request to add this info to the official Symfony Mailer documentation.