Skip to content

Commit

Permalink
Close the SMTP connection pool when done
Browse files Browse the repository at this point in the history
  • Loading branch information
Vinnl committed Oct 29, 2024
1 parent 7dad674 commit 9039130
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 9 deletions.
3 changes: 2 additions & 1 deletion src/scripts/cronjobs/emailBreachAlerts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
addEmailNotification,
markEmailAsNotified,
} from "../../db/tables/email_notifications";
import { initEmail, sendEmail } from "../../utils/email";
import { initEmail, sendEmail, closeEmailPool } from "../../utils/email";

import {
getAddressesAndLanguageForEmail,
Expand Down Expand Up @@ -427,6 +427,7 @@ if (process.env.NODE_ENV !== "test") {
await knexSubscribers.destroy();
await knexEmailAddresses.destroy();
await knexHibp.destroy();
closeEmailPool();
Sentry.captureCheckIn({
checkInId,
monitorSlug: SENTRY_SLUG,
Expand Down
5 changes: 4 additions & 1 deletion src/scripts/cronjobs/firstDataBrokerRemovalFixed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
getPotentialSubscribersWaitingForFirstDataBrokerRemovalFixedEmail,
markFirstDataBrokerRemovalFixedEmailAsJustSent,
} from "../../db/tables/subscribers";
import { initEmail, sendEmail } from "../../utils/email";
import { initEmail, sendEmail, closeEmailPool } from "../../utils/email";
import { renderEmail } from "../../emails/renderEmail";
import { FirstDataBrokerRemovalFixed } from "../../emails/templates/firstDataBrokerRemovalFixed/FirstDataBrokerRemovalFixed";
import { getCronjobL10n } from "../../app/functions/l10n/cronjobs";
Expand Down Expand Up @@ -103,6 +103,9 @@ async function run() {
);
}),
);

closeEmailPool();

console.log(
`[${new Date(Date.now()).toISOString()}] Sent [${subscribersToEmailWithData.length}] first data broker removal fixed emails.`,
);
Expand Down
4 changes: 3 additions & 1 deletion src/scripts/cronjobs/monthlyActivityFree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import { SubscriberRow } from "knex/types/tables";
import { getFreeSubscribersWaitingForMonthlyEmail } from "../../db/tables/subscribers";
import { initEmail, sendEmail } from "../../utils/email";
import { initEmail, sendEmail, closeEmailPool } from "../../utils/email";
import { renderEmail } from "../../emails/renderEmail";
import { MonthlyActivityFreeEmail } from "../../emails/templates/monthlyActivityFree/MonthlyActivityFreeEmail";
import { getCronjobL10n } from "../../app/functions/l10n/cronjobs";
Expand Down Expand Up @@ -43,6 +43,8 @@ async function run() {
sendMonthlyActivityEmail(subscriber),
),
);

closeEmailPool();
console.log(
`[${new Date(Date.now()).toISOString()}] Sent [${subscribersToEmail.length}] monthly activity emails to free users.`,
);
Expand Down
4 changes: 3 additions & 1 deletion src/scripts/cronjobs/monthlyActivityPlus.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
getPlusSubscribersWaitingForMonthlyEmail,
markMonthlyActivityPlusEmailAsJustSent,
} from "../../db/tables/subscribers";
import { initEmail, sendEmail } from "../../utils/email";
import { initEmail, sendEmail, closeEmailPool } from "../../utils/email";
import { renderEmail } from "../../emails/renderEmail";
import { MonthlyActivityPlusEmail } from "../../emails/templates/monthlyActivityPlus/MonthlyActivityPlusEmail";
import { getCronjobL10n } from "../../app/functions/l10n/cronjobs";
Expand Down Expand Up @@ -40,6 +40,8 @@ async function run() {
return sendMonthlyActivityEmail(subscriber);
}),
);

closeEmailPool();
console.log(
`[${new Date(Date.now()).toISOString()}] Sent [${subscribersToEmail.length}] monthly activity emails to Plus users.`,
);
Expand Down
10 changes: 10 additions & 0 deletions src/utils/email.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,16 @@ test("EmailUtils.init with empty host uses jsonTransport. logs messages", async
);
});

test("EmailUtils.closeEmailPool before .init() fails", async () => {
expect.assertions(1);

const { closeEmailPool } = await import("./email");

const expectedError = "`closeEmailPool` called before `initEmail`";

expect(() => closeEmailPool()).toThrow(expectedError);
});

test("randomToken returns a random token of 2xlength (because of hex)", () => {
const token = randomToken(32);
expect(token).toHaveLength(64);
Expand Down
19 changes: 14 additions & 5 deletions src/utils/email.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ let gTransporter: Transporter<SentMessageInfo>;

const envVars = getEnvVarsOrThrow(["SMTP_URL", "EMAIL_FROM", "SES_CONFIG_SET"]);

async function initEmail(smtpUrl = envVars.SMTP_URL) {
export async function initEmail(smtpUrl = envVars.SMTP_URL) {
// Allow a debug mode that will log JSON instead of sending emails.
if (!smtpUrl) {
logger.info("smtpUrl-empty", {
Expand All @@ -30,14 +30,25 @@ async function initEmail(smtpUrl = envVars.SMTP_URL) {
return gTransporterVerification;
}

/** See https://nodemailer.com/smtp/pooled/ */
export function closeEmailPool() {
if (!gTransporter) {
throw new Error("`closeEmailPool` called before `initEmail`");
/* c8 ignore next 4 */
}
// Not covered by tests because it involves a lot of mocks to basically check
// that we called this function. See test-coverage.md#mock-heavy
gTransporter.close();
}

/**
* Send Email
*
* @param recipient
* @param subject
* @param html
*/
async function sendEmail(
export async function sendEmail(
recipient: string,
subject: string,
html: string,
Expand Down Expand Up @@ -86,8 +97,6 @@ async function sendEmail(
}
}

function randomToken(length: number = 64) {
export function randomToken(length: number = 64) {
return crypto.randomBytes(length).toString("hex");
}

export { initEmail, sendEmail, randomToken };

0 comments on commit 9039130

Please sign in to comment.