Files
threadcount-community/lib/mail.ts
T
ThreadCount 822c0b7c0b ThreadCount Community edition
Uniform stock management for healthcare linen rooms: the coordinator app, the phone counter and the staff app, for your own server. Built from 8685140 on 2026-09-13. Licensed under the Functional Source License (FSL-1.1-ALv2).
2026-09-13 11:09:20 +10:00

62 lines
2.3 KiB
TypeScript

import nodemailer from "nodemailer";
/** SMTP is optional. With nothing configured the app still records what it needs to — it just
* doesn't post a notification, and says so in the logs rather than failing the caller's request. */
export function mailConfigured() {
return !!(process.env.SMTP_HOST && process.env.SMTP_USER && process.env.SMTP_PASS && process.env.CONTACT_TO);
}
/** Is transactional mail (password resets, staff activation) possible?
* Deliberately separate from mailConfigured(): the contact form additionally needs CONTACT_TO,
* and a missing CONTACT_TO must not silently disable password resets. */
export function transactionalConfigured() {
return !!(process.env.SMTP_HOST && process.env.SMTP_USER && process.env.SMTP_PASS);
}
/** Send to a specific person. Returns false rather than throwing: a caller deciding what to tell
* the user should never be handed an SMTP stack trace. */
export async function sendTo(to: string, subject: string, text: string): Promise<boolean> {
if (!transactionalConfigured()) {
console.warn("[mail] no SMTP configured — not sending:", subject);
return false;
}
try {
const port = parseInt(process.env.SMTP_PORT || "587", 10);
const t = nodemailer.createTransport({
host: process.env.SMTP_HOST,
port,
secure: port === 465,
auth: { user: process.env.SMTP_USER!, pass: process.env.SMTP_PASS! },
});
await t.sendMail({ from: process.env.SMTP_FROM || process.env.SMTP_USER!, to, subject, text });
return true;
} catch (e) {
console.error("[mail] send failed:", (e as Error).message);
return false;
}
}
export async function sendMail(subject: string, text: string, replyTo?: string): Promise<boolean> {
if (!mailConfigured()) return false;
try {
const port = parseInt(process.env.SMTP_PORT || "587", 10);
const t = nodemailer.createTransport({
host: process.env.SMTP_HOST,
port,
secure: port === 465,
auth: { user: process.env.SMTP_USER!, pass: process.env.SMTP_PASS! },
});
await t.sendMail({
from: process.env.SMTP_FROM || process.env.SMTP_USER!,
to: process.env.CONTACT_TO!,
replyTo: replyTo || undefined,
subject,
text,
});
return true;
} catch (e) {
console.error("[mail] send failed:", (e as Error).message);
return false;
}
}