JB/web/scripts/test-smtp.mjs
JobsBoard Deployer 50b8524775 feat(email): route outbound mail through Proton Mail Bridge SMTP; feat(apply): route one-click apply to employer site
Email:
- Add nodemailer; rewrite lib/email.ts to send via configured SMTP (Proton
  Mail Bridge) first, Resend fallback, then dev simulation.
- Forward SMTP_* env to web and add protonmail-bridge service in compose.
- Document Proton Bridge SMTP vars in .env.example files; add test-smtp.mjs.

Apply:
- OneClickApplyModal now opens the job's real posting URL (company/ATS site)
  in a new tab as the primary action when jobUrl is present, and records the
  external application so the card shows 'Applied'.
- Internal one-click snapshot flow retained for jobs without an external URL.
- POST /api/applications accepts external:true (skips profile completeness)
  and records an external application.
2026-09-07 14:46:57 -04:00

38 lines
1.2 KiB
JavaScript

import nodemailer from "nodemailer";
const host = process.env.SMTP_HOST;
const port = parseInt(process.env.SMTP_PORT || "25", 10);
const user = process.env.SMTP_USER;
const pass = process.env.SMTP_PASS;
const from = process.env.SMTP_FROM || "JobsBoard <notifications@jobsboard.internal>";
const to = process.env.SMTP_TEST_TO || user;
if (!host || !user || !pass) {
console.error("Missing SMTP_HOST / SMTP_USER / SMTP_PASS in the environment.");
process.exit(1);
}
const transporter = nodemailer.createTransport({
host,
port,
secure: port === 465 || port === 10465,
requireTLS: true,
auth: { user, pass },
// Local relays such as Proton Mail Bridge present self-signed certs.
tls: { rejectUnauthorized: false },
});
try {
const info = await transporter.sendMail({
from,
to,
subject: "JobsBoard SMTP relay test",
text: "If you received this, the Proton Mail Bridge SMTP relay is working.",
html: "<p>If you received this, the Proton Mail Bridge SMTP relay is working.</p>",
});
console.log("SMTP test email sent:", info.messageId);
process.exit(0);
} catch (err) {
console.error("SMTP test failed:", err.message);
process.exit(1);
}