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\MailerInterface;
use Symfony\Component\Mailer\Transport;
use Symfony\Component\Mailer\Transport\Dsn;
use Symfony\Component\Mime\Email;
/**
@ -35,11 +36,16 @@ use Symfony\Component\Mime\Email;
*
* @code
* $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
*
* 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
*
* @Mail(
@ -143,6 +149,7 @@ class SymfonyMailer implements MailInterface, ContainerFactoryPluginInterface {
protected function getMailer(): MailerInterface {
if (!isset($this->mailer)) {
$dsn = \Drupal::config('system.mail')->get('mailer_dsn');
$dsnObject = new Dsn(...$dsn);
// Symfony Mailer and Transport classes both optionally depend on the
// 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.
// Therefore, this plugin deliberately refrains from injecting the event
// 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);
}

View File

@ -330,7 +330,14 @@ trait FunctionalTestSetupTrait {
// some tests expect to be able to test mail system implementations.
$config->getEditable('system.mail')
->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();
// 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',
'required' => TRUE,
];
$settings['config']['system.mail']['mailer_dsn'] = (object) [
'value' => 'null://null',
$settings['config']['system.mail']['mailer_dsn']['scheme'] = (object) [
'value' => 'null',
'required' => TRUE,
];
$settings['config']['system.mail']['mailer_dsn']['host'] = (object) [
'value' => 'null',
'required' => TRUE,
];
$this->writeSettings($settings);

View File

@ -1,3 +1,9 @@
interface:
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
label: 'Interface'
mailer_dsn:
type: string
type: mapping
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:
type: theme_settings

View File

@ -19,8 +19,20 @@ process:
plugin: static_map
source: 'mail_system/default-system'
map:
DefaultMailSystem: 'sendmail://default'
MailTestCase: 'null://null'
DefaultMailSystem:
scheme: 'sendmail'
host: 'default'
user: null
password: null
port: null
options: []
MailTestCase:
scheme: 'null'
host: 'null'
user: null
password: null
port: null
options: []
destination:
plugin: config
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.
*/
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->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.
$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' => [
'default' => 'php_mail',
],
'mailer_dsn' => 'sendmail://default',
'mailer_dsn' => [
'scheme' => 'sendmail',
'host' => 'default',
'user' => NULL,
'password' => NULL,
'port' => NULL,
'options' => [],
],
],
'system.maintenance' => [
// langcode is not handled by the migration.

View File

@ -197,7 +197,14 @@ abstract class InstallerTestBase extends BrowserTestBase {
$this->container->get('config.factory')
->getEditable('system.mail')
->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();
$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,
// some tests expect to be able to test mail system implementations.
$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
// functions don't have to install system and its configuration.
// @see file_default_scheme()

View File

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

View File

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