summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorRory& <root@rory.gay>2025-09-30 04:22:33 +0200
committerRory& <root@rory.gay>2025-09-30 04:24:19 +0200
commit088e7d89ab2e875a6423e3958bd54e13655c6653 (patch)
tree468096807a95d8078514243463eac068ffdac67a /src
parentPort SendGrid to new interface (diff)
downloadserver-ts-088e7d89ab2e875a6423e3958bd54e13655c6653.tar.xz
Port SMTP transport, make nodemailer optional
Diffstat (limited to 'src')
-rw-r--r--src/util/util/email/clients/SMTPTransport.ts63
-rw-r--r--src/util/util/email/clients/SendGridEmailClient.ts20
-rw-r--r--src/util/util/email/index.ts3
-rw-r--r--src/util/util/email/transports/SMTP.ts59
-rw-r--r--src/util/util/email/transports/index.ts19
5 files changed, 75 insertions, 89 deletions
diff --git a/src/util/util/email/clients/SMTPTransport.ts b/src/util/util/email/clients/SMTPTransport.ts
new file mode 100644

index 000000000..828c4a3e4 --- /dev/null +++ b/src/util/util/email/clients/SMTPTransport.ts
@@ -0,0 +1,63 @@ +import { BaseEmailClient, IEmail } from "./IEmailClient"; +import { Config } from "@spacebar/util*"; + +export class SMTPTransport extends BaseEmailClient { + // sendGrid?: unknown; + nodemailer?: typeof import("nodemailer"); + transporter: import("nodemailer").Transporter; + override async init(): Promise<void> { + try { + // try to import the transporter package + this.nodemailer = (await import("nodemailer")).default; + } catch { + // if the package is not installed, log an error and return void so we don't set the transporter + console.error("[Email] nodemailer is not installed. Please run `npm install nodemailer --save-optional` to install it."); + return; + } + // get configuration + const { host, port, secure, username, password } = Config.get().email.smtp; + + // ensure all required configuration values are set + if (!host || !port || secure === null || !username || !password) return console.error("[Email] SMTP has not been configured correctly."); + + if (!Config.get().email.senderAddress && !Config.get().general.correspondenceEmail) + return console.error( + '[Email] You have to configure either "email_senderAddress" or "general_correspondenceEmail" for emails to work. The configured value is used as the sender address.', + ); + + // construct the transporter + const transporter = this.nodemailer.createTransport({ + host, + port, + secure, + auth: { + user: username, + pass: password, + }, + }); + + // verify connection configuration + const verified = await transporter.verify().catch((err) => { + console.error("[Email] SMTP verification failed:", err); + return; + }); + + // if verification failed, return void and don't set transporter + if (!verified) return; + + this.transporter = transporter; + } + + override async sendMail(email: IEmail): Promise<void> { + if (!this.nodemailer) throw new Error("nodemailer not initialized"); + if (!this.transporter) throw new Error("nodemailer transporter not initialized"); + + await this.transporter.sendMail({ + to: email.to, + from: email.from, + subject: email.subject, + text: email.text, + html: email.html, + }); + } +} diff --git a/src/util/util/email/clients/SendGridEmailClient.ts b/src/util/util/email/clients/SendGridEmailClient.ts
index cb30ea8ba..e3006e495 100644 --- a/src/util/util/email/clients/SendGridEmailClient.ts +++ b/src/util/util/email/clients/SendGridEmailClient.ts
@@ -2,34 +2,34 @@ import { BaseEmailClient, IEmail } from "./IEmailClient"; import { Config } from "@spacebar/util*"; export class SendGridEmailClient extends BaseEmailClient { - // sendGrid?: unknown; - sendGrid?: typeof import("@sendgrid/mail"); + sendGrid?: unknown; + // sendGrid?: typeof import("@sendgrid/mail"); // for development - doesn't work if package isn't installed override async init(): Promise<void> { // get configuration const { apiKey } = Config.get().email.sendgrid; // ensure all required configuration values are set - if (!apiKey) - return console.error( - "[Email] SendGrid has not been configured correctly.", - ); + if (!apiKey) return console.error("[Email] SendGrid has not been configured correctly."); try { // try to import the transporter package this.sendGrid = (await import("@sendgrid/mail")).default; } catch { // if the package is not installed, log an error and return void so we don't set the transporter - console.error( - "[Email] SendGrid transport is not installed. Please run `npm install Maria-Golomb/nodemailer-sendgrid-transport --save-optional` to install it.", - ); + console.error("[Email] SendGrid transport is not installed. Please run `npm install @sendgrid/mail --save-optional` to install it."); return; } + + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error this.sendGrid.setApiKey(apiKey); } override async sendMail(email: IEmail): Promise<void> { if (!this.sendGrid) throw new Error("SendGrid not initialized"); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error await this.sendGrid.send({ to: email.to, from: email.from, @@ -38,4 +38,4 @@ export class SendGridEmailClient extends BaseEmailClient { html: email.html, }); } -} \ No newline at end of file +} diff --git a/src/util/util/email/index.ts b/src/util/util/email/index.ts
index 64acc3cc5..8223fa55b 100644 --- a/src/util/util/email/index.ts +++ b/src/util/util/email/index.ts
@@ -24,6 +24,7 @@ import { Config } from "../Config"; import { generateToken } from "../Token"; import { BaseEmailClient, IEmail, IEmailClient } from "./clients/IEmailClient"; import { SendGridEmailClient } from "./clients/SendGridEmailClient"; +import { SMTPTransport } from "./clients/SMTPTransport"; const ASSET_FOLDER_PATH = path.join( __dirname, @@ -78,7 +79,7 @@ export const Email: { switch (provider) { case "smtp": - this.transporter = new BaseEmailClient(); + this.transporter = new SMTPTransport(); break; case "sendgrid": this.transporter = new SendGridEmailClient(); diff --git a/src/util/util/email/transports/SMTP.ts b/src/util/util/email/transports/SMTP.ts deleted file mode 100644
index e3031943b..000000000 --- a/src/util/util/email/transports/SMTP.ts +++ /dev/null
@@ -1,59 +0,0 @@ -/* - Spacebar: A FOSS re-implementation and extension of the Discord.com backend. - Copyright (C) 2023 Spacebar and Spacebar Contributors - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see <https://www.gnu.org/licenses/>. -*/ - -import { Config } from "@spacebar/util"; -import nodemailer from "nodemailer"; - -export default async function () { - // get configuration - const { host, port, secure, username, password } = Config.get().email.smtp; - - // ensure all required configuration values are set - if (!host || !port || secure === null || !username || !password) - return console.error("[Email] SMTP has not been configured correctly."); - - if ( - !Config.get().email.senderAddress && - !Config.get().general.correspondenceEmail - ) - return console.error( - '[Email] You have to configure either "email_senderAddress" or "general_correspondenceEmail" for emails to work. The configured value is used as the sender address.', - ); - - // construct the transporter - const transporter = nodemailer.createTransport({ - host, - port, - secure, - auth: { - user: username, - pass: password, - }, - }); - - // verify connection configuration - const verified = await transporter.verify().catch((err) => { - console.error("[Email] SMTP verification failed:", err); - return; - }); - - // if verification failed, return void and don't set transporter - if (!verified) return; - - return transporter; -} diff --git a/src/util/util/email/transports/index.ts b/src/util/util/email/transports/index.ts deleted file mode 100644
index 4d40f9ccc..000000000 --- a/src/util/util/email/transports/index.ts +++ /dev/null
@@ -1,19 +0,0 @@ -/* - Spacebar: A FOSS re-implementation and extension of the Discord.com backend. - Copyright (C) 2023 Spacebar and Spacebar Contributors - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see <https://www.gnu.org/licenses/>. -*/ - -export * from "./SMTP";