Files
company-site/lib/contact-mailer-config.ts
JanYork e2850586a9 feat: 实现联系表单提交与邮件通知功能
添加联系表单提交接口和邮件通知功能,支持从环境变量读取 SMTP 配置
重构 SEO 配置到 site.json,新增 robots.txt 和 sitemap.xml 生成
更新公司电话并添加 PM2 生产运行配置
2026-03-18 13:20:40 +08:00

100 lines
2.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { readFile } from "node:fs/promises"
import path from "node:path"
import { parse } from "yaml"
import { z } from "zod"
export const CONTACT_MAILER_CONFIG_PATH = path.join(
process.cwd(),
"config",
"contact-mailer.yaml"
)
export class ContactMailerConfigError extends Error {}
function coerceBoolean(value: unknown) {
if (typeof value === "boolean") {
return value
}
if (typeof value === "string") {
const normalized = value.trim().toLowerCase()
if (normalized === "true") {
return true
}
if (normalized === "false") {
return false
}
}
return value
}
function resolveEnvPlaceholders(value: unknown): unknown {
if (typeof value === "string") {
return value.replace(/\$\{([A-Z0-9_]+)(?::([^}]*))?\}/gi, (_, envName: string, fallback?: string) => {
return process.env[envName] ?? fallback ?? ""
})
}
if (Array.isArray(value)) {
return value.map(resolveEnvPlaceholders)
}
if (value && typeof value === "object") {
return Object.fromEntries(
Object.entries(value).map(([key, nestedValue]) => [key, resolveEnvPlaceholders(nestedValue)])
)
}
return value
}
const contactMailerConfigSchema = z.object({
smtp: z.object({
host: z.string().trim().min(1, "SMTP host 未配置"),
port: z.coerce.number().int().positive("SMTP port 未配置"),
secure: z.preprocess(coerceBoolean, z.boolean()),
auth: z.object({
user: z.string().trim().min(1, "SMTP 用户名未配置"),
pass: z.string().min(1, "SMTP 密码未配置"),
}),
from: z.object({
email: z.string().email("发件邮箱格式不正确"),
name: z.string().trim().min(1).default("智店软件官网"),
}),
}),
notification: z.object({
to: z.array(z.string().email("通知邮箱格式不正确")).min(1).default(["bd@zhidiansoft.com"]),
subjectPrefix: z.string().trim().min(1).default("官网线索"),
}).default({
to: ["bd@zhidiansoft.com"],
subjectPrefix: "官网线索",
}),
})
export type ContactMailerConfig = z.infer<typeof contactMailerConfigSchema>
export async function loadContactMailerConfig() {
try {
const fileContent = await readFile(CONTACT_MAILER_CONFIG_PATH, "utf8")
const parsed = parse(fileContent) ?? {}
const resolved = resolveEnvPlaceholders(parsed)
return contactMailerConfigSchema.parse(resolved)
} catch (error) {
if (error instanceof z.ZodError) {
throw new ContactMailerConfigError(
`contact-mailer.yaml 配置不完整:${error.issues.map((issue) => issue.message).join("")}`
)
}
if (error instanceof Error) {
throw new ContactMailerConfigError(`读取邮件配置失败:${error.message}`)
}
throw new ContactMailerConfigError("读取邮件配置失败")
}
}