{"id":17467,"date":"2026-11-11T11:46:04","date_gmt":"2026-11-11T10:46:04","guid":{"rendered":"https:\/\/www.mx-relay.com\/?page_id=17467"},"modified":"2026-11-11T12:12:09","modified_gmt":"2026-11-11T11:12:09","slug":"mxtoolbox","status":"publish","type":"page","link":"https:\/\/www.mx-relay.com\/en\/mxtoolbox\/","title":{"rendered":"MXtoolbox"},"content":{"rendered":"\n<style>\n.mxt{--mx-ink:#142d40;--mx-muted:#536776;--mx-teal:#087b82;--mx-line:#dce7eb;--mx-soft:#f3f8f9;max-width:1160px;margin:24px auto 64px;color:var(--mx-ink);font-family:inherit;font-size:16px;line-height:1.6;text-align:left}.mxt *{box-sizing:border-box}.mxt [hidden]{display:none!important}.mxt h2,.mxt h3,.mxt p{font-family:inherit;color:inherit}.mxt button,.mxt input,.mxt textarea{font:inherit}.mxt a{color:var(--mx-teal)}.mxt button{cursor:pointer}.mxt button:disabled{cursor:wait;opacity:.65}.mxt button:focus-visible,.mxt input:focus-visible,.mxt textarea:focus-visible,.mxt a:focus-visible,.mxt summary:focus-visible{outline:3px solid #32b4ae;outline-offset:3px}.mxt-hero{display:grid;grid-template-columns:1fr 260px;gap:36px;align-items:center;padding:44px 42px;border:1px solid var(--mx-line);border-radius:22px;background:linear-gradient(115deg,#f2faf8,#f4f8fb 70%,#e7f4f4)}.mxt-eyebrow{font-size:12px;font-weight:800;letter-spacing:.13em;color:var(--mx-teal)}.mxt-hero h2{margin:14px 0 16px;font-size:clamp(30px,4vw,49px)!important;line-height:1.12!important;letter-spacing:-.035em;font-weight:800!important}.mxt-hero h2 em{font-style:normal;color:var(--mx-teal)}.mxt-hero p{max-width:600px;margin:0;color:var(--mx-muted)}.mxt-hero-note{border-left:1px solid #c9dedf;padding-left:28px}.mxt-hero-note>span{display:block;font-size:46px;color:var(--mx-teal);line-height:1;margin-bottom:18px}.mxt-hero-note strong{font-size:15px}.mxt-hero-note p{font-size:13px;line-height:1.9;margin-top:8px}.mxt-tabs{display:flex;gap:5px;border-bottom:1px solid var(--mx-line);margin:30px 0 28px}.mxt-tabs button{background:transparent;border:0;border-bottom:3px solid transparent;border-radius:0;padding:14px 22px;margin-bottom:-1px;color:var(--mx-muted);font-weight:700}.mxt-tabs button[aria-selected=true]{color:var(--mx-teal);border-bottom-color:var(--mx-teal)}.mxt-tabs button span{font-size:11px;margin-left:12px;opacity:.65}.mxt-form{display:grid;grid-template-columns:1.25fr 1fr auto;gap:18px;align-items:start;padding:26px;background:#fff;border:1px solid var(--mx-line);border-radius:16px;box-shadow:0 6px 24px #142d4006}.mxt label{display:block;font-size:14px;font-weight:700;margin-bottom:8px}.mxt label span{font-size:12px;font-weight:400;color:var(--mx-muted)}.mxt input[type=text],.mxt textarea{display:block!important;width:100%!important;min-width:0;border:1px solid #bdcdd4!important;border-radius:8px!important;background:#fff!important;color:var(--mx-ink)!important;padding:12px 14px!important;line-height:1.5!important;height:auto!important;box-shadow:none!important}.mxt input[type=text]{min-height:50px}.mxt small{display:block;color:var(--mx-muted);font-size:11px;line-height:1.6;margin-top:6px}.mxt code,.mxt pre{font-family:ui-monospace,SFMono-Regular,Consolas,monospace}.mxt-primary,.mxt-secondary{display:inline-flex!important;align-items:center;justify-content:center;gap:20px;padding:13px 20px;border-radius:8px;font-size:14px!important;font-weight:700!important;line-height:1.5;min-height:50px;text-decoration:none;white-space:nowrap}.mxt-primary{background:var(--mx-ink);color:#fff!important;border:1px solid var(--mx-ink)}.mxt-form>.mxt-primary{margin-top:29px}.mxt-primary:hover{background:var(--mx-teal);border-color:var(--mx-teal)}.mxt-secondary{background:#fff;border:1px solid #b9ccd2;color:var(--mx-ink)!important;min-height:44px;padding:10px 16px}.mxt-secondary:hover{background:var(--mx-soft)}.mxt-privacy{font-size:12px;color:var(--mx-muted)!important;margin:12px 4px 24px!important}.mxt-feedback{font-size:14px;font-weight:600;min-height:1.5em;margin:14px 0!important}.mxt-feedback[data-error=true]{color:#b42318}.mxt-results{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}.mxt-card{min-width:0;border:1px solid var(--mx-line);border-radius:14px;background:#fff;padding:22px;position:relative}.mxt-card-header{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:12px}.mxt-card h3{font-size:18px!important;font-weight:700!important;margin:0!important;line-height:1.3!important}.mxt-badge{font-size:11px;font-weight:700;border-radius:30px;padding:4px 10px;white-space:nowrap;background:#edf3f6;color:#486074}.mxt-card[data-tone=ok] .mxt-badge{background:#e7f6ed;color:#157047}.mxt-card[data-tone=warn] .mxt-badge{background:#fff3da;color:#92600b}.mxt-card[data-tone=error] .mxt-badge{background:#fff0ee;color:#b42318}.mxt-card p{font-size:14px;margin:8px 0!important;color:var(--mx-muted)}.mxt-card ul{padding-left:19px;margin:8px 0;color:var(--mx-muted);font-size:13px}.mxt-card details{margin-top:14px;font-size:12px}.mxt summary{cursor:pointer;font-weight:700;color:var(--mx-teal)}.mxt pre{white-space:pre-wrap;overflow-wrap:anywhere;word-break:break-word;background:var(--mx-soft);border:1px solid var(--mx-line);border-radius:7px;padding:12px;color:#304958;font-size:11px;line-height:1.7;max-height:260px;overflow:auto;margin-top:9px}.mxt-report-actions{display:flex;align-items:center;gap:12px;margin-top:20px;font-size:12px}.mxt-explainer{margin-top:36px;border-top:1px solid var(--mx-line);padding-top:26px}.mxt-explainer h3,.mxt-header-intro h3{font-size:22px!important;margin:0 0 16px!important;font-weight:700!important}.mxt-explainer-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:24px}.mxt-explainer-grid p{font-size:13px;color:var(--mx-muted);margin:0}.mxt-explainer-grid strong{display:block;color:var(--mx-ink);margin-bottom:5px}.mxt textarea{font-family:ui-monospace,Consolas,monospace;font-size:12px!important;resize:vertical;min-height:230px}.mxt-header-intro p{color:var(--mx-muted);max-width:800px;margin-bottom:20px}.mxt-header-actions{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-top:16px}.mxt-file-label{position:relative;cursor:pointer;margin:0!important;font-size:14px!important}.mxt-file-label input{position:absolute;width:1px;height:1px;opacity:0}.mxt-file-label:focus-within{outline:3px solid #32b4ae;outline-offset:3px}.mxt-text-button{border:0;background:transparent;color:var(--mx-teal);padding:8px;font-size:13px;font-weight:700}.mxt-header-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:14px;margin-bottom:18px}.mxt-header-grid .mxt-card{padding:18px}.mxt-header-grid .mxt-card strong{display:block;overflow-wrap:anywhere;font-size:14px}.mxt-notice{padding:14px 18px;background:#f3f7fa;border-left:3px solid #7895a7;color:var(--mx-muted);font-size:13px;border-radius:0 8px 8px 0;margin:18px 0}.mxt-table-wrap{overflow:auto;border:1px solid var(--mx-line);border-radius:12px;margin:14px 0 24px}.mxt table{border-collapse:collapse;min-width:620px;width:100%;font-size:12px}.mxt th{text-align:left;background:var(--mx-soft);font-weight:700;padding:12px}.mxt td{padding:12px;border-top:1px solid var(--mx-line);vertical-align:top;overflow-wrap:anywhere;max-width:350px}.mxt-footer{border-top:1px solid var(--mx-line);padding:28px 0 0;margin-top:36px}.mxt-footer p{max-width:900px;font-size:13px;color:var(--mx-muted)}.mxt-footer>a{font-size:14px;font-weight:700}.mxt-footer details{margin-top:24px;font-size:12px}.mxt-dkim-action{margin-top:12px}.mxt-heading{font-size:21px!important;font-weight:700!important;margin-top:28px!important}.mxt-meta{color:var(--mx-muted);font-size:12px}.mxt-spinner{animation:mxt-pulse 1.2s ease-in-out infinite}@keyframes mxt-pulse{50%{opacity:.4}}@media(max-width:850px){.mxt-form{grid-template-columns:1fr 1fr}.mxt-form>.mxt-primary{grid-column:1\/-1;margin-top:0}.mxt-hero{grid-template-columns:1fr;padding:30px}.mxt-hero-note{display:none}.mxt-header-grid{grid-template-columns:1fr 1fr}}@media(max-width:560px){.mxt{margin-top:12px}.mxt-hero{padding:25px 22px}.mxt-form{grid-template-columns:1fr;padding:20px}.mxt-form>.mxt-primary{grid-column:auto}.mxt-results,.mxt-explainer-grid,.mxt-header-grid{grid-template-columns:1fr}.mxt-tabs button{padding:13px 14px;font-size:14px}.mxt-tabs button span{margin-left:6px}.mxt-card{padding:19px}.mxt-header-actions{align-items:stretch}.mxt-header-actions .mxt-primary,.mxt-file-label{width:100%}.mxt-hero h2{font-size:32px!important}}\n\n<\/style>\n<section class=\"mxt\" data-mxtoolbox data-no-translation data-no-dynamic-translation translate=\"no\">\n  <div class=\"mxt-hero\"><div><span class=\"mxt-eyebrow\">MX-RELAY \u00b7 MAILDIAGNOSTIEK<\/span><h2>Je mailinstellingen.<br><em>Helder in \u00e9\u00e9n check.<\/em><\/h2><p>Controleer de DNS-records van je domein of ontdek wat er met een e-mail is gebeurd. Gratis, zonder account.<\/p><\/div><div class=\"mxt-hero-note\"><span aria-hidden=\"true\">&#x2197;<\/span><strong>Van record naar inzicht<\/strong><p>MX \u00b7 SPF \u00b7 DKIM \u00b7 DMARC<br>DNSSEC \u00b7 MTA-STS \u00b7 TLS-RPT<\/p><\/div><\/div>\n  <div class=\"mxt-tabs\" role=\"tablist\" aria-label=\"Kies je analyse\"><button type=\"button\" role=\"tab\" id=\"mxt-tab-domain\" aria-controls=\"mxt-panel-domain\" aria-selected=\"true\" data-tab=\"domain\">Domeincheck <span>01<\/span><\/button><button type=\"button\" role=\"tab\" id=\"mxt-tab-headers\" aria-controls=\"mxt-panel-headers\" aria-selected=\"false\" tabindex=\"-1\" data-tab=\"headers\">Headeranalyse <span>02<\/span><\/button><\/div>\n  <div id=\"mxt-panel-domain\" role=\"tabpanel\" aria-labelledby=\"mxt-tab-domain\" data-panel=\"domain\">\n    <form class=\"mxt-form\" data-role=\"domain-form\"><div class=\"mxt-field\"><label for=\"mxt-domain\">Domeinnaam<\/label><input id=\"mxt-domain\" name=\"domain\" type=\"text\" placeholder=\"bijvoorbeeld.nl\" autocomplete=\"off\" spellcheck=\"false\" maxlength=\"300\" required><small>Een domein, e-mailadres of websiteadres.<\/small><\/div><div class=\"mxt-field\"><label for=\"mxt-selector\">DKIM-selector <span>optioneel<\/span><\/label><input id=\"mxt-selector\" name=\"selector\" type=\"text\" placeholder=\"Bijv. selector1 of google\" autocomplete=\"off\" spellcheck=\"false\" maxlength=\"120\"><small>Vind de selector bij <code>s=<\/code> in de DKIM-Signature.<\/small><\/div><button class=\"mxt-primary\" type=\"submit\" data-role=\"domain-submit\">Controleer domein <span aria-hidden=\"true\">\u2192<\/span><\/button><\/form>\n    <p class=\"mxt-privacy\">DNS-opvragen gaan naar Google Public DNS. Je wijzigt hiermee geen instellingen en verstuurt geen e-mail.<\/p>\n    <p class=\"mxt-feedback\" data-role=\"domain-feedback\" role=\"status\" aria-live=\"polite\"><\/p>\n    <div class=\"mxt-results\" data-role=\"domain-results\" aria-label=\"Resultaten domeincheck\"><\/div>\n    <div class=\"mxt-report-actions\" data-role=\"domain-actions\" hidden><button class=\"mxt-secondary\" type=\"button\" data-role=\"copy-domain\">Kopieer rapport<\/button><span data-role=\"copy-domain-status\" role=\"status\"><\/span><\/div>\n    <div class=\"mxt-explainer\"><h3>Wat vertellen deze checks?<\/h3><div class=\"mxt-explainer-grid\"><p><strong>Ontvangst<\/strong>MX-records wijzen naar je ontvangende mailservers. We controleren ook of die hosts IP-adressen hebben.<\/p><p><strong>Afzenderbescherming<\/strong>SPF, DKIM en DMARC helpen ontvangende servers bepalen of een afzender legitiem is.<\/p><p><strong>Transport &amp; DNS<\/strong>DNSSEC valideert DNS-antwoorden. MTA-STS en TLS-RPT helpen bij beveiligde mailoverdracht en de rapportage daarvan.<\/p><\/div><\/div>\n  <\/div>\n  <div id=\"mxt-panel-headers\" role=\"tabpanel\" aria-labelledby=\"mxt-tab-headers\" data-panel=\"headers\" hidden>\n    <div class=\"mxt-header-intro\"><h3>Volg de route van je e-mail.<\/h3><p>Plak de volledige berichtheaders, of kies lokaal een .eml-bestand. We tonen de route, tijdverschillen en de door mailservers gemelde authenticatieresultaten.<\/p><\/div>\n    <form data-role=\"header-form\"><label for=\"mxt-headers\">Berichtheaders<\/label><textarea id=\"mxt-headers\" data-hj-suppress data-clarity-mask=\"true\" class=\"fs-mask\" autocomplete=\"off\" spellcheck=\"false\" maxlength=\"262144\" rows=\"11\" placeholder=\"Received: from ...&#10;Authentication-Results: ...&#10;DKIM-Signature: ...\"><\/textarea><div class=\"mxt-header-actions\"><button class=\"mxt-primary\" type=\"submit\">Analyseer headers <span aria-hidden=\"true\">\u2192<\/span><\/button><label class=\"mxt-secondary mxt-file-label\" for=\"mxt-file\">Kies .eml of .txt<input id=\"mxt-file\" type=\"file\" accept=\".eml,.txt,message\/rfc822,text\/plain\" data-role=\"header-file\"><\/label><button class=\"mxt-text-button\" type=\"button\" data-role=\"clear-headers\">Wissen<\/button><button class=\"mxt-text-button\" type=\"button\" data-role=\"example-headers\">Bekijk voorbeeld<\/button><\/div><\/form>\n    <p class=\"mxt-privacy\">De toolbox analyseert headers lokaal in je browser en verstuurt of bewaart ze niet. Bij een bestand wordt alleen het headerdeel gebruikt.<\/p><p class=\"mxt-feedback\" data-role=\"header-feedback\" role=\"status\" aria-live=\"polite\"><\/p><div data-role=\"header-results\"><\/div>\n  <\/div>\n  <div class=\"mxt-footer\"><strong>Verder kijken?<\/strong><p>Voor een volledige afleverdiagnose zijn ook een SMTP-\/STARTTLS-test, certificaatcontrole, reverse DNS van het verzendende IP en IP-reputatie nuttig. Die live server- en reputatietests vallen buiten deze DNS- en headercheck.<\/p><a href=\"\/contact\/\">Hulp nodig met je mailinstellingen? <span aria-hidden=\"true\">\u2192<\/span><\/a><details><summary>Over de resultaten en standaarden<\/summary><p>Een DNS-record is geen bewijs dat elk bericht slaagt voor authenticatie. Deze tool verstuurt geen testmail en verifieert geen DKIM-handtekening of DMARC-resultaat van een bericht. Een headeranalyse toont wat de betrokken servers melden; headers kunnen worden vervalst. De DNS-resultaten zijn een momentopname en kunnen afwijken van lokale caches.<\/p><p><a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc7208\" target=\"_blank\" rel=\"noopener noreferrer\">SPF<\/a> \u00b7 <a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc6376\" target=\"_blank\" rel=\"noopener noreferrer\">DKIM<\/a> \u00b7 <a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc7489\" target=\"_blank\" rel=\"noopener noreferrer\">DMARC<\/a> \u00b7 <a href=\"https:\/\/developers.google.com\/speed\/public-dns\/docs\/doh\/json\" target=\"_blank\" rel=\"noopener noreferrer\">DNS-resolver<\/a><\/p><\/details><\/div>\n  <noscript>Schakel JavaScript in om de domeincheck en lokale headeranalyse te gebruiken.<\/noscript>\n<\/section>\n\n<template data-mxt-english data-no-translation>\n<section class=\"mxt\" data-mxtoolbox data-no-translation data-no-dynamic-translation translate=\"no\">\n  <div class=\"mxt-hero\"><div><span class=\"mxt-eyebrow\">MX-RELAY \u00b7 EMAIL DIAGNOSTICS<\/span><h2>Your email settings.<br><em>Clear in one check.<\/em><\/h2><p>Check your domain\u2019s DNS records or discover what happened to an email. Free, with no account required.<\/p><\/div><div class=\"mxt-hero-note\"><span aria-hidden=\"true\">&#x2197;<\/span><strong>From records to insight<\/strong><p>MX \u00b7 SPF \u00b7 DKIM \u00b7 DMARC<br>DNSSEC \u00b7 MTA-STS \u00b7 TLS-RPT<\/p><\/div><\/div>\n  <div class=\"mxt-tabs\" role=\"tablist\" aria-label=\"Choose an analysis\"><button type=\"button\" role=\"tab\" id=\"mxt-tab-domain\" aria-controls=\"mxt-panel-domain\" aria-selected=\"true\" data-tab=\"domain\">Domain check <span>01<\/span><\/button><button type=\"button\" role=\"tab\" id=\"mxt-tab-headers\" aria-controls=\"mxt-panel-headers\" aria-selected=\"false\" tabindex=\"-1\" data-tab=\"headers\">Header analysis <span>02<\/span><\/button><\/div>\n  <div id=\"mxt-panel-domain\" role=\"tabpanel\" aria-labelledby=\"mxt-tab-domain\" data-panel=\"domain\">\n    <form class=\"mxt-form\" data-role=\"domain-form\"><div class=\"mxt-field\"><label for=\"mxt-domain\">Domain name<\/label><input id=\"mxt-domain\" name=\"domain\" type=\"text\" placeholder=\"example.com\" autocomplete=\"off\" spellcheck=\"false\" maxlength=\"300\" required><small>A domain, email address or website URL.<\/small><\/div><div class=\"mxt-field\"><label for=\"mxt-selector\">DKIM selector <span>optional<\/span><\/label><input id=\"mxt-selector\" name=\"selector\" type=\"text\" placeholder=\"For example, selector1 or google\" autocomplete=\"off\" spellcheck=\"false\" maxlength=\"120\"><small>Find the selector in the <code>s=<\/code> tag of a DKIM-Signature.<\/small><\/div><button class=\"mxt-primary\" type=\"submit\" data-role=\"domain-submit\">Check domain <span aria-hidden=\"true\">\u2192<\/span><\/button><\/form>\n    <p class=\"mxt-privacy\">DNS queries are sent to Google Public DNS. This does not change any settings or send email.<\/p>\n    <p class=\"mxt-feedback\" data-role=\"domain-feedback\" role=\"status\" aria-live=\"polite\"><\/p>\n    <div class=\"mxt-results\" data-role=\"domain-results\" aria-label=\"Domain check results\"><\/div>\n    <div class=\"mxt-report-actions\" data-role=\"domain-actions\" hidden><button class=\"mxt-secondary\" type=\"button\" data-role=\"copy-domain\">Copy report<\/button><span data-role=\"copy-domain-status\" role=\"status\"><\/span><\/div>\n    <div class=\"mxt-explainer\"><h3>What do these checks tell you?<\/h3><div class=\"mxt-explainer-grid\"><p><strong>Receiving email<\/strong>MX records point to your incoming mail servers. We also check whether those hosts have IP addresses.<\/p><p><strong>Sender protection<\/strong>SPF, DKIM and DMARC help receiving servers determine whether a sender is legitimate.<\/p><p><strong>Transport &amp; DNS<\/strong>DNSSEC validates DNS responses. MTA-STS and TLS-RPT support secure email transport and reporting.<\/p><\/div><\/div>\n  <\/div>\n  <div id=\"mxt-panel-headers\" role=\"tabpanel\" aria-labelledby=\"mxt-tab-headers\" data-panel=\"headers\" hidden>\n    <div class=\"mxt-header-intro\"><h3>Follow your email\u2019s journey.<\/h3><p>Paste the complete message headers or select a local .eml file. We show the route, time differences and authentication results reported by mail servers.<\/p><\/div>\n    <form data-role=\"header-form\"><label for=\"mxt-headers\">Message headers<\/label><textarea id=\"mxt-headers\" data-hj-suppress data-clarity-mask=\"true\" class=\"fs-mask\" autocomplete=\"off\" spellcheck=\"false\" maxlength=\"262144\" rows=\"11\" placeholder=\"Received: from ...&#10;Authentication-Results: ...&#10;DKIM-Signature: ...\"><\/textarea><div class=\"mxt-header-actions\"><button class=\"mxt-primary\" type=\"submit\">Analyze headers <span aria-hidden=\"true\">\u2192<\/span><\/button><label class=\"mxt-secondary mxt-file-label\" for=\"mxt-file\">Choose .eml or .txt<input id=\"mxt-file\" type=\"file\" accept=\".eml,.txt,message\/rfc822,text\/plain\" data-role=\"header-file\"><\/label><button class=\"mxt-text-button\" type=\"button\" data-role=\"clear-headers\">Clear<\/button><button class=\"mxt-text-button\" type=\"button\" data-role=\"example-headers\">View example<\/button><\/div><\/form>\n    <p class=\"mxt-privacy\">The toolbox analyzes headers locally in your browser without transmitting or storing them. Only the header section of a selected file is used.<\/p><p class=\"mxt-feedback\" data-role=\"header-feedback\" role=\"status\" aria-live=\"polite\"><\/p><div data-role=\"header-results\"><\/div>\n  <\/div>\n  <div class=\"mxt-footer\"><strong>Want to go further?<\/strong><p>A complete delivery diagnosis can also include SMTP\/STARTTLS testing, certificate checks, reverse DNS for the sending IP and IP reputation. Those live server and reputation tests are outside the scope of this DNS and header check.<\/p><a href=\"\/en\/contact\/\">Need help with your email settings? <span aria-hidden=\"true\">\u2192<\/span><\/a><details><summary>About the results and standards<\/summary><p>A DNS record does not prove that every message passes authentication. This tool does not send test emails or verify a message\u2019s DKIM signature or DMARC result. Header analysis shows what the servers report; headers can be forged. DNS results are a snapshot and may differ from local caches.<\/p><p><a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc7208\" target=\"_blank\" rel=\"noopener noreferrer\">SPF<\/a> \u00b7 <a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc6376\" target=\"_blank\" rel=\"noopener noreferrer\">DKIM<\/a> \u00b7 <a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc7489\" target=\"_blank\" rel=\"noopener noreferrer\">DMARC<\/a> \u00b7 <a href=\"https:\/\/developers.google.com\/speed\/public-dns\/docs\/doh\/json\" target=\"_blank\" rel=\"noopener noreferrer\">DNS resolver<\/a><\/p><\/details><\/div>\n  <noscript>Enable JavaScript to use the domain check and local header analysis.<\/noscript>\n<\/section>\n\n<\/template>\n<script>\n(() => {\n  'use strict';\n  const english = \/^en(?:-|$)\/i.test(document.documentElement.lang) || \/^\\\/en(?:\\\/|$)\/i.test(location.pathname);\n  const locale = english ? 'en-GB' : 'nl-NL';\n  const tr = (nl, en) => english ? en : nl;\n  const TYPES = { A: 1, NS: 2, CNAME: 5, MX: 15, TXT: 16, AAAA: 28 };\n  const labels = { ok: tr(\"In orde\", \"OK\"), warn: tr(\"Aandachtspunt\", \"Needs attention\"), error: tr(\"Probleem\", \"Issue\"), info: tr(\"Ter informatie\", \"Information\"), loading: tr(\"Bezig\u2026\", \"Checking\u2026\") };\n  const domainPattern = \/^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z](?:[a-z0-9-]{0,61}[a-z0-9])?$\/i;\n  const dnsNamePattern = \/^(?=.{1,253}$)(?:[a-z0-9_-]{1,63}\\.)+[a-z0-9_-]{1,63}$\/i;\n  function normaliseDomain(value) {\n    let raw = String(value).trim();\n    if (!raw || \/[\\r\\n\\t]\/.test(raw)) throw new Error(tr(\"Vul een geldige domeinnaam in.\", \"Enter a valid domain name.\"));\n    if (!\/^https?:\\\/\\\/\/i.test(raw) && raw.includes('@')) raw = raw.slice(raw.lastIndexOf('@') + 1);\n    let url; try { url = new URL(\/^https?:\\\/\\\/\/i.test(raw) ? raw : 'https:\/\/' + raw); } catch { throw new Error(tr(\"Vul een geldige domeinnaam in.\", \"Enter a valid domain name.\")); }\n    const domain = url.hostname.toLowerCase().replace(\/\\.$\/, '');\n    if (!domainPattern.test(domain) || url.username || url.password || \/\\s\/.test(raw)) throw new Error(tr(\"Gebruik een publiek domein, bijvoorbeeld voorbeeld.nl.\", \"Enter a public domain, for example example.com.\"));\n    return domain;\n  }\n  function txt(data) {\n    const parts = [...String(data).matchAll(\/\"((?:\\\\.|[^\"\\\\])*)\"\/g)];\n    return parts.length ? parts.map(m => m[1].replace(\/\\\\(\\d{3})|\\\\(.)\/g, (_, n, c) => n ? String.fromCharCode(Number(n)) : c)).join('') : String(data);\n  }\n  function tags(record) {\n    const values = {}, duplicate = [];\n    for (const term of record.split(';')) {\n      const at = term.indexOf('='); if (0 > at) continue;\n      const key = term.slice(0, at).trim().toLowerCase();\n      if (Object.hasOwn(values, key)) duplicate.push(key);\n      values[key] = term.slice(at + 1).trim();\n    }\n    return { values, duplicate };\n  }\n  function createResolver(signal) {\n    const cache = new Map(); let count = 0;\n    return async (name, type) => {\n      const key = `${name}:${type}`;\n      if (cache.has(key)) return cache.get(key);\n      if (++count > 80) throw new Error(tr(\"De limiet voor deze controle is bereikt. Controleer specifieke records afzonderlijk.\", \"The query limit for this check has been reached. Check specific records separately.\"));\n      const promise = (async () => {\n        const controller = new AbortController();\n        const stop = () => controller.abort();\n        signal?.addEventListener('abort', stop, { once: true });\n        if (signal?.aborted) controller.abort();\n        const timer = setTimeout(stop, 9000);\n        try {\n          const url = new URL('https:\/\/dns.google\/resolve');\n          url.searchParams.set('name', name); url.searchParams.set('type', type); url.searchParams.set('do', 'true'); url.searchParams.set('cd', 'false');\n          const response = await fetch(url.toString(), { signal: controller.signal, credentials: 'omit', referrerPolicy: 'no-referrer' });\n          if (!response.ok) throw new Error(tr(\"De DNS-resolver is tijdelijk niet beschikbaar.\", \"The DNS resolver is temporarily unavailable.\"));\n          const data = await response.json();\n          if (![0, 3].includes(data.Status)) throw new Error(tr(`De DNS-resolver geeft fout ${data.Status}. Het domein kan niet betrouwbaar worden gecontroleerd.`, `The DNS resolver returned error ${data.Status}. The domain could not be checked reliably.`));\n          return { ...data, records: (data.Answer || []).filter(r => r.type === TYPES[type]).map(r => type === 'TXT' ? txt(r.data) : r.data) };\n        } catch (e) {\n          if (e.name === 'AbortError') throw new Error(signal?.aborted ? tr(\"Controle geannuleerd.\", \"Check cancelled.\") : tr(\"DNS-opvraag duurde te lang. Probeer het opnieuw.\", \"The DNS request timed out. Please try again.\"));\n          throw e;\n        } finally { clearTimeout(timer); signal?.removeEventListener('abort', stop); }\n      })();\n      cache.set(key, promise); return promise;\n    };\n  }\n  const result = (tone, summary, notes = [], records = []) => ({ tone, summary, notes, records });\n  async function checkMx(domain, dns) {\n    const r = await dns(domain, 'MX');\n    if (!r.records.length) {\n      const ips = await Promise.all([dns(domain, 'A'), dns(domain, 'AAAA')]);\n      return result('warn', tr(\"Geen MX-record gevonden.\", \"No MX record found.\"), [ips.some(x => x.records.length) ? tr(\"Er zijn wel IP-adressen: SMTP kan bij een ontbrekend MX-record daarop terugvallen. Een afleverpoging is niet uitgevoerd.\", \"IP addresses exist: SMTP may fall back to them when no MX record is present. No delivery attempt was made.\") : tr(\"Ook geen A- of AAAA-record gevonden voor terugval.\", \"No A or AAAA record was found for fallback delivery either.\"), tr(\"Een MX-record beschrijft ontvangst, niet welke servers namens dit domein mogen versturen.\", \"An MX record describes incoming mail, not which servers are allowed to send on behalf of this domain.\")]);\n    }\n    const parsed = r.records.map(v => { const m = String(v).match(\/^(\\d+)\\s+(\\S+)$\/); if (!m) throw new Error(tr(\"Onverwacht formaat van een MX-record.\", \"Unexpected MX record format.\")); return { priority: Number(m[1]), host: m[2].replace(\/\\.$\/, '') }; }).sort((a, b) => a.priority - b.priority);\n    if (parsed.some(x => !x.host)) return parsed.length === 1 && parsed[0].priority === 0 ? result('info', tr(\"Null MX: dit domein verklaart geen e-mail te ontvangen.\", \"Null MX: this domain declares that it does not receive email.\"), [], r.records) : result('error', tr(\"Een Null MX is gecombineerd met andere MX-records of een ongeldige prioriteit.\", \"A Null MX is combined with other MX records or an invalid priority.\"), [], r.records);\n    if (parsed.length > 12) return result('warn', tr(`${parsed.length} MX-records gevonden; alleen de DNS-lijst wordt getoond.`, `${parsed.length} MX records found; only the DNS list is shown.`), [tr(\"Er zijn te veel mailservers om hun adressen in \u00e9\u00e9n check op te vragen.\", \"There are too many mail servers to resolve their addresses in a single check.\")], r.records);\n    let missing = false, alias = false;\n    const notes = await Promise.all(parsed.map(async mx => {\n      const [a, aaaa] = await Promise.all([dns(mx.host, 'A'), dns(mx.host, 'AAAA')]);\n      const addresses = [...a.records, ...aaaa.records];\n      missing ||= addresses.length === 0;\n      alias ||= [...(a.Answer || []), ...(aaaa.Answer || [])].some(x => x.type === TYPES.CNAME && String(x.name).replace(\/\\.$\/, '').toLowerCase() === mx.host.toLowerCase());\n      return `${mx.priority} \u00b7 ${mx.host} \u2192 ${addresses.join(', ') || tr(\"geen IP-adres gevonden\", \"no IP address found\")}`;\n    }));\n    if (alias) notes.push(tr(\"Minstens \u00e9\u00e9n MX-host is een CNAME. Gebruik voor MX een host met directe adresrecords.\", \"At least one MX host is a CNAME. MX targets should have direct address records.\"));\n    notes.push(tr(\"Een lager prioriteitsgetal heeft voorrang. SMTP-bereikbaarheid en certificaten zijn niet getest.\", \"A lower priority number takes precedence. SMTP connectivity and certificates have not been tested.\"));\n    return result(missing ? 'error' : alias ? 'warn' : 'ok', tr(`${parsed.length} ontvangende mailserver${parsed.length === 1 ? '' : 's'} gevonden.`, `${parsed.length} receiving mail server${parsed.length === 1 ? '' : 's'} found.`), notes, r.records);\n  }\n  async function checkSpf(domain, dns) {\n    const records = (await dns(domain, 'TXT')).records.filter(x => \/^v=spf1(?:\\s|$)\/i.test(x));\n    if (!records.length) return result('warn', tr(\"Geen SPF-record gevonden.\", \"No SPF record found.\"), [tr(\"SPF vertelt welke servers de envelopafzender van dit domein mogen gebruiken.\", \"SPF specifies which servers may use this domain as the envelope sender.\")]);\n    if (records.length !== 1) return result('error', tr(\"Meerdere SPF-records: een domein mag maar \u00e9\u00e9n SPF-record hebben.\", \"Multiple SPF records: a domain may publish only one SPF record.\"), [], records);\n    const record = records[0], terms = record.trim().split(\/\\s+\/).slice(1), notes = [];\n    const all = terms.findIndex(t => \/^[+?~-]?all$\/i.test(t));\n    if (terms.some(t => \/^\\+?all$\/i.test(t))) return result('error', tr(\"SPF staat iedere verzendende server toe (+all).\", \"SPF allows every sending server (+all).\"), [tr(\"Beperk het record tot je werkelijke maildiensten.\", \"Limit the record to your actual email services.\")], records);\n    let tone = 'ok';\n    if (0 > all && !terms.some(t => \/^redirect=\/i.test(t))) { tone = 'warn'; notes.push(tr(\"Geen afsluitend all-mechanisme of redirect gevonden.\", \"No final all mechanism or redirect found.\")); }\n    if (all >= 0 && all !== terms.length - 1) { tone = 'warn'; notes.push(tr(\"Termen na all worden niet ge\u00ebvalueerd.\", \"Terms after all are not evaluated.\")); }\n    if (terms.some(t => \/^(?:\\?|~)all$\/i.test(t))) notes.push(tr(\"Het all-mechanisme geeft neutral of softfail; dat is geen harde afwijzing.\", \"The all mechanism returns neutral or softfail, rather than a hard fail.\"));\n    if (terms.some(t => \/^[+?~-]?ptr(?::|$)\/i.test(t))) { tone = 'warn'; notes.push(tr(\"Het verouderde ptr-mechanisme wordt afgeraden.\", \"The legacy ptr mechanism is not recommended.\")); }\n    const known = \/^[+?~-]?(?:all|include:[^\\s]+|ip4:[^\\s]+|ip6:[^\\s]+|a(?::[^\\s\/]+)?(?:\\\/\\d+)?(?:\\\/\\\/\\d+)?|mx(?::[^\\s\/]+)?(?:\\\/\\d+)?(?:\\\/\\\/\\d+)?|ptr(?::[^\\s]+)?|exists:[^\\s]+)$|^[a-z][a-z0-9_.-]*=[^\\s]+$\/i;\n    if (terms.some(t => !known.test(t))) return result('error', tr(\"Een SPF-term heeft een onbekend of ongeldig formaat.\", \"An SPF term has an unknown or invalid format.\"), [tr(\"Dit is een DNS-\/configuratiecontrole, geen volledige SPF-evaluatie voor een verzendend IP.\", \"This is a DNS\/configuration check, not a full SPF evaluation for a sending IP.\")], records);\n    for (const term of terms) {\n      const ip = term.match(\/^[+?~-]?ip([46]):(.+)$\/i);\n      if (!ip) continue;\n      const parts = ip[2].split('\/'), address = parts[0], maximum = ip[1] === '4' ? 32 : 128;\n      let valid = parts.length === 1 || (parts.length === 2 && \/^\\d+$\/.test(parts[1]) && maximum >= Number(parts[1]));\n      if (ip[1] === '4') valid = valid && \/^(?:\\d{1,3}\\.){3}\\d{1,3}$\/.test(address) && address.split('.').every(n => 255 >= Number(n));\n      else { try { if (!\/^[0-9a-f:.]+$\/i.test(address)) throw new Error(); new URL('https:\/\/[' + address + ']\/'); } catch { valid = false; } }\n      if (!valid) return result('error', tr('Een SPF ip' + ip[1] + '-adres of netwerkmasker is ongeldig.', 'An SPF ip' + ip[1] + ' address or network mask is invalid.'), [], records);\n    }\n    let lookups = 0, incomplete = false;\n    async function walk(name, rec, path) {\n      if (path.includes(name)) throw new Error(tr(\"Een kringverwijzing in de SPF include-\/redirect-keten gevonden.\", \"A circular reference was found in the SPF include\/redirect chain.\"));\n      if (path.length > 10) { incomplete = true; return; }\n      const chain = [...path, name];\n      const currentTerms = rec.trim().split(\/\\s+\/).slice(1);\n      const hasAll = currentTerms.some(t => \/^[+?~-]?all$\/i.test(t));\n      for (const term of currentTerms) {\n        if (\/^[+?~-]?all$\/i.test(term)) break;\n        if (hasAll && \/^redirect=\/i.test(term)) continue;\n        if (\/^[+?~-]?(include:|a(?::|\\\/|$)|mx(?::|\\\/|$)|ptr(?::|$)|exists:)\/i.test(term) || \/^redirect=\/i.test(term)) lookups++;\n        if (lookups > 10) return;\n        const child = term.match(\/^[+?~-]?include:(.+)$|^redirect=(.+)$\/i);\n        if (!child) continue;\n        const target = (child[1] || child[2]).replace(\/\\.$\/, '').toLowerCase();\n        if (!dnsNamePattern.test(target)) { incomplete = true; continue; }\n        const sub = (await dns(target, 'TXT')).records.filter(x => \/^v=spf1(?:\\s|$)\/i.test(x));\n        if (sub.length !== 1) throw new Error(tr(`SPF-verwijzing naar ${target} bevat ${sub.length ? 'meerdere SPF-records' : 'geen SPF-record'}.`, `The SPF reference to ${target} contains ${sub.length ? 'multiple SPF records' : 'no SPF record'}.`));\n        await walk(target, sub[0], chain);\n      }\n    }\n    try { await walk(domain, record, []); } catch (e) { return result('error', e.message, [], records); }\n    notes.push(tr(`${lookups > 10 ? 'Meer dan 10' : lookups} DNS-opvragende termen gevonden in de onderzochte include-\/redirect-keten.`, `${lookups > 10 ? 'More than 10' : lookups} DNS-querying terms found in the examined include\/redirect chain.`));\n    if (lookups > 10) { tone = 'warn'; notes.push(tr(\"De limiet kan worden overschreden. Het werkelijke pad hangt af van het verzendende IP; deze telling is een indicatie, geen exacte SPF-evaluatie.\", \"The lookup limit may be exceeded. The actual path depends on the sending IP; this count is an estimate, not an exact SPF evaluation.\")); }\n    if (incomplete) { tone = 'warn'; notes.push(tr(\"Niet alle verwijzingen konden statisch worden gevolgd, bijvoorbeeld door SPF-macro\u2019s.\", \"Not all references could be followed statically, for example because they contain SPF macros.\")); }\n    return result(tone, tr(\"E\u00e9n SPF-record gevonden.\", \"One SPF record found.\"), notes, records);\n  }\n  async function keyStrength(value, kind) {\n    if (!\/^[A-Za-z0-9+\/]+={0,2}$\/.test(value)) throw new Error(tr(\"De DKIM-public key is geen geldige base64.\", \"The DKIM public key is not valid base64.\"));\n    const bytes = Uint8Array.from(atob(value), c => c.charCodeAt(0));\n    if (kind === 'ed25519') { if (bytes.length !== 32) throw new Error(tr(\"Een Ed25519-sleutel moet 32 bytes bevatten.\", \"An Ed25519 key must contain 32 bytes.\")); return 'Ed25519 \u00b7 256 bit'; }\n    if (kind !== 'rsa') throw new Error(tr('Onbekend DKIM-sleuteltype: ' + kind, 'Unknown DKIM key type: ' + kind));\n    if (!globalThis.crypto?.subtle) return tr(\"RSA \u00b7 sleutellengte kon in deze browser niet worden gecontroleerd\", \"RSA \u00b7 the key length could not be checked in this browser\");\n    let key;\n    const algorithm = { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' };\n    try { key = await crypto.subtle.importKey('spki', bytes, algorithm, false, ['verify']); }\n    catch {\n      \/\/ DKIM keys occur as either SubjectPublicKeyInfo or a raw DER RSAPublicKey.\n      if (bytes.length > 16384) throw new Error(tr(\"De DKIM-sleutel is te groot.\", \"The DKIM key is too large.\"));\n      const length = n => 128 > n ? [n] : 256 > n ? [129, n] : [130, n >> 8, n & 255];\n      const rsa = [48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0];\n      const body = [...rsa, 3, ...length(bytes.length + 1), 0, ...bytes];\n      const wrapped = new Uint8Array([48, ...length(body.length), ...body]);\n      key = await crypto.subtle.importKey('spki', wrapped, algorithm, false, ['verify']);\n    }\n    const bits = key.algorithm.modulusLength;\n    if (1024 > bits) throw new Error(tr(`RSA-sleutel is te kort: ${bits} bit.`, `The RSA key is too short: ${bits} bits.`));\n    return `RSA \u00b7 ${bits} bit${2048 > bits ? tr(\" \u00b7 2048 bit of meer wordt aanbevolen\", \" \u00b7 2048 bits or more is recommended\") : ''}`;\n  }\n  async function checkDkim(domain, selector, dns) {\n    const supplied = !!selector.trim();\n    const selectors = supplied ? [...new Set(selector.trim().split(\/[\\s,]+\/))] : ['selector1', 'selector2', 'default', 'google', 'mxrelay'];\n    if (selectors.length > 5 || selectors.some(x => x.length > 100 || !\/^[a-z0-9_-]+(?:\\.[a-z0-9_-]+)*$\/i.test(x))) throw new Error(tr(\"Gebruik maximaal vijf DKIM-selectors, met alleen letters, cijfers, punten, _ en -.\", \"Enter up to five DKIM selectors using only letters, numbers, dots, _ and -.\"));\n    const checks = await Promise.all(selectors.map(async s => {\n      const records = (await dns(`${s}._domainkey.${domain}`, 'TXT')).records.filter(r => \/(?:^|;)\\s*p\\s*=\/i.test(r) || \/^v=DKIM1\/i.test(r));\n      if (!records.length) return { selector: s, records, missing: true };\n      if (records.length > 1) return { selector: s, records, error: tr(\"Meerdere sleutelrecords voor \u00e9\u00e9n selector.\", \"Multiple key records for one selector.\") };\n      const t = tags(records[0]);\n      if (t.duplicate.length || (t.values.v && t.values.v !== 'DKIM1')) return { selector: s, records, error: tr(\"Ongeldige versie of dubbele DKIM-tags.\", \"Invalid version or duplicate DKIM tags.\") };\n      if (!Object.hasOwn(t.values, 'p')) return { selector: s, records, error: tr(\"Public key (p=) ontbreekt.\", \"Public key (p=) is missing.\") };\n      if (!t.values.p) return { selector: s, records, error: tr(\"De sleutel is ingetrokken (lege p=).\", \"The key has been revoked (empty p=).\") };\n      try { return { selector: s, records, strength: await keyStrength(t.values.p.replace(\/\\s\/g, ''), (t.values.k || 'rsa').toLowerCase()) }; }\n      catch (e) { return { selector: s, records, error: e.name === 'DataError' ? tr(\"De public key kan niet als RSA-sleutel worden gelezen.\", \"The public key could not be read as an RSA key.\") : e.message }; }\n    }));\n    const found = checks.filter(x => !x.missing), invalid = found.filter(x => x.error);\n    const notes = checks.map(x => `${x.selector}: ${x.missing ? tr(\"geen sleutel gevonden\", \"no key found\") : x.error || x.strength}`);\n    notes.push(supplied ? tr(\"Alleen de opgegeven selectors zijn onderzocht.\", \"Only the specified selectors were checked.\") : tr(\"Alleen vijf veelgebruikte selectors zijn geprobeerd. Geef de s=-waarde uit een DKIM-Signature op voor een gerichte check.\", \"Only five common selectors were tried. Enter the s= value from a DKIM-Signature for a targeted check.\"));\n    notes.push(tr(\"Een gevonden sleutel bewijst niet dat een afzonderlijke e-mail een geldige DKIM-handtekening heeft.\", \"Finding a key does not prove that a particular email has a valid DKIM signature.\"));\n    return result(invalid.length ? 'error' : !found.length ? supplied ? 'warn' : 'info' : found.some(x => \/aanbevolen|recommended\/.test(x.strength || '')) ? 'warn' : 'ok', found.length ? tr(`${found.length} selector${found.length === 1 ? '' : 's'} met een sleutelrecord gevonden.`, `${found.length} selector${found.length === 1 ? '' : 's'} with a key record found.`) : supplied ? tr(\"Geen DKIM-sleutel gevonden voor deze selector(s).\", \"No DKIM key found for the specified selector(s).\") : tr(\"DKIM kan zonder de juiste selector niet worden vastgesteld.\", \"DKIM cannot be established without the correct selector.\"), notes, found.flatMap(x => x.records.map(r => `${x.selector}._domainkey.${domain}\\n${r}`)));\n  }\n  async function checkDmarc(domain, dns) {\n    const records = (await dns('_dmarc.' + domain, 'TXT')).records.filter(x => \/^v=DMARC1(?:\\s*;|$)\/i.test(x));\n    if (!records.length) return result('warn', tr(\"Geen DMARC-record op dit domein gevonden.\", \"No DMARC record found on this domain.\"), [tr(\"Een subdomein kan beleid van het organisatiedomein erven. Die volledige policy discovery is hier niet uitgevoerd.\", \"A subdomain may inherit policy from its organizational domain. Full policy discovery has not been performed here.\")]);\n    if (records.length > 1) return result('error', tr(\"Meerdere DMARC-records gevonden.\", \"Multiple DMARC records found.\"), [], records);\n    const t = tags(records[0]), p = t.values.p;\n    if (t.duplicate.length || !['none', 'quarantine', 'reject'].includes(p) || (t.values.pct && !\/^(?:100|[1-9]?\\d)$\/.test(t.values.pct)) || ['adkim', 'aspf'].some(k => t.values[k] && !['r', 's'].includes(t.values[k])) || (t.values.sp && !['none', 'quarantine', 'reject'].includes(t.values.sp))) return result('error', tr(\"Het DMARC-record bevat ongeldige of dubbele beleidstags.\", \"The DMARC record contains invalid or duplicate policy tags.\"), [], records);\n    const notes = [tr(`Beleid: ${p}. SPF-uitlijning: ${t.values.aspf === 's' ? 'strict' : 'relaxed'}; DKIM-uitlijning: ${t.values.adkim === 's' ? 'strict' : 'relaxed'}.`, `Policy: ${p}. SPF alignment: ${t.values.aspf === 's' ? 'strict' : 'relaxed'}; DKIM alignment: ${t.values.adkim === 's' ? 'strict' : 'relaxed'}.`)];\n    if (p === 'none') notes.push(tr(\"Monitoring: je vraagt ontvangers nog niet om mislukte DMARC-controles te blokkeren.\", \"Monitoring: you are not yet asking recipients to block messages that fail DMARC.\"));\n    if (t.values.pct && 100 > Number(t.values.pct)) notes.push(tr(`Het beleid wordt voor ${t.values.pct}% gevraagd; niet voor alle berichten.`, `The policy is requested for ${t.values.pct}% of messages, not all messages.`));\n    notes.push(t.values.rua ? tr(\"Adres voor geaggregeerde rapportage aanwezig. Bereikbaarheid en toestemming van externe rapportontvangers zijn niet gecontroleerd.\", \"An aggregate reporting address is present. Reachability and authorization of external report recipients have not been checked.\") : tr(\"Geen rua-adres voor geaggregeerde rapportage gevonden.\", \"No rua address found for aggregate reporting.\"));\n    return result(p === 'none' || (t.values.pct && 100 > Number(t.values.pct)) ? 'warn' : 'ok', tr(`DMARC-beleid: ${p}.`, `DMARC policy: ${p}.`), notes, records);\n  }\n  async function checkDnssec(domain, dns) {\n    const r = await dns(domain, 'MX');\n    return r.AD === true ? result('ok', tr(\"Het DNS-antwoord is met DNSSEC gevalideerd.\", \"The DNS response was validated with DNSSEC.\"), [tr(\"Google Public DNS meldt de AD-vlag voor dit antwoord. Dit zegt niets over de inhoudelijke juistheid van je mailrecords.\", \"Google Public DNS reports the AD flag for this response. This does not assess the actual configuration of your mail records.\")]) : result('info', tr(\"Geen DNSSEC-gevalideerd antwoord ontvangen.\", \"No DNSSEC-validated response received.\"), [tr(\"Het antwoord heeft geen AD-vlag. Dit is geen bewijs van een aanval; het domein kan bijvoorbeeld niet ondertekend zijn.\", \"The response has no AD flag. This is not evidence of an attack; the domain may simply be unsigned.\")]);\n  }\n  async function checkTransport(domain, dns, type) {\n    const sts = type === 'sts', host = sts ? '_mta-sts.' : '_smtp._tls.', version = sts ? 'STSv1' : 'TLSRPTv1';\n    const records = (await dns(host + domain, 'TXT')).records.filter(r => new RegExp('^v=' + version + '(?:\\\\s*;|$)', 'i').test(r));\n    if (!records.length) return result('info', tr(`Geen ${sts ? 'MTA-STS' : 'TLS-RPT'}-record gevonden.`, `No ${sts ? 'MTA-STS' : 'TLS-RPT'} record found.`), [sts ? tr(\"MTA-STS kan versleutelde aflevering aan je domein afdwingen als ook de HTTPS-policy correct is ingesteld.\", \"MTA-STS can enforce encrypted delivery to your domain when the HTTPS policy is also configured correctly.\") : tr(\"TLS-RPT kan rapporten over mislukte versleutelde mailoverdracht laten sturen.\", \"TLS-RPT enables reports about failures in encrypted email transport.\")]);\n    const t = tags(records[0]);\n    if (records.length > 1 || t.duplicate.length || !(sts ? t.values.id : t.values.rua)) return result('error', tr(\"Onvolledig record of meerdere records gevonden.\", \"An incomplete record or multiple records were found.\"), [], records);\n    return result(sts ? 'info' : 'ok', tr(`${sts ? 'MTA-STS DNS-verwijzing' : 'TLS-rapportageadres'} gevonden.`, `${sts ? 'MTA-STS DNS reference' : 'TLS reporting address'} found.`), [sts ? tr(\"De HTTPS-policy op mta-sts en de TLS-verbinding met je MX-servers zijn niet gecontroleerd. Een DNS-record alleen betekent niet dat MTA-STS werkt.\", \"The HTTPS policy on mta-sts and the TLS connection to your MX servers have not been checked. A DNS record alone does not prove that MTA-STS works.\") : tr(\"Dit controleert alleen het DNS-record; ontvangst en verwerking van TLS-rapporten zijn niet getest.\", \"This checks the DNS record only; receiving and processing TLS reports have not been tested.\")], records);\n  }\n  function parseHeaders(raw) {\n    const header = String(raw).replace(\/^\\uFEFF\/, '').split(\/\\r?\\n\\r?\\n\/)[0];\n    if (header.length > 262144) throw new Error(tr(\"De headers zijn te groot. Gebruik maximaal 256 KB.\", \"The headers are too large. Use a maximum of 256 KB.\"));\n    const fields = []; let malformed = 0;\n    for (const line of header.split(\/\\r?\\n\/)) {\n      if (\/^[ \\t]\/.test(line) && fields.length) fields[fields.length - 1].value += ' ' + line.trim();\n      else { const m = line.match(\/^([!-9;-~]+):[ \\t]*(.*)$\/); if (m) fields.push({ name: m[1].toLowerCase(), value: m[2] }); else if (line.trim()) malformed++; }\n    }\n    if (fields.length > 1000) throw new Error(tr(\"Te veel headers. Gebruik maximaal 1000 headerregels.\", \"Too many headers. Use a maximum of 1,000 header fields.\"));\n    const get = name => fields.filter(f => f.name === name).map(f => f.value);\n    if (!fields.length) throw new Error(tr(\"Geen geldige berichtheaders gevonden. Plak de volledige originele headers.\", \"No valid message headers found. Paste the complete original headers.\"));\n    const auth = fields.filter(f => ['authentication-results', 'arc-authentication-results', 'authentication-results-original'].includes(f.name)).map(f => {\n      const value = f.value, instance = value.match(\/^i=(\\d+)\\s*;\/i)?.[1] || '';\n      return { source: f.name, instance, server: value.replace(\/^i=\\d+\\s*;\\s*\/i, '').split(';')[0], value, outcomes: [...value.matchAll(\/\\b(spf|dkim|dmarc|arc|compauth)\\s*=\\s*(pass|fail|softfail|neutral|none|temperror|permerror|policy)\\b\/gi)].map(m => ({ mechanism: m[1].toUpperCase(), result: m[2].toLowerCase() })) };\n    });\n    const spamReports = fields.filter(f => ['x-forefront-antispam-report', 'x-forefront-antispam-report-untrusted', 'x-microsoft-antispam', 'x-microsoft-antispam-untrusted'].includes(f.name)).map(f => ({ name: f.name, value: f.value, entries: f.value.split(';').map(part => part.match(\/^\\s*([a-z0-9_-]+):([\\s\\S]*)$\/i)).filter(Boolean).map(m => ({ key: m[1].toUpperCase(), value: m[2].trim() })) }));\n    const missing = ['from', 'subject', 'message-id', 'date', 'received'].filter(name => !get(name).length);\n    const signatures = get('dkim-signature').map(value => { const t = tags(value).values; return { domain: t.d || '', selector: t.s || '', algorithm: t.a || '' }; });\n    const route = get('received').slice().reverse().map((value, i, rows) => {\n      const at = value.lastIndexOf(';'), date = at >= 0 ? value.slice(at + 1).trim() : '', timestamp = Date.parse(date);\n      const previous = i ? Date.parse(rows[i - 1].slice(rows[i - 1].lastIndexOf(';') + 1).trim()) : NaN;\n      return { from: value.match(\/\\bfrom\\s+([^;]+?)(?=\\s+by\\s|;|$)\/i)?.[1] || tr(\"Niet vermeld\", \"Not specified\"), by: value.match(\/\\bby\\s+(\\S+)\/i)?.[1] || tr(\"Niet vermeld\", \"Not specified\"), date, timestamp, delay: Number.isFinite(timestamp) && Number.isFinite(previous) ? (timestamp - previous) \/ 1000 : null, value };\n    });\n    return { fields, malformed, from: get('from'), to: get('to'), subject: get('subject'), returnPath: get('return-path'), messageId: get('message-id'), date: get('date'), auth, signatures, route, spamReports, missing, receivedSpf: get('received-spf'), relayScore: get('x-mx-relay-spam-score') };\n  }\n  function element(tag, className, text) { const el = document.createElement(tag); if (className) el.className = className; if (text !== undefined) el.textContent = text; return el; }\n  function card(title, data) {\n    const el = element('article', 'mxt-card'); el.dataset.tone = data.tone;\n    const head = element('div', 'mxt-card-header'); head.append(element('h3', '', title), element('span', 'mxt-badge', labels[data.tone])); el.append(head, element('p', '', data.summary));\n    if (data.notes?.length) { const list = element('ul'); for (const note of data.notes) list.append(element('li', '', note)); el.append(list); }\n    if (data.records?.length) { const details = element('details'); details.append(element('summary', '', tr(\"Bekijk DNS-records\", \"View DNS records\")), element('pre', '', data.records.join('\\n\\n'))); el.append(details); }\n    return el;\n  }\n  const jobs = (domain, selector, dns) => [['MX', () => checkMx(domain, dns)], ['SPF', () => checkSpf(domain, dns)], ['DKIM', () => checkDkim(domain, selector, dns)], ['DMARC', () => checkDmarc(domain, dns)], ['DNSSEC', () => checkDnssec(domain, dns)], ['MTA-STS', () => checkTransport(domain, dns, 'sts')], ['TLS-RPT', () => checkTransport(domain, dns, 'tlsrpt')]];\n  function init(root) {\n    if (root.dataset.mxtReady) return;\n    root.dataset.mxtReady = 'true';\n    const q = role => root.querySelector(`[data-role=\"${role}\"]`), form = q('domain-form'), button = q('domain-submit');\n    let controller, lastReport = '';\n    function tab(name, focus = false) { root.querySelectorAll('[data-tab]').forEach(b => { const selected = b.dataset.tab === name; b.setAttribute('aria-selected', String(selected)); b.tabIndex = selected ? 0 : -1; if (selected && focus) b.focus(); }); root.querySelectorAll('[data-panel]').forEach(p => { p.hidden = p.dataset.panel !== name; }); }\n    root.querySelectorAll('[data-tab]').forEach(b => { b.addEventListener('click', () => tab(b.dataset.tab)); b.addEventListener('keydown', e => { if (['ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(e.key)) { e.preventDefault(); tab(e.key === 'Home' ? 'domain' : e.key === 'End' ? 'headers' : b.dataset.tab === 'domain' ? 'headers' : 'domain', true); } }); });\n    form.addEventListener('submit', async event => {\n      event.preventDefault(); const feedback = q('domain-feedback'); feedback.dataset.error = 'false';\n      let domain; try { domain = normaliseDomain(form.elements.domain.value); } catch (e) { feedback.textContent = e.message; feedback.dataset.error = 'true'; form.elements.domain.focus(); return; }\n      controller?.abort(); controller = new AbortController(); const run = controller; const dns = createResolver(run.signal);\n      button.disabled = true; q('domain-actions').hidden = true; q('domain-results').replaceChildren(); form.elements.domain.value = domain; feedback.textContent = tr(`DNS-records van ${domain} worden gecontroleerd\u2026`, `Checking DNS records for ${domain}\u2026`);\n      const tasks = jobs(domain, form.elements.selector.value, dns), answers = new Array(tasks.length);\n      const slots = tasks.map(([name]) => { const el = card(name, result('loading', tr(\"DNS-records opvragen\u2026\", \"Looking up DNS records\u2026\"))); el.classList.add('mxt-spinner'); q('domain-results').append(el); return el; });\n      await Promise.all(tasks.map(async ([name, job], i) => { let data; try { data = await job(); } catch (e) { data = result('error', e.message); } if (run.signal.aborted) return; answers[i] = { name, ...data }; slots[i].replaceWith(card(name, data)); }));\n      if (run.signal.aborted) return;\n      const stamp = new Date().toLocaleString(locale); feedback.textContent = tr(`Controle afgerond voor ${domain} \u00b7 ${stamp}. Lees ook de toelichting per check.`, `Check completed for ${domain} \u00b7 ${stamp}. Read the notes for each check.`);\n      lastReport = tr(`MX-Relay MXtoolbox\\nDomein: ${domain}\\nGemeten: ${stamp}\\n\\n`, `MX-Relay MXtoolbox\\nDomain: ${domain}\\nChecked: ${stamp}\\n\\n`) + answers.map(a => `${a.name} \u2014 ${labels[a.tone]}\\n${a.summary}\\n${(a.notes || []).join('\\n')}\\n${(a.records || []).join('\\n')}`).join('\\n\\n');\n      button.disabled = false; q('domain-actions').hidden = false;\n    });\n    q('copy-domain').addEventListener('click', async () => { try { await navigator.clipboard.writeText(lastReport); q('copy-domain-status').textContent = tr(\"Rapport gekopieerd.\", \"Report copied.\"); } catch { q('copy-domain-status').textContent = tr(\"Kopi\u00ebren is niet toegestaan in deze browser. Selecteer de resultaten handmatig.\", \"Copying is not permitted in this browser. Select the results manually.\"); } });\n    const textarea = root.querySelector('#mxt-headers');\n    function showHeaders(raw) {\n      const feedback = q('header-feedback'), output = q('header-results'); output.replaceChildren(); feedback.dataset.error = 'false';\n      let h; try { h = parseHeaders(raw); } catch (e) { feedback.textContent = e.message; feedback.dataset.error = 'true'; return; }\n      const grid = element('div', 'mxt-header-grid');\n      for (const [label, values] of [[tr(\"Van\", \"From\"), h.from], [tr(\"Aan\", \"To\"), h.to], ['Return-Path', h.returnPath], [tr(\"Onderwerp (ruwe header)\", \"Subject (raw header)\"), h.subject], [tr(\"Bericht-ID\", \"Message-ID\"), h.messageId], [tr(\"Berichtdatum\", \"Message date\"), h.date]]) { const box = element('div', 'mxt-card'); box.append(element('span', 'mxt-meta', label), element('strong', '', values.join(' \u00b7 ') || tr(\"Niet vermeld\", \"Not specified\"))); grid.append(box); }\n      if (h.missing.length) output.append(element('p', 'mxt-notice', tr(`Onvolledige headers: ${h.missing.join(', ')} ontbreken. Ontbrekende gegevens en de mailroute kunnen niet betrouwbaar worden gereconstrueerd. Kopieer de volledige originele berichtbron of upload het originele .eml-bestand.`, `Incomplete headers: ${h.missing.join(', ')} are missing. Missing details and the mail route cannot be reliably reconstructed. Copy the complete original message source or upload the original .eml file.`)));\n      output.append(grid, element('p', 'mxt-notice', tr(\"Authenticatieresultaten hieronder zijn claims uit de headers. Controleer welke ontvangende server je vertrouwt. De toolbox verifieert geen SPF, DKIM-handtekening of DMARC-uitlijning van dit bericht.\", \"The authentication results below are claims in the headers. Check which receiving server you trust. This toolbox does not independently verify SPF, the DKIM signature or DMARC alignment of this message.\")));\n      if (h.from.length > 1 || h.malformed) output.append(element('p', 'mxt-notice', `${h.from.length > 1 ? tr(\"Meerdere From-headers gevonden. \", \"Multiple From headers found. \") : ''}${h.malformed ? tr(`${h.malformed} regel(s) konden niet als header worden gelezen.`, `${h.malformed} line(s) could not be read as a header.`) : ''}`));\n      output.append(element('h3', 'mxt-heading', tr(\"Gemelde authenticatie\", \"Reported authentication\")));\n      if (!h.auth.length) output.append(element('p', '', tr(\"Geen Authentication-Results of ARC-Authentication-Results gevonden. Daaruit volgt niet dat het bericht geslaagd of mislukt is.\", \"No Authentication-Results or ARC-Authentication-Results found. This does not establish whether the message passed or failed.\")));\n      for (const a of h.auth) { const box = element('article', 'mxt-card'); box.append(element('h3', '', `${a.server} \u00b7 ${a.source}${a.instance ? ` \u00b7 ARC i=${a.instance}` : ''}`), element('p', '', a.outcomes.length ? a.outcomes.map(o => tr(`${o.mechanism}: gemeld ${o.result}`, `${o.mechanism}: reported ${o.result}`)).join(' \u00b7 ') : tr(\"Geen herkenbare SPF-, DKIM- of DMARC-uitkomst.\", \"No recognizable SPF, DKIM or DMARC result.\"))); const d = element('details'); d.append(element('summary', '', tr(\"Bekijk oorspronkelijke header\", \"View original header\")), element('pre', '', a.value)); box.append(d); output.append(box); }\n      if (h.spamReports.length || h.receivedSpf.length || h.relayScore.length) {\n        output.append(element('h3', 'mxt-heading', tr('Spam- en filterdiagnose', 'Spam and filter diagnostics')));\n        const descriptions = {\n          CIP: tr('Verbindend IP-adres', 'Connecting IP address'), CTRY: tr('Land\/regio', 'Country\/region'), LANG: tr('Taal', 'Language'), SCL: tr('Spam Confidence Level', 'Spam Confidence Level'), BCL: tr('Bulk Complaint Level', 'Bulk Complaint Level'), SFV: tr('Spamfilteroordeel', 'Spam filtering verdict'), IPV: tr('IP-filteroordeel', 'IP filter verdict'), H: 'HELO\/EHLO', PTR: tr('PTR volgens ontvangende server', 'PTR reported by receiving server'), CAT: tr('Filtercategorie', 'Filter category'), SFS: tr('Spamregelcodes', 'Spam rule codes'), ARA: tr('Filterregelcodes', 'Filter rule codes'), DIR: tr('Richting', 'Direction'), SRV: tr('Serverveld', 'Server field')\n        };\n        for (const report of h.spamReports) {\n          const box = element('article', 'mxt-card'); box.append(element('h3', '', report.name));\n          for (const item of report.entries) box.append(element('p', '', `${descriptions[item.key] || item.key} (${item.key}): ${item.value || '\u2014'}${item.key === 'SFV' && item.value === 'NSPM' ? tr(' \u00b7 gemeld als geen spam', ' \u00b7 reported as non-spam') : ''}`));\n          const details = element('details'); details.append(element('summary', '', tr('Bekijk oorspronkelijke header', 'View original header')), element('pre', '', report.value)); box.append(details); output.append(box);\n        }\n        for (const value of h.receivedSpf) output.append(card('Received-SPF', result(\/^(fail|softfail|permerror|temperror)\\b\/i.test(value) ? 'warn' : 'info', value)));\n        for (const value of h.relayScore) output.append(card('MX-Relay spam score', result('info', value)));\n        output.append(element('p', 'mxt-meta', tr('Dit zijn filterclaims uit het bericht, geen nieuwe IP-reputatie-, PTR- of SPF-controle. SPF kan na doorsturen falen terwijl DKIM en DMARC slagen. De oorspronkelijke From en Received-headers ontbreken mogelijk; trek daaruit geen definitieve afleverconclusie.', 'These are filter claims from the message, not fresh IP reputation, PTR or SPF checks. SPF can fail after forwarding while DKIM and DMARC pass. Original From and Received headers may be missing; this does not establish a final delivery diagnosis.')));\n      }\n      if (h.signatures.length) {\n        output.append(element('h3', 'mxt-heading', tr(\"DKIM in dit bericht\", \"DKIM in this message\")));\n        for (const sig of h.signatures) {\n          const box = element('article', 'mxt-card'); box.append(element('p', '', tr(`Ondertekenend domein: ${sig.domain || 'ontbreekt'} \u00b7 selector: ${sig.selector || 'ontbreekt'} \u00b7 algoritme: ${sig.algorithm || 'ontbreekt'}`, `Signing domain: ${sig.domain || 'missing'} \u00b7 selector: ${sig.selector || 'missing'} \u00b7 algorithm: ${sig.algorithm || 'missing'}`)));\n          if (domainPattern.test(sig.domain) && \/^[a-z0-9_-]+(?:\\.[a-z0-9_-]+)*$\/i.test(sig.selector)) { const b = element('button', 'mxt-secondary mxt-dkim-action', tr(\"Controleer deze DKIM-sleutel\", \"Check this DKIM key\")); b.type = 'button'; b.addEventListener('click', () => { form.elements.domain.value = sig.domain; form.elements.selector.value = sig.selector; tab('domain'); form.requestSubmit(); }); box.append(b); }\n          output.append(box);\n        }\n      }\n      output.append(element('h3', 'mxt-heading', tr(`Mailroute \u00b7 ${h.route.length} Received-header${h.route.length === 1 ? '' : 's'}`, `Mail route \u00b7 ${h.route.length} Received header${h.route.length === 1 ? '' : 's'}`)));\n      if (!h.route.length) output.append(element('p', '', tr(\"Geen Received-headers gevonden.\", \"No Received headers found.\")));\n      else {\n        const wrap = element('div', 'mxt-table-wrap'), table = element('table'), head = element('thead'), row = element('tr');\n        for (const title of [tr(\"Stap\", \"Hop\"), tr(\"Van\", \"From\"), tr(\"Via\", \"Via\"), tr(\"Tijd uit header\", \"Time in header\"), tr(\"Verschil\", \"Difference\")]) row.append(element('th', '', title)); head.append(row); table.append(head);\n        const body = element('tbody'); h.route.forEach((hop, i) => { const tableRow = element('tr'); for (const value of [String(i + 1), hop.from, hop.by, hop.date || tr(\"Niet vermeld\", \"Not specified\"), hop.delay === null ? '\u2014' : 0 > hop.delay ? tr(`${hop.delay} s \u00b7 klokverschil`, `${hop.delay} s \u00b7 clock difference`) : `${hop.delay} s`]) tableRow.append(element('td', '', value)); body.append(tableRow); }); table.append(body); wrap.append(table); output.append(wrap, element('p', 'mxt-meta', tr(\"Volgorde: oudste naar nieuwste Received-header. Tijdverschillen hangen af van serverklokken en kunnen ook door vervalste of ontbrekende headers afwijken.\", \"Order: oldest to newest Received header. Time differences depend on server clocks and can also be affected by forged or missing headers.\")));\n      }\n      feedback.textContent = tr(`${h.fields.length} headers lokaal gelezen. Er zijn geen headers verstuurd.`, `${h.fields.length} header fields read locally. No headers were transmitted.`);\n    }\n    q('header-form').addEventListener('submit', e => { e.preventDefault(); showHeaders(textarea.value); });\n    q('clear-headers').addEventListener('click', () => { textarea.value = ''; q('header-results').replaceChildren(); q('header-feedback').textContent = ''; q('header-file').value = ''; textarea.focus(); });\n    q('header-file').addEventListener('change', async e => { const file = e.target.files[0]; if (!file) return; if (file.size > 1048576) { q('header-feedback').textContent = tr(\"Gebruik een bestand van maximaal 1 MB, of plak alleen de headers.\", \"Use a file of up to 1 MB, or paste only the headers.\"); q('header-feedback').dataset.error = 'true'; e.target.value = ''; return; } try { const text = (await file.text()).split(\/\\r?\\n\\r?\\n\/)[0]; textarea.value = text; showHeaders(text); } catch { q('header-feedback').textContent = tr(\"Dit bestand kon niet worden gelezen.\", \"This file could not be read.\"); } });\n    q('example-headers').addEventListener('click', () => { textarea.value = (english ? 'Received: from relay.example.net by inbox.example.org; Wed, 11 Nov 2026 10:00:03 +0100\\nReceived: from sender.example.com by relay.example.net; Wed, 11 Nov 2026 10:00:00 +0100\\nAuthentication-Results: inbox.example.org; spf=pass smtp.mailfrom=example.com; dkim=pass header.d=example.com; dmarc=pass header.from=example.com\\nDKIM-Signature: v=1; a=rsa-sha256; d=example.com; s=example; b=EXAMPLE\\nFrom: Example \\x3csender@example.com>\\nTo: Recipient \\x3crecipient@example.org>\\nSubject: Example headers \u2014 not a real email\\nMessage-ID: \\x3cexample@example.com>\\nDate: Wed, 11 Nov 2026 10:00:00 +0100' : 'Received: from relay.example.net by inbox.example.org; Wed, 11 Nov 2026 10:00:03 +0100\\nReceived: from sender.example.com by relay.example.net; Wed, 11 Nov 2026 10:00:00 +0100\\nAuthentication-Results: inbox.example.org; spf=pass smtp.mailfrom=example.com; dkim=pass header.d=example.com; dmarc=pass header.from=example.com\\nDKIM-Signature: v=1; a=rsa-sha256; d=example.com; s=voorbeeld; b=VOORBEELD\\nFrom: Voorbeeld \\x3cafzender@example.com>\\nTo: Ontvanger \\x3contvanger@example.org>\\nSubject: Voorbeeldheaders \u2014 geen echte e-mail\\nMessage-ID: \\x3cvoorbeeld@example.com>\\nDate: Wed, 11 Nov 2026 10:00:00 +0100'); showHeaders(textarea.value); });\n  }\n  window.MXRelayToolbox = { locale, normaliseDomain, txt, tags, createResolver, checkMx, checkSpf, checkDkim, checkDmarc, checkDnssec, checkTransport, parseHeaders, init };\n  const englishTemplate = document.querySelector('template[data-mxt-english]');\n  if (english && englishTemplate) document.querySelector('[data-mxtoolbox]')?.replaceWith(englishTemplate.content.cloneNode(true));\n  englishTemplate?.remove();\n  document.querySelectorAll('[data-mxtoolbox]').forEach(init);\n})();\n\n<\/script>\n","protected":false},"excerpt":{"rendered":"<p>Controleer MX, SPF, DKIM, DMARC en aanvullende DNS-beveiliging. Analyseer e-mailheaders lokaal in je browser.<\/p>","protected":false},"author":21,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-17467","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/www.mx-relay.com\/en\/wp-json\/wp\/v2\/pages\/17467","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.mx-relay.com\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.mx-relay.com\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.mx-relay.com\/en\/wp-json\/wp\/v2\/users\/21"}],"replies":[{"embeddable":true,"href":"https:\/\/www.mx-relay.com\/en\/wp-json\/wp\/v2\/comments?post=17467"}],"version-history":[{"count":6,"href":"https:\/\/www.mx-relay.com\/en\/wp-json\/wp\/v2\/pages\/17467\/revisions"}],"predecessor-version":[{"id":17475,"href":"https:\/\/www.mx-relay.com\/en\/wp-json\/wp\/v2\/pages\/17467\/revisions\/17475"}],"wp:attachment":[{"href":"https:\/\/www.mx-relay.com\/en\/wp-json\/wp\/v2\/media?parent=17467"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}