From 2c68ba8d04c25ab41bb3b270f6632a8571e9230b Mon Sep 17 00:00:00 2001 From: IanM Date: Sat, 20 Dec 2025 00:01:12 +0000 Subject: [PATCH 1/3] fix: backwards tls/ssl encryption mapping --- .../core/js/src/admin/components/MailPage.tsx | 38 ++++++++++++++++++- .../js/src/common/components/FormGroup.tsx | 2 +- framework/core/locale/core.yml | 4 ++ framework/core/src/Mail/SmtpDriver.php | 14 ++++++- 4 files changed, 53 insertions(+), 5 deletions(-) diff --git a/framework/core/js/src/admin/components/MailPage.tsx b/framework/core/js/src/admin/components/MailPage.tsx index 126ac5368d..dee53e056a 100644 --- a/framework/core/js/src/admin/components/MailPage.tsx +++ b/framework/core/js/src/admin/components/MailPage.tsx @@ -138,15 +138,42 @@ export default class MailPage exten ); if (!!fieldKeys.length) { + const driver = this.setting('mail_driver')(); + const descriptionKey = `core.admin.email.${driver}_description`; + const descriptionText = app.translator.trans(descriptionKey); + items.add( 'mail_driver_settings',
{fieldKeys.map((field) => { const fieldInfo = fields[field]; + // For encryption field, show all help text options above the dropdown + let helpText; + if (field === 'mail_encryption') { + const tlsHelp = app.translator.trans('core.admin.email.mail_encryption_tls_help'); + const sslHelp = app.translator.trans('core.admin.email.mail_encryption_ssl_help'); + const noneHelp = app.translator.trans('core.admin.email.mail_encryption_none_help'); + + helpText = ( + <> +
TLS: {tlsHelp}
+
SSL: {sslHelp}
+
None: {noneHelp}
+ + ); + } else { + const helpKey = `core.admin.email.${field}_help`; + const translatedHelp = app.translator.trans(helpKey); + helpText = translatedHelp !== helpKey ? translatedHelp : undefined; + } + return ( <> {this.buildSettingComponent({ @@ -154,8 +181,15 @@ export default class MailPage exten label: app.translator.trans(`core.admin.email.${field}_label`), setting: field, options: fieldInfo, + help: helpText, })} - {this.status!.errors[field] &&

{this.status!.errors[field]}

} + {this.status!.errors[field] && ( +
+ {Array.isArray(this.status!.errors[field]) + ? this.status!.errors[field].map((error: string) =>

{error}

) + :

{this.status!.errors[field]}

} +
+ )} ); })} diff --git a/framework/core/js/src/common/components/FormGroup.tsx b/framework/core/js/src/common/components/FormGroup.tsx index 5fca1b34ec..ed67610a62 100644 --- a/framework/core/js/src/common/components/FormGroup.tsx +++ b/framework/core/js/src/common/components/FormGroup.tsx @@ -209,7 +209,7 @@ export default class FormGroup + ); } else if ((RadioSettingTypes as readonly string[]).includes(type)) { const { default: defaultValue, options, multiple, ...otherAttrs } = attrs; diff --git a/framework/core/locale/core.yml b/framework/core/locale/core.yml index 89269035dc..f942c61de6 100644 --- a/framework/core/locale/core.yml +++ b/framework/core/locale/core.yml @@ -229,6 +229,9 @@ core: format_help: "Choose the format that outgoing emails will be sent in. The recommended option is multipart, as this will allow your user's email client to display the most appropriate format." from_label: Sender mail_encryption_label: Encryption + mail_encryption_tls_help: "Connection starts unencrypted and upgrades to TLS (STARTTLS). Typically used with port 587 or 25." + mail_encryption_ssl_help: "Connection is encrypted from the start (Implicit TLS). Typically used with port 465." + mail_encryption_none_help: "No encryption. Not recommended for production use." mail_host_label: Host mail_mailgun_domain_label: Domain mail_mailgun_region_label: Region @@ -243,6 +246,7 @@ core: send_test_mail_success: "Test mail sent successfully!" send_test_mail_text: "This will send an email using the above configuration to your email, {email}." smtp_heading: SMTP Settings + smtp_description: "Configure SMTP connection settings. Common configurations: Port 587 with TLS, or Port 465 with SSL." title: => core.ref.email # These translations are used on default extension pages. diff --git a/framework/core/src/Mail/SmtpDriver.php b/framework/core/src/Mail/SmtpDriver.php index 748759a2e6..ee4d8e1823 100644 --- a/framework/core/src/Mail/SmtpDriver.php +++ b/framework/core/src/Mail/SmtpDriver.php @@ -30,7 +30,11 @@ public function availableSettings(): array return [ 'mail_host' => '', // a hostname, IPv4 address or IPv6 wrapped in [] 'mail_port' => '', // a number, defaults to 25 - 'mail_encryption' => '', // "tls" or "ssl" + 'mail_encryption' => [ // Dropdown options for encryption + '' => 'None', + 'tls' => 'TLS', + 'ssl' => 'SSL', + ], 'mail_username' => '', 'mail_password' => '', ]; @@ -54,8 +58,14 @@ public function canSend(): bool public function buildTransport(SettingsRepositoryInterface $settings): TransportInterface { + $encryption = strtolower((string) $settings->get('mail_encryption')); + + // 'ssl' means implicit TLS/SSL (smtps://), typically used with port 465 + // 'tls' or empty means STARTTLS (smtp://), typically used with port 587 or 25 + $scheme = ($encryption === 'ssl') ? 'smtps' : 'smtp'; + return $this->factory->create(new Dsn( - $settings->get('mail_encryption') === 'tls' ? 'smtps' : 'smtp', + $scheme, $settings->get('mail_host'), $settings->get('mail_username'), $settings->get('mail_password'), From 5993f3030f32e262151c19f1899fc6e594babe6e Mon Sep 17 00:00:00 2001 From: IanM Date: Sat, 20 Dec 2025 00:05:23 +0000 Subject: [PATCH 2/3] chore: format js --- .../core/js/src/admin/components/MailPage.tsx | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/framework/core/js/src/admin/components/MailPage.tsx b/framework/core/js/src/admin/components/MailPage.tsx index dee53e056a..0c63bf624a 100644 --- a/framework/core/js/src/admin/components/MailPage.tsx +++ b/framework/core/js/src/admin/components/MailPage.tsx @@ -147,9 +147,7 @@ export default class MailPage exten
{fieldKeys.map((field) => { const fieldInfo = fields[field]; @@ -163,9 +161,15 @@ export default class MailPage exten helpText = ( <> -
TLS: {tlsHelp}
-
SSL: {sslHelp}
-
None: {noneHelp}
+
+ TLS: {tlsHelp} +
+
+ SSL: {sslHelp} +
+
+ None: {noneHelp} +
); } else { @@ -185,9 +189,11 @@ export default class MailPage exten })} {this.status!.errors[field] && (
- {Array.isArray(this.status!.errors[field]) - ? this.status!.errors[field].map((error: string) =>

{error}

) - :

{this.status!.errors[field]}

} + {Array.isArray(this.status!.errors[field]) ? ( + this.status!.errors[field].map((error: string) =>

{error}

) + ) : ( +

{this.status!.errors[field]}

+ )}
)} From 56d4a5a4618d652e1ed6e745824af1e4a4042ddd Mon Sep 17 00:00:00 2001 From: IanM Date: Sat, 20 Dec 2025 00:10:11 +0000 Subject: [PATCH 3/3] chore: update test for mail setting --- framework/core/tests/integration/extenders/MailTest.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/framework/core/tests/integration/extenders/MailTest.php b/framework/core/tests/integration/extenders/MailTest.php index 2354af990e..44cc42adc1 100644 --- a/framework/core/tests/integration/extenders/MailTest.php +++ b/framework/core/tests/integration/extenders/MailTest.php @@ -46,7 +46,11 @@ public function drivers_are_unchanged_by_default() $this->assertEquals([ 'mail_host' => '', 'mail_port' => '', - 'mail_encryption' => '', + 'mail_encryption' => [ + '' => 'None', + 'tls' => 'TLS', + 'ssl' => 'SSL', + ], 'mail_username' => '', 'mail_password' => '', ], $fields['smtp']);