import { defineEventHandler, createError, readBody } from "h3"; import nodemailer from "nodemailer"; import type SMTPTransport from "nodemailer/lib/smtp-transport"; import { useRuntimeConfig } from "#imports"; type MailConfig = { smtpHost?: string; smtpPort?: number | string; smtpUser?: string; smtpPass?: string; senderEmail?: string; adminEmail?: string; smtpSecure?: boolean; }; type SendMailPayload = { name?: string; url?: string; desc?: string; email?: string; avatar?: string; message?: string; }; const ensureValue = (value?: string, fallback = "未填写") => (value?.trim() ? value.trim() : fallback); export default defineEventHandler(async (event) => { const method = event.node.req.method; if (method === "OPTIONS") { event.node.res.statusCode = 200; return { status: "ok" }; } if (method !== "POST") { throw createError({ statusCode: 405, statusMessage: "Method Not Allowed" }); } const payload = (await readBody(event)) || {}; const { name, url, desc, email, avatar, message } = payload; if (!name?.trim() || !url?.trim() || !email?.trim()) { throw createError({ statusCode: 400, statusMessage: "Missing required fields: name, url, and email", }); } const config = useRuntimeConfig() as MailConfig; const { smtpHost, smtpPort: configSmtpPort, smtpUser, smtpPass, senderEmail, adminEmail, smtpSecure } = config; const smtpPort = Number(configSmtpPort ?? 465); if (!smtpHost || !smtpUser || !smtpPass || !senderEmail || !adminEmail) { throw createError({ statusCode: 500, statusMessage: "SMTP server is not fully configured" }); } const secure = typeof smtpSecure === "boolean" ? smtpSecure : smtpPort === 465; const smtpOptions: SMTPTransport.Options = { host: smtpHost, port: smtpPort, secure, auth: { user: smtpUser, pass: smtpPass, }, }; const transporter = nodemailer.createTransport(smtpOptions); const friendEntry = `{ name: "${ensureValue(name).replace(/"/g, '\\"')}", url: "${ensureValue(url).replace(/"/g, '\\"')}", desc: "${ensureValue(desc).replace(/"/g, '\\"')}", avatar: "${ensureValue(avatar).replace(/"/g, '\\"')}", },`; const htmlMessage = `

一个新的友链申请已提交,以下是可直接复制到项目中的配置:

${friendEntry}
        

申请者信息:

名称:${ensureValue(name)}

邮箱:${ensureValue(email)}

站点:${ensureValue(url)}

描述:${ensureValue(desc)}

头像:${ensureValue(avatar)}

想说的话:${ensureValue(message)}

时间:${new Date().toISOString()}

`; const info = await transporter.sendMail({ from: senderEmail, to: adminEmail, replyTo: email, subject: `友链申请 / 联系表单 · ${ensureValue(name)}`, html: htmlMessage, }); return { message: "Mail sent", id: info.messageId, }; });