From b257637a38cab0addcdc1c9e1e6789d813d7cb3f Mon Sep 17 00:00:00 2001 From: Erin of Yukis Date: Thu, 4 Dec 2025 05:16:17 +0100 Subject: [PATCH] =?UTF-8?q?Expose=20all=20of=20nodemailer=E2=80=99s=20tran?= =?UTF-8?q?sport=20settings=20using=20a=20new=20transportConfig=20configur?= =?UTF-8?q?ation=20subkey?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All known documentation has been updated to expose host and port below this new key. Existing configuration continues to work but shows a warning on startup. --- .env.sample | 4 ++-- bewcloud.config.sample.ts | 6 ++++-- lib/config.ts | 16 ++++++++++++++-- lib/models/email.ts | 27 ++++++++++++++++++++++----- lib/types.ts | 15 +++++++++++++-- 5 files changed, 55 insertions(+), 13 deletions(-) diff --git a/.env.sample b/.env.sample index 0a501ae..451b92f 100644 --- a/.env.sample +++ b/.env.sample @@ -16,5 +16,5 @@ MFA_SALT="fake" # optional, if you want to enable multi-factor authentication OIDC_CLIENT_ID="fake" # optional, if you want to enable SSO (Single Sign-On) OIDC_CLIENT_SECRET="fake" # optional, if you want to enable SSO (Single Sign-On) -SMTP_USERNAME="fake" # optional, if you want to enable signup email verification or multi-factor authentication via email -SMTP_PASSWORD="fake" # optional, if you want to enable signup email verification or multi-factor authentication via email +SMTP_USERNAME="fake" # optional, if you want to use a mail service requiring password authentication +SMTP_PASSWORD="fake" # optional, if you want to use a mail service requiring password authentication diff --git a/bewcloud.config.sample.ts b/bewcloud.config.sample.ts index 6918864..515f0d3 100644 --- a/bewcloud.config.sample.ts +++ b/bewcloud.config.sample.ts @@ -30,8 +30,10 @@ const config: PartialDeep = { // }, // email: { // from: 'help@bewcloud.com', - // host: 'localhost', - // port: 465, + // transportConfig: { // Specify any needed options listed at https://nodemailer.com/smtp here; authentication data will automatically be added if specify using the `SMTP_USERNAME` and `SMTP_PASSWORD` environment variables + // host: 'localhost', + // port: 465, + // }, // }, // contacts: { // enableCardDavServer: true, diff --git a/lib/config.ts b/lib/config.ts index b843111..a6c5b81 100644 --- a/lib/config.ts +++ b/lib/config.ts @@ -35,8 +35,10 @@ export class AppConfig { }, email: { from: 'help@bewcloud.com', - host: 'localhost', - port: 465, + transportConfig: { + host: 'localhost', + port: 465, + }, }, contacts: { enableCardDavServer: true, @@ -95,6 +97,16 @@ export class AppConfig { }, }; + // Support for older transport configuration settings + if (typeof(this.config.email.host) !== "undefined") { + console.warn('Config entry “email.host” has been renamed to “email.transportConfig.host”'); + this.config.email.transportConfig.host = this.config.email.host; + } + if (typeof(this.config.email.port) !== "undefined") { + console.warn('Config entry “email.port” has been renamed to “email.transportConfig.port”'); + this.config.email.transportConfig.port = this.config.email.port; + } + console.info('\nConfig loaded from bewcloud.config.ts', JSON.stringify(this.config, null, 2), '\n'); if (this.config.core.enabledApps.length === 0) { diff --git a/lib/models/email.ts b/lib/models/email.ts index 3aac62e..8c4a44d 100644 --- a/lib/models/email.ts +++ b/lib/models/email.ts @@ -4,6 +4,24 @@ import '@std/dotenv/load'; import { escapeHtml } from '/lib/utils/misc.ts'; import { AppConfig } from '/lib/config.ts'; +/** + * Simple JSON object deep merger + * + * Source: https://stackoverflow.com/a/58618599 + */ +const deepMerge = (objs) => + objs.reduce((acc, obj) => + Object.keys(obj).reduce((innerAcc, key) => ({ + ...innerAcc, + [key]: + key in acc + ? typeof acc[key] === 'object' && acc[key] !== null && typeof obj[key] === 'object' && obj[key] !== null + ? deepMerge([acc[key], obj[key]]) + : obj[key] + : obj[key] + }), acc), + {}); + const SMTP_USERNAME = Deno.env.get('SMTP_USERNAME') || ''; const SMTP_PASSWORD = Deno.env.get('SMTP_PASSWORD') || ''; @@ -15,15 +33,14 @@ export class EmailModel { throw new Error('config.email.from, config.email.host, or config.email.port is not set'); } - const transporterConfig = { - host: emailConfig.host, - port: emailConfig.port, - secure: Number(emailConfig.port) === 465, + const transporterConfig = deepMerge([{ + secure: Number(emailConfig.transportConfig.port) === 465, + }, ((SMTP_USERNAME || SMTP_PASSWORD) ? { auth: { user: SMTP_USERNAME, pass: SMTP_PASSWORD, }, - }; + } : {}), emailConfig.transportConfig]); const transporter = nodemailer.createTransport(transporterConfig); diff --git a/lib/types.ts b/lib/types.ts index 04dd1a3..353f798 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -202,10 +202,21 @@ export interface Config { email: { /** The email address to send emails from */ from: string; - /** The SMTP host to send emails from */ + /** Deprecated alias for .transportConfig.host */ host: string; - /** The SMTP port to send emails from */ + /** Deprecated alias for .transportConfig.host */ port: number; + /** Transport options to pass to nodemailer (see https://nodemailer.com/smtp) */ + transportConfig: { + /** The SMTP host to send emails from */ + host: string; + /** The SMTP port to send emails from */ + port: number; + /** Whether to use immediate TLS or not (defaults to `true` if port is 465, `false` otherwise) */ + secure?: boolean; + /** Other transport properties */ + [_: string]: string|number|boolean|object; + }; }; contacts: { /** If true, the CardDAV server will be enabled (proxied) */