Add mailjet transport
This commit is contained in:
parent
4383fcd449
commit
bf55ebc81f
BIN
package-lock.json
generated
BIN
package-lock.json
generated
Binary file not shown.
@ -116,6 +116,7 @@
|
|||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"erlpack": "^0.1.4",
|
"erlpack": "^0.1.4",
|
||||||
"sqlite3": "^5.1.4",
|
"sqlite3": "^5.1.4",
|
||||||
"nodemailer-mailgun-transport": "^2.1.5"
|
"nodemailer-mailgun-transport": "^2.1.5",
|
||||||
|
"nodemailer-mailjet-transport": "^1.0.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
MailGunConfiguration,
|
MailGunConfiguration,
|
||||||
|
MailJetConfiguration,
|
||||||
SMTPConfiguration,
|
SMTPConfiguration,
|
||||||
} from "./subconfigurations/email";
|
} from "./subconfigurations/email";
|
||||||
|
|
||||||
@ -25,4 +26,5 @@ export class EmailConfiguration {
|
|||||||
provider: string | null = null;
|
provider: string | null = null;
|
||||||
smtp: SMTPConfiguration = new SMTPConfiguration();
|
smtp: SMTPConfiguration = new SMTPConfiguration();
|
||||||
mailgun: MailGunConfiguration = new MailGunConfiguration();
|
mailgun: MailGunConfiguration = new MailGunConfiguration();
|
||||||
|
mailjet: MailJetConfiguration = new MailJetConfiguration();
|
||||||
}
|
}
|
||||||
|
|||||||
22
src/util/config/types/subconfigurations/email/MailJet.ts
Normal file
22
src/util/config/types/subconfigurations/email/MailJet.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
Fosscord: A FOSS re-implementation and extension of the Discord.com backend.
|
||||||
|
Copyright (C) 2023 Fosscord and Fosscord 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 class MailJetConfiguration {
|
||||||
|
apiKey: string | null = null;
|
||||||
|
apiSecret: string | null = null;
|
||||||
|
}
|
||||||
@ -17,4 +17,5 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export * from "./MailGun";
|
export * from "./MailGun";
|
||||||
|
export * from "./MailJet";
|
||||||
export * from "./SMTP";
|
export * from "./SMTP";
|
||||||
|
|||||||
@ -52,11 +52,111 @@ export function adjustEmail(email?: string): string | undefined {
|
|||||||
// return email;
|
// return email;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const transporters = {
|
||||||
|
smtp: 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 || !username || !password)
|
||||||
|
return console.error(
|
||||||
|
"[Email] SMTP has not been configured correctly.",
|
||||||
|
);
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
},
|
||||||
|
mailgun: async function () {
|
||||||
|
// get configuration
|
||||||
|
const { apiKey, domain } = Config.get().email.mailgun;
|
||||||
|
|
||||||
|
// ensure all required configuration values are set
|
||||||
|
if (!apiKey || !domain)
|
||||||
|
return console.error(
|
||||||
|
"[Email] Mailgun has not been configured correctly.",
|
||||||
|
);
|
||||||
|
|
||||||
|
let mg;
|
||||||
|
try {
|
||||||
|
// try to import the transporter package
|
||||||
|
mg = require("nodemailer-mailgun-transport");
|
||||||
|
} catch {
|
||||||
|
// if the package is not installed, log an error and return void so we don't set the transporter
|
||||||
|
console.error(
|
||||||
|
"[Email] Mailgun transport is not installed. Please run `npm install nodemailer-mailgun-transport --save-optional` to install it.",
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the transporter configuration object
|
||||||
|
const auth = {
|
||||||
|
auth: {
|
||||||
|
api_key: apiKey,
|
||||||
|
domain: domain,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// create the transporter and return it
|
||||||
|
return nodemailer.createTransport(mg(auth));
|
||||||
|
},
|
||||||
|
mailjet: async function () {
|
||||||
|
// get configuration
|
||||||
|
const { apiKey, apiSecret } = Config.get().email.mailjet;
|
||||||
|
|
||||||
|
// ensure all required configuration values are set
|
||||||
|
if (!apiKey || !apiSecret)
|
||||||
|
return console.error(
|
||||||
|
"[Email] Mailjet has not been configured correctly.",
|
||||||
|
);
|
||||||
|
|
||||||
|
let mj;
|
||||||
|
try {
|
||||||
|
// try to import the transporter package
|
||||||
|
mj = require("nodemailer-mailjet-transport");
|
||||||
|
} catch {
|
||||||
|
// if the package is not installed, log an error and return void so we don't set the transporter
|
||||||
|
console.error(
|
||||||
|
"[Email] Mailjet transport is not installed. Please run `npm install nodemailer-mailjet-transport --save-optional` to install it.",
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the transporter configuration object
|
||||||
|
const auth = {
|
||||||
|
auth: {
|
||||||
|
apiKey: apiKey,
|
||||||
|
apiSecret: apiSecret,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// create the transporter and return it
|
||||||
|
return nodemailer.createTransport(mj(auth));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export const Email: {
|
export const Email: {
|
||||||
transporter: Transporter | null;
|
transporter: Transporter | null;
|
||||||
init: () => Promise<void>;
|
init: () => Promise<void>;
|
||||||
initSMTP: () => Promise<void>;
|
|
||||||
initMailgun: () => Promise<void>;
|
|
||||||
generateVerificationLink: (id: string, email: string) => Promise<string>;
|
generateVerificationLink: (id: string, email: string) => Promise<string>;
|
||||||
sendVerificationEmail: (user: User, email: string) => Promise<any>;
|
sendVerificationEmail: (user: User, email: string) => Promise<any>;
|
||||||
doReplacements: (
|
doReplacements: (
|
||||||
@ -77,64 +177,15 @@ export const Email: {
|
|||||||
const { provider } = Config.get().email;
|
const { provider } = Config.get().email;
|
||||||
if (!provider) return;
|
if (!provider) return;
|
||||||
|
|
||||||
if (provider === "smtp") await this.initSMTP();
|
const transporterFn =
|
||||||
else if (provider === "mailgun") await this.initMailgun();
|
transporters[provider as keyof typeof transporters];
|
||||||
else throw new Error(`Unknown email provider: ${provider}`);
|
if (!transporterFn)
|
||||||
},
|
return console.error(`[Email] Invalid provider: ${provider}`);
|
||||||
initSMTP: async function () {
|
console.log(`[Email] Initializing ${provider} transport...`);
|
||||||
const { host, port, secure, username, password } =
|
const transporter = await transporterFn();
|
||||||
Config.get().email.smtp;
|
if (!transporter) return;
|
||||||
if (!host || !port || !secure || !username || !password)
|
this.transporter = transporter;
|
||||||
return console.error(
|
console.log(`[Email] ${provider} transport initialized.`);
|
||||||
"[Email] SMTP has not been configured correctly.",
|
|
||||||
);
|
|
||||||
|
|
||||||
console.log(`[Email] Initializing SMTP transport: ${host}`);
|
|
||||||
this.transporter = nodemailer.createTransport({
|
|
||||||
host,
|
|
||||||
port,
|
|
||||||
secure,
|
|
||||||
auth: {
|
|
||||||
user: username,
|
|
||||||
pass: password,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
await this.transporter.verify((error, _) => {
|
|
||||||
if (error) {
|
|
||||||
console.error(`[Email] SMTP error: ${error}`);
|
|
||||||
this.transporter?.close();
|
|
||||||
this.transporter = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
console.log(`[Email] Ready`);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
initMailgun: async function () {
|
|
||||||
const { apiKey, domain } = Config.get().email.mailgun;
|
|
||||||
if (!apiKey || !domain)
|
|
||||||
return console.error(
|
|
||||||
"[Email] Mailgun has not been configured correctly.",
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const mg = require("nodemailer-mailgun-transport");
|
|
||||||
const auth = {
|
|
||||||
auth: {
|
|
||||||
api_key: apiKey,
|
|
||||||
domain: domain,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log(`[Email] Initializing Mailgun transport...`);
|
|
||||||
this.transporter = nodemailer.createTransport(mg(auth));
|
|
||||||
console.log(`[Email] Ready`);
|
|
||||||
} catch {
|
|
||||||
console.error(
|
|
||||||
"[Email] Mailgun transport is not installed. Please run `npm install nodemailer-mailgun-transport --save` to install it.",
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Replaces all placeholders in an email template with the correct values
|
* Replaces all placeholders in an email template with the correct values
|
||||||
@ -214,6 +265,7 @@ export const Email: {
|
|||||||
user.id,
|
user.id,
|
||||||
email,
|
email,
|
||||||
);
|
);
|
||||||
|
|
||||||
// load the email template
|
// load the email template
|
||||||
const rawTemplate = fs.readFileSync(
|
const rawTemplate = fs.readFileSync(
|
||||||
path.join(
|
path.join(
|
||||||
@ -223,13 +275,14 @@ export const Email: {
|
|||||||
),
|
),
|
||||||
{ encoding: "utf-8" },
|
{ encoding: "utf-8" },
|
||||||
);
|
);
|
||||||
|
|
||||||
// replace email template placeholders
|
// replace email template placeholders
|
||||||
const html = this.doReplacements(rawTemplate, user, verificationLink);
|
const html = this.doReplacements(rawTemplate, user, verificationLink);
|
||||||
|
|
||||||
// extract the title from the email template to use as the email subject
|
// extract the title from the email template to use as the email subject
|
||||||
const subject = html.match(/<title>(.*)<\/title>/)?.[1] || "";
|
const subject = html.match(/<title>(.*)<\/title>/)?.[1] || "";
|
||||||
|
|
||||||
// // construct the email
|
// construct the email
|
||||||
const message = {
|
const message = {
|
||||||
from:
|
from:
|
||||||
Config.get().general.correspondenceEmail || "noreply@localhost",
|
Config.get().general.correspondenceEmail || "noreply@localhost",
|
||||||
@ -238,7 +291,7 @@ export const Email: {
|
|||||||
html,
|
html,
|
||||||
};
|
};
|
||||||
|
|
||||||
// // send the email
|
// send the email
|
||||||
return this.transporter.sendMail(message);
|
return this.transporter.sendMail(message);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user