Issue #3399645 by znerol, smustgrave: Use structured DSN instead of URI in system.mail mailer_dsn

merge-requests/5506/merge
Dave Long 2023-11-22 16:59:34 +00:00
parent 7cb99a11ac
commit 0b7c2a60a5
No known key found for this signature in database
GPG Key ID: ED52AE211E142771
13 changed files with 149 additions and 19 deletions

View File

@ -12,6 +12,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Mailer\Mailer; use Symfony\Component\Mailer\Mailer;
use Symfony\Component\Mailer\MailerInterface; use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mailer\Transport; use Symfony\Component\Mailer\Transport;
use Symfony\Component\Mailer\Transport\Dsn;
use Symfony\Component\Mime\Email; use Symfony\Component\Mime\Email;
/** /**
@ -35,11 +36,16 @@ use Symfony\Component\Mime\Email;
* *
* @code * @code
* $config['system.mail']['interface'] = [ 'default' => 'symfony_mailer' ]; * $config['system.mail']['interface'] = [ 'default' => 'symfony_mailer' ];
* $config['system.mail']['mailer_dsn'] = 'smtp://user:pass@smtp.example.com:25'; * $config['system.mail']['mailer_dsn'] = [
* 'scheme' => 'smtp',
* 'host' => 'smtp.example.com',
* 'port' => 25,
* 'user' => 'user',
* 'password' => 'pass',
* 'options' => [],
* ];
* @endcode * @endcode
* *
* Note that special characters in the mailer_dsn need to be URL encoded.
*
* @see https://symfony.com/doc/current/mailer.html#using-built-in-transports * @see https://symfony.com/doc/current/mailer.html#using-built-in-transports
* *
* @Mail( * @Mail(
@ -143,6 +149,7 @@ class SymfonyMailer implements MailInterface, ContainerFactoryPluginInterface {
protected function getMailer(): MailerInterface { protected function getMailer(): MailerInterface {
if (!isset($this->mailer)) { if (!isset($this->mailer)) {
$dsn = \Drupal::config('system.mail')->get('mailer_dsn'); $dsn = \Drupal::config('system.mail')->get('mailer_dsn');
$dsnObject = new Dsn(...$dsn);
// Symfony Mailer and Transport classes both optionally depend on the // Symfony Mailer and Transport classes both optionally depend on the
// event dispatcher. When provided, a MessageEvent is fired whenever an // event dispatcher. When provided, a MessageEvent is fired whenever an
@ -154,7 +161,9 @@ class SymfonyMailer implements MailInterface, ContainerFactoryPluginInterface {
// mails into the code path (i.e., event subscribers) of the new API. // mails into the code path (i.e., event subscribers) of the new API.
// Therefore, this plugin deliberately refrains from injecting the event // Therefore, this plugin deliberately refrains from injecting the event
// dispatcher. // dispatcher.
$transport = Transport::fromDsn($dsn, logger: $this->logger); $factories = Transport::getDefaultFactories(logger: $this->logger);
$transportFactory = new Transport($factories);
$transport = $transportFactory->fromDsnObject($dsnObject);
$this->mailer = new Mailer($transport); $this->mailer = new Mailer($transport);
} }

View File

@ -330,7 +330,14 @@ trait FunctionalTestSetupTrait {
// some tests expect to be able to test mail system implementations. // some tests expect to be able to test mail system implementations.
$config->getEditable('system.mail') $config->getEditable('system.mail')
->set('interface.default', 'test_mail_collector') ->set('interface.default', 'test_mail_collector')
->set('mailer_dsn', 'null://null') ->set('mailer_dsn', [
'scheme' => 'null',
'host' => 'null',
'user' => NULL,
'password' => NULL,
'port' => NULL,
'options' => [],
])
->save(); ->save();
// By default, verbosely display all errors and disable all production // By default, verbosely display all errors and disable all production

View File

@ -65,8 +65,12 @@ abstract class MigrateUpgradeExecuteTestBase extends MigrateUpgradeTestBase {
'value' => 'test_mail_collector', 'value' => 'test_mail_collector',
'required' => TRUE, 'required' => TRUE,
]; ];
$settings['config']['system.mail']['mailer_dsn'] = (object) [ $settings['config']['system.mail']['mailer_dsn']['scheme'] = (object) [
'value' => 'null://null', 'value' => 'null',
'required' => TRUE,
];
$settings['config']['system.mail']['mailer_dsn']['host'] = (object) [
'value' => 'null',
'required' => TRUE, 'required' => TRUE,
]; ];
$this->writeSettings($settings); $this->writeSettings($settings);

View File

@ -1,3 +1,9 @@
interface: interface:
default: 'php_mail' default: 'php_mail'
mailer_dsn: "sendmail://default" mailer_dsn:
scheme: 'sendmail'
host: 'default'
user: null
password: null
port: null
options: []

View File

@ -304,8 +304,45 @@ system.mail:
type: string type: string
label: 'Interface' label: 'Interface'
mailer_dsn: mailer_dsn:
type: string type: mapping
label: 'Symfony mailer transport DSN' label: 'Symfony mailer transport DSN'
mapping:
scheme:
type: string
label: 'Scheme'
constraints:
NotBlank:
message: 'The mailer DSN must contain a scheme.'
host:
type: string
label: 'Host'
constraints:
NotBlank:
message: 'The mailer DSN must contain a host (use "default" by default).'
user:
type: string
nullable: true
label: 'User'
password:
type: string
nullable: true
label: 'Password'
port:
type: integer
nullable: true
label: 'Port'
constraints:
Range:
min: 0
max: 65535
options:
type: sequence
label: 'Options'
sequence:
type: string
label: Option
constraints:
NotNull: []
system.theme.global: system.theme.global:
type: theme_settings type: theme_settings

View File

@ -19,8 +19,20 @@ process:
plugin: static_map plugin: static_map
source: 'mail_system/default-system' source: 'mail_system/default-system'
map: map:
DefaultMailSystem: 'sendmail://default' DefaultMailSystem:
MailTestCase: 'null://null' scheme: 'sendmail'
host: 'default'
user: null
password: null
port: null
options: []
MailTestCase:
scheme: 'null'
host: 'null'
user: null
password: null
port: null
options: []
destination: destination:
plugin: config plugin: config
config_name: system.mail config_name: system.mail

View File

@ -164,8 +164,21 @@ function system_post_update_set_blank_log_url_to_null() {
* Add new default mail transport dsn. * Add new default mail transport dsn.
*/ */
function system_post_update_mailer_dsn_settings() { function system_post_update_mailer_dsn_settings() {
}
/**
* Add new default mail transport dsn.
*/
function system_post_update_mailer_structured_dsn_settings() {
$config = \Drupal::configFactory()->getEditable('system.mail'); $config = \Drupal::configFactory()->getEditable('system.mail');
$config->set('mailer_dsn', 'sendmail://default')->save(); $config->set('mailer_dsn', [
'scheme' => 'sendmail',
'host' => 'default',
'user' => NULL,
'password' => NULL,
'port' => NULL,
'options' => [],
])->save();
} }
/** /**

View File

@ -30,7 +30,15 @@ class MailDsnSettingsUpdateTest extends UpdatePathTestBase {
// Confirm that config was created. // Confirm that config was created.
$config = $this->config('system.mail'); $config = $this->config('system.mail');
$this->assertEquals('sendmail://default', $config->get('mailer_dsn')); $expected = [
'scheme' => 'sendmail',
'host' => 'default',
'user' => NULL,
'password' => NULL,
'port' => NULL,
'options' => [],
];
$this->assertEquals($expected, $config->get('mailer_dsn'));
} }
} }

View File

@ -59,7 +59,14 @@ class MigrateSystemConfigurationTest extends MigrateDrupal7TestBase {
'interface' => [ 'interface' => [
'default' => 'php_mail', 'default' => 'php_mail',
], ],
'mailer_dsn' => 'sendmail://default', 'mailer_dsn' => [
'scheme' => 'sendmail',
'host' => 'default',
'user' => NULL,
'password' => NULL,
'port' => NULL,
'options' => [],
],
], ],
'system.maintenance' => [ 'system.maintenance' => [
// langcode is not handled by the migration. // langcode is not handled by the migration.

View File

@ -197,7 +197,14 @@ abstract class InstallerTestBase extends BrowserTestBase {
$this->container->get('config.factory') $this->container->get('config.factory')
->getEditable('system.mail') ->getEditable('system.mail')
->set('interface.default', 'test_mail_collector') ->set('interface.default', 'test_mail_collector')
->set('mailer_dsn', 'null://null') ->set('mailer_dsn', [
'scheme' => 'null',
'host' => 'null',
'user' => NULL,
'password' => NULL,
'port' => NULL,
'options' => [],
])
->save(); ->save();
$this->installDefaultThemeFromClassProperty($this->container); $this->installDefaultThemeFromClassProperty($this->container);

View File

@ -430,8 +430,14 @@ abstract class KernelTestBase extends TestCase implements ServiceProviderInterfa
// While this should be enforced via settings.php prior to installation, // While this should be enforced via settings.php prior to installation,
// some tests expect to be able to test mail system implementations. // some tests expect to be able to test mail system implementations.
$GLOBALS['config']['system.mail']['interface']['default'] = 'test_mail_collector'; $GLOBALS['config']['system.mail']['interface']['default'] = 'test_mail_collector';
$GLOBALS['config']['system.mail']['mailer_dsn'] = 'null://null'; $GLOBALS['config']['system.mail']['mailer_dsn'] = [
'scheme' => 'null',
'host' => 'null',
'user' => NULL,
'password' => NULL,
'port' => NULL,
'options' => [],
];
// Manually configure the default file scheme so that modules that use file // Manually configure the default file scheme so that modules that use file
// functions don't have to install system and its configuration. // functions don't have to install system and its configuration.
// @see file_default_scheme() // @see file_default_scheme()

View File

@ -114,7 +114,14 @@ class MailManagerTest extends UnitTestCase {
$this->configFactory = $this->getConfigFactoryStub([ $this->configFactory = $this->getConfigFactoryStub([
'system.mail' => [ 'system.mail' => [
'interface' => $interface, 'interface' => $interface,
'mailer_dsn' => 'null://null', 'mailer_dsn' => [
'scheme' => 'null',
'host' => 'null',
'user' => NULL,
'password' => NULL,
'port' => NULL,
'options' => [],
],
], ],
'system.site' => [ 'system.site' => [
'mail' => 'test@example.com', 'mail' => 'test@example.com',

View File

@ -46,7 +46,14 @@ class PhpMailTest extends UnitTestCase {
$this->configFactory = $this->getConfigFactoryStub([ $this->configFactory = $this->getConfigFactoryStub([
'system.mail' => [ 'system.mail' => [
'interface' => [], 'interface' => [],
'mailer_dsn' => 'null://null', 'mailer_dsn' => [
'scheme' => 'null',
'host' => 'null',
'user' => NULL,
'password' => NULL,
'port' => NULL,
'options' => [],
],
], ],
'system.site' => [ 'system.site' => [
'mail' => 'test@example.com', 'mail' => 'test@example.com',