diff --git a/apps/mana/apps/web/src/lib/modules/broadcast/api.ts b/apps/mana/apps/web/src/lib/modules/broadcast/api.ts index 204af4c82..33a5bf315 100644 --- a/apps/mana/apps/web/src/lib/modules/broadcast/api.ts +++ b/apps/mana/apps/web/src/lib/modules/broadcast/api.ts @@ -107,6 +107,39 @@ export async function sendCampaign( return (await res.json()) as BulkSendResult; } +/** + * Run a DNS authentication check for the user's sending domain. + * Returns null on auth / 404 so the UI can treat "service down" and + * "nothing to report" the same way. + */ +export interface DnsCheckResult { + domain: string; + spf: { status: 'ok' | 'missing' | 'wrong' | 'weak'; record: string | null; message: string }; + dkim: { + status: 'ok' | 'missing' | 'wrong' | 'weak'; + record: string | null; + selector: string; + message: string; + }; + dmarc: { status: 'ok' | 'missing' | 'wrong' | 'weak'; record: string | null; message: string }; + checkedAt: string; + suggested: { + spfAdd: string; + dmarcRecord: string; + }; +} + +export async function runDnsCheck(domain: string, selector?: string): Promise { + const params = new URLSearchParams({ domain }); + if (selector) params.set('selector', selector); + const res = await fetchWithAuth(`/api/v1/mail/dns-check?${params.toString()}`); + if (!res.ok) { + const errorText = await res.text(); + throw new Error(`DNS-Check fehlgeschlagen (${res.status}): ${errorText}`); + } + return (await res.json()) as DnsCheckResult; +} + /** * Fetch aggregate stats for a campaign from mana-mail. Safe to poll on a * timer from the DetailView (M7) — server returns cached rollups. diff --git a/apps/mana/apps/web/src/lib/modules/broadcast/components/DnsCheckBanner.svelte b/apps/mana/apps/web/src/lib/modules/broadcast/components/DnsCheckBanner.svelte new file mode 100644 index 000000000..4ac941ef4 --- /dev/null +++ b/apps/mana/apps/web/src/lib/modules/broadcast/components/DnsCheckBanner.svelte @@ -0,0 +1,346 @@ + + + +
+
+
+

DNS-Authentifizierung

+

+ SPF / DKIM / DMARC auf {domain || '—'} — ohne das landen Newsletter überdurchschnittlich + oft im Spam. +

+
+ +
+ + {#if error} +
{error}
+ {/if} + + {#if result} + + + {#if result.spf.status !== 'ok' || result.dmarc.status === 'missing'} +
+ Empfohlene DNS-Records (zum Kopieren) +

+ Bei deinem Domain-Registrar (z. B. Cloudflare / Infomaniak) als TXT-Records anlegen. +

+ {#if result.spf.status !== 'ok'} +
+
+ TXT auf {result.domain} + +
+
{result.suggested.spfAdd}
+
+ {/if} + {#if result.dmarc.status === 'missing'} +
+
+ + TXT auf _dmarc.{result.domain} + + +
+
{result.suggested.dmarcRecord}
+
+ {/if} + {#if result.dkim.status === 'missing'} +

+ DKIM-Setup ist provider-spezifisch — wende dich an den Mana-Support oder schau in der + Stalwart-Doku, wie der DKIM-Key für + {result.dkim.selector}._domainkey.{result.domain} + aussehen soll. +

+ {/if} +
+ {/if} + + + {:else if settings.dnsCheck} +

+ Letzte Prüfung: {new Date(settings.dnsCheck.checkedAt).toLocaleString()} +
+ SPF {statusIcon(settings.dnsCheck.spf)} · DKIM {statusIcon(settings.dnsCheck.dkim)} · DMARC {statusIcon( + settings.dnsCheck.dmarc + )} +

+ {/if} +
+ + diff --git a/apps/mana/apps/web/src/lib/modules/broadcast/components/SettingsForm.svelte b/apps/mana/apps/web/src/lib/modules/broadcast/components/SettingsForm.svelte index 915bfee27..f81f66bc8 100644 --- a/apps/mana/apps/web/src/lib/modules/broadcast/components/SettingsForm.svelte +++ b/apps/mana/apps/web/src/lib/modules/broadcast/components/SettingsForm.svelte @@ -8,6 +8,7 @@ -->