diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
index 902d3468fc835..59c6883802af5 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
@@ -2091,6 +2091,15 @@ private function addMailerSection(ArrayNodeDefinition $rootNode, callable $enabl
->end()
->end()
->end()
+ ->arrayNode('smtp')
+ ->fixXmlConfig('authenticator')
+ ->children()
+ ->arrayNode('authenticators')
+ ->info('Services implementing AuthenticatorInterface to use with the EsmtpTransport')
+ ->prototype('scalar')->end()
+ ->end()
+ ->end()
+ ->end()
->end()
->end()
->end()
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
index d03932f8c4840..7041545337e45 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
@@ -2556,6 +2556,11 @@ private function registerMailerConfiguration(array $config, ContainerBuilder $co
} else {
$mailer->replaceArgument(1, $messageBus ? new Reference($messageBus) : new Reference('messenger.default_bus', ContainerInterface::NULL_ON_INVALID_REFERENCE));
}
+ $authenticators = [];
+ foreach ($config['smtp']['authenticators'] ?? [] as $authenticator) {
+ $authenticators[] = new Reference($authenticator);
+ }
+ $container->getDefinition('mailer.transport_factory.smtp')->setArgument(3, $authenticators);
$classToServices = [
MailerBridge\Brevo\Transport\BrevoTransportFactory::class => 'mailer.transport_factory.brevo',
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd
index 532cf022d3c66..3fa69a6a25aac 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd
@@ -737,6 +737,7 @@
+
@@ -758,6 +759,12 @@
+
+
+
+
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/mailer_with_authenticators.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/mailer_with_authenticators.php
new file mode 100644
index 0000000000000..4e3bade10f552
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/mailer_with_authenticators.php
@@ -0,0 +1,20 @@
+extension('framework', [
+ 'annotations' => false,
+ 'http_method_override' => false,
+ 'handle_all_throwables' => true,
+ 'php_errors' => ['log' => true],
+ 'mailer' => [
+ 'smtp' => [
+ 'authenticators' => [
+ 'my_authenticator_service1',
+ 'my_authenticator_service2',
+ ],
+ ],
+ ],
+ ]);
+};
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/mailer_with_authenticators.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/mailer_with_authenticators.xml
new file mode 100644
index 0000000000000..ee9657ea7da59
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/mailer_with_authenticators.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+ my_authenticator_service1
+ my_authenticator_service2
+
+
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/mailer_with_authenticators.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/mailer_with_authenticators.yml
new file mode 100644
index 0000000000000..05d129c6aa4e8
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/mailer_with_authenticators.yml
@@ -0,0 +1,11 @@
+framework:
+ annotations: false
+ http_method_override: false
+ handle_all_throwables: true
+ php_errors:
+ log: true
+ mailer:
+ smtp:
+ authenticators:
+ - my_authenticator_service1
+ - my_authenticator_service2
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php
index 9036fc6d58da7..add701479f8ed 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php
@@ -2031,6 +2031,13 @@ public function testMailerWithSpecificMessageBus()
$this->assertEquals(new Reference('app.another_bus'), $container->getDefinition('mailer.mailer')->getArgument(1));
}
+ public function testMailerWithAuthenticators()
+ {
+ $container = $this->createContainerFromFile('mailer_with_authenticators');
+
+ $this->assertCount(2, $container->getDefinition('mailer.mailer')->getArgument(3));
+ }
+
public function testHttpClientMockResponseFactory()
{
$container = $this->createContainerFromFile('http_client_mock_response_factory');
diff --git a/src/Symfony/Component/Mailer/Transport/Smtp/Auth/AuthTokenProviderInterface.php b/src/Symfony/Component/Mailer/Transport/Smtp/Auth/AuthTokenProviderInterface.php
new file mode 100644
index 0000000000000..4714aa4f2ae2c
--- /dev/null
+++ b/src/Symfony/Component/Mailer/Transport/Smtp/Auth/AuthTokenProviderInterface.php
@@ -0,0 +1,26 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Mailer\Transport\Smtp\Auth;
+
+/**
+ * The auth token provider knows how to create a valid token for the XOAuth2Authenticator.
+ *
+ * Usually with OAuth, you will need to do some web request to fetch the token.
+ * You also want to cache the token for as long as it is valid.
+ */
+interface AuthTokenProviderInterface
+{
+ /**
+ * Acquire the authentication token.
+ */
+ public function getToken(): string;
+}
diff --git a/src/Symfony/Component/Mailer/Transport/Smtp/Auth/XOAuth2Authenticator.php b/src/Symfony/Component/Mailer/Transport/Smtp/Auth/XOAuth2Authenticator.php
index c3aaa4909dbd0..61a6d88a8d484 100644
--- a/src/Symfony/Component/Mailer/Transport/Smtp/Auth/XOAuth2Authenticator.php
+++ b/src/Symfony/Component/Mailer/Transport/Smtp/Auth/XOAuth2Authenticator.php
@@ -22,6 +22,13 @@
*/
class XOAuth2Authenticator implements AuthenticatorInterface
{
+ private ?AuthTokenProviderInterface $tokenProvider;
+
+ public function __construct(AuthTokenProviderInterface $tokenProvider = null)
+ {
+ $this->tokenProvider = $tokenProvider;
+ }
+
public function getAuthKeyword(): string
{
return 'XOAUTH2';
@@ -32,6 +39,7 @@ public function getAuthKeyword(): string
*/
public function authenticate(EsmtpTransport $client): void
{
- $client->executeCommand('AUTH XOAUTH2 '.base64_encode('user='.$client->getUsername()."\1auth=Bearer ".$client->getPassword()."\1\1")."\r\n", [235]);
+ $token = $this->tokenProvider?->getToken() : $client->getPassword();
+ $client->executeCommand('AUTH XOAUTH2 '.base64_encode('user='.$client->getUsername()."\1auth=Bearer ".$token."\1\1")."\r\n", [235]);
}
}
diff --git a/src/Symfony/Component/Mailer/Transport/Smtp/EsmtpTransport.php b/src/Symfony/Component/Mailer/Transport/Smtp/EsmtpTransport.php
index 2683050c9cb22..3551b8e65919c 100644
--- a/src/Symfony/Component/Mailer/Transport/Smtp/EsmtpTransport.php
+++ b/src/Symfony/Component/Mailer/Transport/Smtp/EsmtpTransport.php
@@ -27,11 +27,17 @@
*/
class EsmtpTransport extends SmtpTransport
{
+ /**
+ * @var AuthenticatorInterface[]
+ */
private array $authenticators = [];
private string $username = '';
private string $password = '';
private array $capabilities;
+ /**
+ * @param AuthenticatorInterface[]|null $authenticators
+ */
public function __construct(string $host = 'localhost', int $port = 0, bool $tls = null, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null, AbstractStream $stream = null, array $authenticators = null)
{
parent::__construct($stream, $dispatcher, $logger);
diff --git a/src/Symfony/Component/Mailer/Transport/Smtp/EsmtpTransportFactory.php b/src/Symfony/Component/Mailer/Transport/Smtp/EsmtpTransportFactory.php
index a15d12245d19b..fa5a537a7b242 100644
--- a/src/Symfony/Component/Mailer/Transport/Smtp/EsmtpTransportFactory.php
+++ b/src/Symfony/Component/Mailer/Transport/Smtp/EsmtpTransportFactory.php
@@ -11,23 +11,41 @@
namespace Symfony\Component\Mailer\Transport\Smtp;
+use Psr\EventDispatcher\EventDispatcherInterface;
+use Psr\Log\LoggerInterface;
use Symfony\Component\Mailer\Transport\AbstractTransportFactory;
use Symfony\Component\Mailer\Transport\Dsn;
+use Symfony\Component\Mailer\Transport\Smtp\Auth\AuthenticatorInterface;
use Symfony\Component\Mailer\Transport\Smtp\Stream\SocketStream;
use Symfony\Component\Mailer\Transport\TransportInterface;
+use Symfony\Contracts\HttpClient\HttpClientInterface;
/**
* @author Konstantin Myakshin
*/
final class EsmtpTransportFactory extends AbstractTransportFactory
{
+ /**
+ * @var AuthenticatorInterface[]
+ */
+ private ?array $authenticators;
+
+ /**
+ * @param AuthenticatorInterface[]|null $authenticators
+ */
+ public function __construct(EventDispatcherInterface $dispatcher = null, HttpClientInterface $client = null, LoggerInterface $logger = null, array $authenticators = null)
+ {
+ parent::__construct($dispatcher, $client, $logger);
+ $this->authenticators = $authenticators;
+ }
+
public function create(Dsn $dsn): TransportInterface
{
$tls = 'smtps' === $dsn->getScheme() ? true : null;
$port = $dsn->getPort(0);
$host = $dsn->getHost();
- $transport = new EsmtpTransport($host, $port, $tls, $this->dispatcher, $this->logger);
+ $transport = new EsmtpTransport($host, $port, $tls, $this->dispatcher, $this->logger, null, $this->authenticators);
/** @var SocketStream $stream */
$stream = $transport->getStream();