From c1eb61675984d22f3a74752a8086bf0f357815bb Mon Sep 17 00:00:00 2001 From: LanQin_ Date: Tue, 16 Jun 2026 11:15:03 +0800 Subject: [PATCH] =?UTF-8?q?feat(admin):=20=E4=BC=98=E5=8C=96=20DNS=20?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=E5=B1=95=E7=A4=BA=E4=B8=8E=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 为 DNS 记录补充说明文案,帮助理解 MX、SPF、DKIM、DMARC 的作用。 - 将 MX 记录目标改为 `PublicHostname`,避免固定指向 `mail` 子域。 --- apps/api/internal/app/dns_handlers.go | 6 ++---- apps/web/src/pages/admin.tsx | 27 ++++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/apps/api/internal/app/dns_handlers.go b/apps/api/internal/app/dns_handlers.go index eccc879..fcdb97b 100644 --- a/apps/api/internal/app/dns_handlers.go +++ b/apps/api/internal/app/dns_handlers.go @@ -34,11 +34,9 @@ func (a *App) handleDNSCheck(w http.ResponseWriter, r *http.Request) { func (a *App) dnsRecordsFor(d *Domain) []DNSRecord { name := strings.TrimSuffix(d.Name, ".") - // MX 建议使用 mail.<域名> 标准格式,而不是直接用 PublicHostname - // 避免 PublicHostname 等于域名本身时出现 MX 指向自己的问题 - mxHost := "mail." + name + "." + host := strings.TrimSuffix(a.cfg.PublicHostname, ".") + "." return []DNSRecord{ - {Type: "MX", Name: name, Value: fmt.Sprintf("10 %s", mxHost), TTL: 300}, + {Type: "MX", Name: name, Value: fmt.Sprintf("10 %s", host), TTL: 300}, {Type: "TXT", Name: name, Value: "v=spf1 mx -all", TTL: 300}, {Type: "TXT", Name: d.DKIMSelector + "._domainkey." + name, Value: "v=DKIM1; k=rsa; p=" + d.DKIMPublicKey, TTL: 300}, {Type: "TXT", Name: "_dmarc." + name, Value: "v=DMARC1; p=quarantine; rua=mailto:postmaster@" + name, TTL: 300}, diff --git a/apps/web/src/pages/admin.tsx b/apps/web/src/pages/admin.tsx index 2e4b5e4..0e6efa9 100644 --- a/apps/web/src/pages/admin.tsx +++ b/apps/web/src/pages/admin.tsx @@ -851,9 +851,34 @@ function DNSPanel({ domain, embedded = false }: { domain?: Domain; embedded?: bo return {header}{content} } +const dnsDescriptions: Record = { + MX: "指定收件服务器。把邮件投递到该地址指向的服务器。", + TXT: "", // 具体含义根据内容区分 +} + +function dnsDescription(record: DNSRecord): string { + if (record.type === "TXT" && record.name.startsWith("_dmarc")) return "声明域名的 DMARC 策略(如何处理未通过 SPF/DKIM 验证的邮件)。" + if (record.type === "TXT" && record.value.includes("DKIM1")) return "DKIM 公钥。收件服务器用此密钥验证邮件是否由你发出。" + if (record.type === "TXT" && record.value.includes("spf1")) return "声明哪些服务器有权使用你的域名发件,防止伪造。" + if (record.type === "MX") return `确保 ${record.name} 的 A 记录已指向你的服务器 IP,邮件才能到达。` + return "" +} + function DNSRecordRow({ record }: { record: DNSRecord }) { const { toast } = useToast(); const text = `${record.type} ${record.name} ${record.value}` - return
{record.type}
Name: {record.name}
Value: {record.value}
TTL: {record.ttl}s
+ const desc = dnsDescription(record) + return
+
+ {record.type} + +
+ {desc &&

{desc}

} +
+
Name: {record.name}
+
Value: {record.value}
+
TTL: {record.ttl}s
+
+
} function fieldValue(form: FormData, name: string, fallback: string) {