Something went wrong. Try again.
Cooperative email for PDS operators
Something went wrong. Try again.
5.0 kB · 171 lines
Astro
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172---// Reusable zone-file export block. Mirrors web/templates/marque_import.go// ZoneFileExportFromFields + renderZoneFileExportSection: takes the// same six fields and emits a textarea with the SPF/DMARC/DKIM records// in zone-file format, plus a "Copy to clipboard" button.//// Usage:// <ZoneFileExport// domain={domain}// relayPublicIP={ip}// rsaDNSName={rsa.name}// rsaRecord={rsa.value}// edDNSName={ed.name}// edRecord={ed.value}// />//// Returns nothing renderable when domain or relayPublicIP is empty —// matches the Go formatter's "no relay IP means no SPF, so no export"// branch.
export interface Props { domain: string; relayPublicIP: string; rsaDNSName?: string; rsaRecord?: string; edDNSName?: string; edRecord?: string; /** DMARC reporting mailbox; keep in sync with marque_import.go * dmarcReportingMailbox. */ dmarcReportingMailbox?: string;}
const { domain, relayPublicIP, rsaDNSName, rsaRecord, edDNSName, edRecord, dmarcReportingMailbox = "postmaster@atmos.email",} = Astro.props;
/** Strip a trailing `.<domain>` from an FQDN to produce the relative * form a zone-file importer expects. Mirrors marque.RelativeName. */function relativeName(name: string, dom: string): string { if (!name) return "@"; if (name === dom) return "@"; const suffix = "." + dom; if (name.endsWith(suffix)) { return name.slice(0, -suffix.length); } return name;}
interface ZoneRecord { name: string; type: string; ttl: number; value: string;}
function buildRecords(): ZoneRecord[] { const records: ZoneRecord[] = [ { name: "@", type: "TXT", ttl: 3600, value: `v=spf1 ip4:${relayPublicIP} -all`, }, { name: "_dmarc", type: "TXT", ttl: 3600, value: `v=DMARC1; p=reject; adkim=r; aspf=r; rua=mailto:${dmarcReportingMailbox}`, }, ]; if (rsaDNSName && rsaRecord) { records.push({ name: relativeName(rsaDNSName, domain), type: "TXT", ttl: 3600, value: rsaRecord, }); } if (edDNSName && edRecord) { records.push({ name: relativeName(edDNSName, domain), type: "TXT", ttl: 3600, value: edRecord, }); } return records;}
function formatZoneFile(records: ZoneRecord[]): string { // Same column layout marque.FormatImport produces: name, type, ttl, // value separated by single spaces. Quoting was removed in PR #632 // (internal ref) so we emit values raw. return records.map((r) => `${r.name} ${r.type} ${r.ttl} ${r.value}`).join("\n");}
const enabled = Boolean(domain && relayPublicIP);const exportText = enabled ? formatZoneFile(buildRecords()) : "";const rowCount = enabled ? Math.max(4, exportText.split("\n").length) : 4;---
{ enabled && ( <section class="section"> <h2>Export DNS records (zone-file format)</h2> <p class="section-lede"> Paste the block below into any registrar that accepts zone-file syntax: Cloudflare's <strong>Import and Export</strong>, BIND, Marque's bulk-import dialog, etc. Same records as above for <code>{domain}</code>, one paste instead of four. </p> <textarea id="zonefile-export-text" readonly rows={rowCount} style="width: 100%; font-family: 'JetBrains Mono', monospace; font-size: var(--t-s); padding: 0.5rem;" >{exportText}</textarea> <button type="button" id="zonefile-copy-btn" style="margin-top: 0.5rem;" > Copy to clipboard </button> <p style="margin-top: 0.5rem; font-size: var(--t-xs); color: var(--muted);" > Bulk import doesn't expose your DNS host credentials to comail. We just format the records; you paste them on the host you already control. </p> <script> (function () { var btn = document.getElementById("zonefile-copy-btn"); var ta = document.getElementById( "zonefile-export-text", ) as HTMLTextAreaElement | null; if (!btn || !ta) return; btn.addEventListener("click", function () { ta!.select(); var ok = false; try { ok = document.execCommand("copy"); } catch (e) { /* fall through to clipboard API */ } if (!ok && navigator.clipboard) { navigator.clipboard.writeText(ta!.value).then(function () { btn!.textContent = "Copied"; setTimeout(function () { btn!.textContent = "Copy to clipboard"; }, 2000); }); return; } btn!.textContent = ok ? "Copied" : "Press Cmd/Ctrl+C"; setTimeout(function () { btn!.textContent = "Copy to clipboard"; }, 2000); }); })(); </script> </section> )}