diff --git a/dashboard/server/control.js b/dashboard/server/control.js index 195f7ef..02df044 100644 --- a/dashboard/server/control.js +++ b/dashboard/server/control.js @@ -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]); } diff --git a/dashboard/server/notify.js b/dashboard/server/notify.js index 407a1d1..11658e6 100644 --- a/dashboard/server/notify.js +++ b/dashboard/server/notify.js @@ -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; }