Control centre: don't block the provisioning report on email; fix resend

- The welcome email is sent in the background, so a slow mail server no
  longer makes provision-tenants.sh time out.
- SMTP connection/greeting/socket timeouts, so a bad host fails with a
  reason in the agency log instead of hanging.
- "Resend welcome" never sent anything (report() only emails on the
  change to running); it now sends directly and shows the error if any.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
metatroncubeswdev 2026-10-25 13:15:45 -04:00
parent 86f4f2c089
commit 1e97bbd31f
2 changed files with 15 additions and 9 deletions

View File

@ -185,23 +185,28 @@ export async function report(slug, { actual, error }) {
if (actual === "running" && ["provisioning", "past_due"].includes(x.status)) x.status = "active";
}, error ? `provisioning error: ${String(error).slice(0, 120)}` : `container ${actual}`);
if (!error && actual === "running" && before.actual !== "running" && t.setupToken && !t.welcomedAt) {
const sent = await notify.sendEmail({
to: t.ownerEmail, subject: `Your Quorla workspace is ready`, heading: `Welcome to Quorla, ${t.ownerName || t.agencyName}`,
lines: [`Your workspace for ${t.agencyName} is ready at ${t.url}.`, "Use the button to create your admin account. The link works once; after that, sign in with your email and password.", "Then follow the Getting started list: connect your clients' accounts, invite your team and schedule your first post."],
button: { label: "Create my account", url: `${t.url}/?setup=${t.setupToken}` }, fromName: "Quorla",
});
update(slug, (x) => { if (sent.sent) x.welcomedAt = now(); }, sent.sent ? "welcome email sent" : `welcome email not sent: ${sent.reason}`);
// Don't make the script wait for the mail server; the outcome lands in the agency's log on Admin → Agencies.
sendWelcome(slug, t).catch(() => {});
}
return PUBLIC(read()[slug]);
}
async function sendWelcome(slug, t) {
const sent = await notify.sendEmail({
to: t.ownerEmail, subject: `Your Quorla workspace is ready`, heading: `Welcome to Quorla, ${t.ownerName || t.agencyName}`,
lines: [`Your workspace for ${t.agencyName} is ready at ${t.url}.`, "Use the button to create your admin account. The link works once; after that, sign in with your email and password.", "Then follow the Getting started list: connect your clients' accounts, invite your team and schedule your first post."],
button: { label: "Create my account", url: `${t.url}/?setup=${t.setupToken}` }, fromName: "Quorla",
});
update(slug, (x) => { if (sent.sent) x.welcomedAt = now(); }, sent.sent ? "welcome email sent" : `welcome email not sent: ${sent.reason}`);
return sent;
}
/** Send the welcome email again (the setup link only works until the first account exists). */
export async function resendWelcome(slug) {
const t = read()[slug];
if (!t) throw err("Unknown agency.", 404);
if (t.actual !== "running") throw err("The workspace isn't running yet.");
update(slug, (x) => { delete x.welcomedAt; });
await report(slug, { actual: "running" });
update(slug, () => {}, "welcome email re-sent");
const sent = await sendWelcome(slug, t);
if (!sent.sent) throw err(`Welcome email not sent: ${sent.reason}`, 502);
return PUBLIC(read()[slug]);
}

View File

@ -23,6 +23,7 @@ function mailer() {
transport ||= nodemailer.createTransport({
host: process.env.SMTP_HOST, port: Number(process.env.SMTP_PORT || 587), secure: Number(process.env.SMTP_PORT) === 465,
auth: process.env.SMTP_USER ? { user: process.env.SMTP_USER, pass: process.env.SMTP_PASS || "" } : undefined,
connectionTimeout: 15000, greetingTimeout: 15000, socketTimeout: 30000, // fail with a reason instead of hanging for minutes
});
return transport;
}