Files
kitadmin 45f1e0e7f6 fix(deploy): requireTLS for SMTP relay + bridge network for docker-compose
- mailer.js: add requireTLS to force STARTTLS before AUTH on internal relay
- docker-compose.yml: use network_mode:bridge to reach 172.17.0.1:2587 SMTP relay
  and switch to ${SMTP_HOST:-172.17.0.1}/${SMTP_PORT:-2587} defaults

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 03:28:54 +00:00

68 lines
2.5 KiB
JavaScript

'use strict'
const nodemailer = require('nodemailer')
const SMTP_HOST = process.env.SMTP_HOST || ''
const SMTP_PORT = parseInt(process.env.SMTP_PORT || '587', 10)
const SMTP_USER = process.env.SMTP_USER || ''
const SMTP_PASS = process.env.SMTP_PASS || ''
const APP_URL = (process.env.APP_URL || 'http://localhost:3001').replace(/\/$/, '')
const FROM_ADDR = SMTP_USER
? `"MorseQuest" <${SMTP_USER}>`
: '"MorseQuest" <noreply@morsequest.keylinkit.net>'
let transport = null
if (SMTP_HOST && SMTP_USER && SMTP_PASS) {
transport = nodemailer.createTransport({
host: SMTP_HOST,
port: SMTP_PORT,
secure: SMTP_PORT === 465,
auth: { user: SMTP_USER, pass: SMTP_PASS },
requireTLS: true, // force STARTTLS before AUTH
connectionTimeout: 10_000,
greetingTimeout: 10_000,
socketTimeout: 15_000,
tls: { rejectUnauthorized: false }, // relay cert is for mail.keylinkit.net, not 172.17.0.1
})
console.log(`[mailer] SMTP configured: ${SMTP_HOST}:${SMTP_PORT}`)
} else {
console.warn('[mailer] SMTP not configured — magic links will be logged only')
}
async function send(to, subject, html) {
if (!transport) {
console.log(`[mailer] Would send to ${to}: ${subject}`)
return
}
await transport.sendMail({ from: FROM_ADDR, to, subject, html })
}
async function sendMagicLink(email, token) {
const link = `${APP_URL}/api/auth/verify?token=${token}`
const subject = 'Your MorseQuest Login Link'
const html = `
<div style="font-family:'Open Sans',sans-serif;max-width:480px;margin:0 auto;
padding:2rem;background:#F5E6D3;border:2px solid #D4AF37">
<h1 style="font-family:'Cinzel',serif;color:#3C2415;font-size:1.4rem;margin-bottom:1rem">
&#x26A1; MorseQuest Login
</h1>
<p style="color:#3C2415;line-height:1.6">
Click the button below to log in to MorseQuest. This link is valid for 24 hours
and can only be used once.
</p>
<div style="text-align:center;margin:2rem 0">
<a href="${link}"
style="display:inline-block;padding:0.8rem 2rem;background:#D4AF37;
color:#3C2415;text-decoration:none;font-family:'Cinzel',serif;
font-size:1rem;font-weight:600;border:2px solid #3C2415">
Begin Your Quest &rsaquo;
</a>
</div>
<p style="color:#654321;font-size:0.85rem;line-height:1.5">
If you didn't request this link, you can ignore this email safely.
</p>
</div>`
await send(email, subject, html)
}
module.exports = { sendMagicLink }