{"id":13343,"date":"2026-08-31T14:47:01","date_gmt":"2026-08-31T12:47:01","guid":{"rendered":"https:\/\/www.lukaswojcik.com\/blog\/toolbox\/email-authentication-spf-dkim-dmarc-checker\/"},"modified":"2026-08-31T14:49:50","modified_gmt":"2026-08-31T12:49:50","slug":"email-authentication-spf-dkim-dmarc-checker","status":"publish","type":"page","link":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/email-authentication-spf-dkim-dmarc-checker\/","title":{"rendered":"Email Authentication Checker: SPF, DKIM, DMARC, MX and CAA"},"content":{"rendered":"<div class=\"gtm-analyser-container\" style=\"background: var(--bg-panel, #1e1e24); padding: 25px; border-radius: 8px; border: 1px solid var(--border, #2a2a35);\">\n<p style=\"color: var(--text-secondary, #a0a0b0); margin-bottom: 20px;\">Three records decide whether someone can send mail in a domain&#039;s name. SPF and DKIM say who is allowed to; only DMARC tells the receiving server what to do when neither matches. A domain can carry all three and still reject nothing &#8211; that is the ordinary case, not the exception. This reads the records and names which of them are doing work.<\/p>\n<div style=\"display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 12px; margin-bottom: 14px;\">\n<div>\n            <label for=\"ma-domain\" style=\"color: var(--text-secondary, #a0a0b0); display: block; font-size: 0.85rem; margin-bottom: 5px;\">Domain<\/label><br \/>\n            <input id=\"ma-domain\" type=\"text\" value=\"example.com\" class=\"form-control\" style=\"width: 100%; padding: 10px; background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); color: var(--text-primary, #e8e8ee); border-radius: 6px; box-sizing: border-box; font-family: monospace;\">\n        <\/div>\n<div>\n            <label for=\"ma-selektoren\" style=\"color: var(--text-secondary, #a0a0b0); display: block; font-size: 0.85rem; margin-bottom: 5px;\">Extra DKIM selectors, optional<\/label><br \/>\n            <input id=\"ma-selektoren\" type=\"text\" value=\"\" placeholder=\"s1 s2\" class=\"form-control\" style=\"width: 100%; padding: 10px; background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); color: var(--text-primary, #e8e8ee); border-radius: 6px; box-sizing: border-box; font-family: monospace;\">\n        <\/div>\n<\/p><\/div>\n<p style=\"color: var(--text-secondary, #a0a0b0); font-size: 0.82rem; margin-bottom: 16px;\">Only DNS is queried; nothing is fetched from the entered domain, and no message is sent. The query is protected by reCAPTCHA v3, and the calling IP address together with the domain is stored for one hour to limit the rate &#8211; twenty queries per address per hour. Nothing else is kept.<\/p>\n<p>    <button id=\"ma-btn\" class=\"button\" style=\"background: var(--accent, #7ee787); color: var(--on-accent, #0b1114); border: none; padding: 12px 24px; border-radius: 6px; font-weight: 700; cursor: pointer;\">Check the domain<\/button><\/p>\n<div id=\"ma-ausgabe\" style=\"margin-top: 22px;\"><\/div>\n<\/div>\n<p><script>\n(function () {\n    'use strict';<\/p>\n<p>    const T = {\"einleitung\":\"Three records decide whether someone can send mail in a domain\\u0027s name. SPF and DKIM say who is allowed to; only DMARC tells the receiving server what to do when neither matches. A domain can carry all three and still reject nothing - that is the ordinary case, not the exception. This reads the records and names which of them are doing work.\",\"label_domain\":\"Domain\",\"label_selektoren\":\"Extra DKIM selectors, optional\",\"datenschutz\":\"Only DNS is queried; nothing is fetched from the entered domain, and no message is sent. The query is protected by reCAPTCHA v3, and the calling IP address together with the domain is stored for one hour to limit the rate - twenty queries per address per hour. Nothing else is kept.\",\"knopf\":\"Check the domain\",\"laeuft\":\"Reading the DNS records...\",\"fehler_kein_token\":\"The check could not be started because reCAPTCHA did not load. A blocker or a strict privacy setting usually causes this.\",\"fehler_captcha\":\"reCAPTCHA classified the request as automated. Reloading the page normally helps.\",\"fehler_zu_viele\":\"The limit of {limit} queries per hour for this address has been reached. It resets on its own.\",\"fehler_domain\":\"That is not a usable domain name.\",\"fehler_zaehler\":\"The rate counter is unavailable, so the query was not run. Nothing is served without it.\",\"fehler_pruefdienst\":\"The reCAPTCHA service could not be reached.\",\"fehler_aufbau\":\"The service is not configured correctly. The fault is on this side.\",\"fehler_eingabe\":\"The request could not be read.\",\"fehler_methode\":\"Wrong request method.\",\"fehler_netz\":\"The service could not be reached.\",\"fehler_antwort\":\"The answer could not be read.\",\"fehler_unbekannt\":\"Something went wrong that has no message of its own.\",\"grund_leer\":\"Nothing was entered.\",\"grund_zu_lang\":\"The name is longer than a domain name may be.\",\"grund_ip_adresse\":\"That is an IP address, not a domain.\",\"grund_kein_punkt\":\"A domain name needs at least one dot.\",\"grund_form\":\"Allowed are letters, digits and hyphens, separated by dots.\",\"h_uebersicht\":\"Overview\",\"zeile_domain\":\"Domain\",\"ampel_gut\":\"in force\",\"ampel_teilweise\":\"present, without force\",\"ampel_fehlt\":\"missing\",\"urteil_geschlossen\":\"All three records are set and in force.\",\"urteil_halb\":\"The records exist, but at least one of them enforces nothing.\",\"urteil_offen\":\"A message in this domain\\u0027s name passes without being stopped.\",\"h_spf\":\"SPF: who may send\",\"spf_keiner\":\"No SPF record. Every server may claim to send for this domain, and the receiver has no list to check against.\",\"zeile_all\":\"Closing rule\",\"zeile_lookups\":\"DNS lookups used\",\"zeile_kette\":\"Chain\",\"all_-\":\"-all, hard fail\",\"all_~\":\"~all, soft fail\",\"all_?\":\"?all, neutral\",\"all_+\":\"+all, everything passes\",\"h_dkim\":\"DKIM: the signature\",\"dkim_keiner\":\"No key found under the known selectors. That does not prove there is none - a selector cannot be enumerated, only guessed. If the sending service names one, it goes in the field above.\",\"spalte_selektor\":\"Selector\",\"spalte_typ\":\"Type\",\"spalte_bits\":\"Bits\",\"dkim_widerrufen\":\"revoked\",\"h_dmarc\":\"DMARC: what the receiver should do\",\"dmarc_keiner\":\"No DMARC record. SPF and DKIM then say who is allowed to send, and nobody says what happens when neither matches.\",\"zeile_politik\":\"Policy\",\"zeile_pct\":\"Applies to\",\"zeile_rua\":\"Reports to\",\"zeile_ausrichtung\":\"Alignment\",\"p_none\":\"none - watch only\",\"p_quarantine\":\"quarantine - into the spam folder\",\"p_reject\":\"reject - refused\",\"h_umfeld\":\"Around it\",\"zeile_mx\":\"MX\",\"zeile_caa\":\"CAA\",\"zeile_bimi\":\"BIMI\",\"zeile_dauer\":\"Query took\",\"wert_keiner\":\"none\",\"h_befunde\":\"Findings\",\"befund_mx_fehlt\":\"No MX record. The domain receives no mail, which is fine for a send-only domain and a fault everywhere else.\",\"befund_mx_einzeln\":\"Only one MX host. If it is unreachable, the sender queues and eventually gives up; a second host with a higher preference costs nothing in normal operation.\",\"befund_spf_fehlt\":\"No SPF record at all.\",\"befund_spf_mehrfach\":\"More than one SPF record. That is a permanent error by specification - receivers do not pick one, they stop checking.\",\"befund_spf_lookups_ueber\":\"More than {limit} DNS lookups. The specification allows exactly that many; above it the check ends in permerror, and everything the record would have permitted is worth nothing. Usually one include chain too many.\",\"befund_spf_lookups_knapp\":\"Close to the limit of {limit} lookups. One more provider added to the record and it tips over - and the record still looks correct while it does.\",\"befund_spf_schleife\":\"An include chain refers back to itself.\",\"befund_spf_ohne_all\":\"No closing rule. Without one the record ends in neutral, which stops nothing.\",\"befund_spf_plus_all\":\"+all lets every server pass. That is the same as having no record, only harder to notice.\",\"befund_spf_neutral\":\"?all is neutral: the record names senders and then declares everything acceptable anyway.\",\"befund_spf_softfail\":\"~all is a soft fail. Receivers accept the message and mark it. Only -all asks for a refusal - and only DMARC makes it binding.\",\"befund_spf_ptr\":\"The record uses ptr. That mechanism is deprecated; several large receivers ignore it entirely.\",\"befund_dmarc_fehlt\":\"No DMARC record. Nothing tells a receiver what to do with a message that fails SPF and DKIM.\",\"befund_dmarc_mehrfach\":\"More than one DMARC record. As with SPF, that is an error rather than a choice.\",\"befund_dmarc_none\":\"p=none means reports only. Nothing is quarantined, nothing is refused. This is the intended starting position - and the position most domains never leave.\",\"befund_dmarc_quarantine\":\"p=quarantine sends failing messages to the spam folder rather than refusing them.\",\"befund_dmarc_reject\":\"p=reject refuses failing messages. That is the enforcing setting.\",\"befund_dmarc_ohne_rua\":\"No rua address. Without reports there is no way to see who sends in this name, and no way to tell whether tightening the policy would break something.\",\"befund_dmarc_pct\":\"The policy applies to only part of the mail. The remainder is treated as p=none.\",\"befund_dmarc_fehlerhaft\":\"The DMARC record has a formal error. Receivers that read it strictly ignore the whole record.\",\"befund_dkim_widerrufen\":\"A key with an empty p= is revoked. It stays in the zone as a marker; signatures made with it no longer verify.\",\"befund_dkim_zu_kurz\":\"An RSA key below 1024 bits. Several receivers treat such a signature as absent.\",\"befund_dkim_1024\":\"An RSA key with 1024 bits. Still accepted, but below what is recommended today; 2048 is the usual size.\",\"befund_dkim_keiner_gefunden\":\"No key found under the known selectors. Selectors cannot be enumerated, so this is not proof that none exists.\",\"befund_caa_fehlt\":\"No CAA record. Any certificate authority may issue for this domain. Not an email matter, but the same zone.\",\"befund_bimi_ohne_durchsetzung\":\"A BIMI record exists, but DMARC is not enforcing. BIMI requires quarantine or reject, so the logo will not be shown.\"};<\/p>\n<p>    var ENDPUNKT = '\/lw-mailauth.php';\n    var SITEKEY = '6LcrPkEtAAAAAPo1QCOf-IIM2fCL0UfdJz4y2iSY';\n    var SPF_LIMIT = 10;<\/p>\n<p>    \/\/ =========================================================================\n    \/\/ Bewertung - reine Funktion ueber der Antwort des Endpunkts\n    \/\/ =========================================================================\n    \/\/\n    \/\/ Der Abruf steckt bewusst daneben und nicht hier drin: nur so laesst sich\n    \/\/ die Darstellung gegen erfundene Antworten pruefen, ohne dass ein Lauf\n    \/\/ vom Netz und vom Zustand fremder Zonen abhaengt.<\/p>\n<p>    function zahlOderNull(w) {\n        return (typeof w === 'number' && isFinite(w)) ? w : null;\n    }<\/p>\n<p>    function bewerten(antwort) {\n        var a = antwort || {};\n        if (a.fehler) {\n            return { fehler: a.fehler, grund: a.grund || null, limit: zahlOderNull(a.limit) };\n        }<\/p>\n<p>        var spf = a.spf || {};\n        var dmarc = (a.dmarc && a.dmarc.zerlegt) ? a.dmarc.zerlegt : { gefunden: false, kennwerte: {} };\n        var dkim = Array.isArray(a.dkim) ? a.dkim : [];\n        var befunde = Array.isArray(a.befunde) ? a.befunde : [];<\/p>\n<p>        var lookups = zahlOderNull(spf.lookups);\n        var p = (dmarc.kennwerte && dmarc.kennwerte.p) ? String(dmarc.kennwerte.p).toLowerCase() : null;<\/p>\n<p>        \/\/ Eine Ampel je Baustein. \"teilweise\" heisst: vorhanden, aber ohne\n        \/\/ Wirkung - der haeufigste Zustand und der, der am meisten taeuscht.\n        function ampelSpf() {\n            if (!spf.satz) { return 'fehlt'; }\n            if (lookups !== null && lookups > SPF_LIMIT) { return 'fehlt'; }\n            if (spf.all === '-') { return 'gut'; }\n            if (spf.all === '~' || spf.all === '?') { return 'teilweise'; }\n            if (spf.all === '+') { return 'fehlt'; }\n            return 'teilweise';\n        }\n        function ampelDmarc() {\n            if (!dmarc.gefunden) { return 'fehlt'; }\n            if (p === 'reject') { return 'gut'; }\n            if (p === 'quarantine') { return 'teilweise'; }\n            return 'teilweise';\n        }\n        function ampelDkim() {\n            if (!dkim.length) { return 'fehlt'; }\n            var schwach = dkim.filter(function (k) {\n                return k.widerrufen || (k.typ === 'rsa' && zahlOderNull(k.bits) !== null && k.bits < 2048);\n            });\n            return schwach.length === dkim.length ? 'teilweise' : 'gut';\n        }\n\n        var ampeln = { spf: ampelSpf(), dkim: ampelDkim(), dmarc: ampelDmarc() };\n        var gut = 0;\n        ['spf', 'dkim', 'dmarc'].forEach(function (k) { if (ampeln[k] === 'gut') { gut++; } });\n\n        var urteil;\n        if (ampeln.dmarc === 'fehlt' || ampeln.spf === 'fehlt') { urteil = 'offen'; }\n        else if (gut === 3) { urteil = 'geschlossen'; }\n        else { urteil = 'halb'; }\n\n        return {\n            fehler: null,\n            domain: a.domain || '',\n            ampeln: ampeln,\n            urteil: urteil,\n            spf: {\n                satz: spf.satz || null,\n                all: spf.all || null,\n                lookups: lookups,\n                limit: SPF_LIMIT,\n                kette: Array.isArray(spf.kette) ? spf.kette : [],\n                mehrfach: !!spf.mehrfach\n            },\n            dmarc: {\n                satz: (a.dmarc &#038;&#038; a.dmarc.satz) ? a.dmarc.satz : null,\n                p: p,\n                sp: (dmarc.kennwerte &#038;&#038; dmarc.kennwerte.sp) ? dmarc.kennwerte.sp : null,\n                pct: (dmarc.kennwerte &#038;&#038; dmarc.kennwerte.pct) ? dmarc.kennwerte.pct : '100',\n                rua: (dmarc.kennwerte &#038;&#038; dmarc.kennwerte.rua) ? dmarc.kennwerte.rua : null,\n                adkim: (dmarc.kennwerte &#038;&#038; dmarc.kennwerte.adkim) ? dmarc.kennwerte.adkim : 'r',\n                aspf: (dmarc.kennwerte &#038;&#038; dmarc.kennwerte.aspf) ? dmarc.kennwerte.aspf : 'r'\n            },\n            dkim: dkim,\n            mx: Array.isArray(a.mx) ? a.mx : [],\n            caa: Array.isArray(a.caa) ? a.caa : [],\n            bimi: a.bimi || null,\n            dauer: zahlOderNull(a.dauer_ms),\n            rest: zahlOderNull(a.limit_rest),\n            befunde: befunde\n        };\n    }\n\n    \/\/ =========================================================================\n    \/\/ Abruf - der einzige Teil, der ans Netz geht\n    \/\/ =========================================================================\n\n    \/** Laedt api.js. Sagt nur, ob das Skript da ist - nicht, ob es bereit ist. *\/\n    function skriptLaden() {\n        return new Promise(function (aufloesen) {\n            if (window.grecaptcha) { aufloesen(true); return; }\n            var s = document.createElement('script');\n            s.src = 'https:\/\/www.google.com\/recaptcha\/api.js?render=' + SITEKEY;\n            s.onload = function () { aufloesen(true); };\n            s.onerror = function () { aufloesen(false); };\n            document.head.appendChild(s);\n            setTimeout(function () { aufloesen(!!window.grecaptcha); }, 8000);\n        });\n    }\n\n    \/**\n     * Holt ein Token.\n     *\n     * Auf grecaptcha.ready() zu warten ist nicht optional: onload des Skripts\n     * feuert, bevor grecaptcha.execute ueberhaupt definiert ist. Wer direkt\n     * nach onload auf execute prueft, findet nichts und gibt null zurueck,\n     * obwohl reCAPTCHA einwandfrei laeuft.\n     *\/\n    function tokenHolen() {\n        return skriptLaden().then(function (da) {\n            if (!da || !window.grecaptcha || !window.grecaptcha.ready) { return null; }\n            return new Promise(function (aufloesen) {\n                var fertig = false;\n                function einmal(wert) {\n                    if (fertig) { return; }\n                    fertig = true;\n                    aufloesen(wert);\n                }\n                setTimeout(function () { einmal(null); }, 12000);\n                try {\n                    window.grecaptcha.ready(function () {\n                        if (fertig) { return; }\n                        if (!window.grecaptcha.execute) { einmal(null); return; }\n                        window.grecaptcha.execute(SITEKEY, { action: 'mailauth' })\n                            .then(function (t) { einmal(t || null); }, function () { einmal(null); });\n                    });\n                } catch (e) { einmal(null); }\n            });\n        }, function () { return null; });\n    }\n\n    function abfragen(domain, selektoren) {\n        return tokenHolen().then(function (token) {\n            return fetch(ENDPUNKT, {\n                method: 'POST',\n                headers: { 'Content-Type': 'application\/json' },\n                body: JSON.stringify({ domain: domain, selektoren: selektoren, token: token || '' })\n            }).then(function (r) {\n                return r.json().then(function (j) { return j; }, function () { return { fehler: 'antwort' }; });\n            }, function () { return { fehler: 'netz' }; });\n        });\n    }\n\n    \/\/ --- Pruefpunkt ----------------------------------------------------------\n    window.LW_TEST = window.LW_TEST || {};\n    window.LW_TEST.MA = {\n        bewerten: bewerten,\n        darstellen: null,      \/\/ wird unten gesetzt\n        SPF_LIMIT: SPF_LIMIT,\n        ENDPUNKT: ENDPUNKT,\n        T: T\n    };\n\n    \/\/ =========================================================================\n    \/\/ Oberflaeche\n    \/\/ =========================================================================\n\n    var btn = document.getElementById('ma-btn');\n    var out = document.getElementById('ma-ausgabe');\n    if (!btn || !out) { return; }\n\n    function el(tag, stil, text) {\n        var e = document.createElement(tag);\n        if (stil) { e.setAttribute('style', stil); }\n        if (text !== undefined) { e.textContent = text; }\n        return e;\n    }\n    function wert(id) { var e = document.getElementById(id); return e ? e.value : ''; }\n\n    var UEBERSCHRIFT = 'font-family: \"Nunito Sans\", sans-serif; font-weight: 700; color: var(--text-primary, #e8e8ee); font-size: 0.92rem; margin: 18px 0 8px;';\n    var ZELLE = 'padding: 5px 12px 5px 0; color: var(--text-secondary, #a0a0b0); font-size: 0.87rem;';\n    var ZELLE_WERT = 'padding: 5px 12px 5px 0; color: var(--text-primary, #e8e8ee); font-size: 0.87rem; font-family: monospace; word-break: break-all;';\n    var VORFORM = 'background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); border-radius: 6px; padding: 10px; color: var(--text-primary, #e8e8ee); font-family: monospace; font-size: 0.78rem; white-space: pre-wrap; word-break: break-all; margin: 0;';\n    var GUT = ' color: #7ee787;';\n    var WARN = ' color: #ffa94d;';\n    var GRAU = ' color: #8a8a99;';\n\n    function farbe(ampel) {\n        if (ampel === 'gut') { return GUT; }\n        if (ampel === 'teilweise') { return WARN; }\n        return WARN;\n    }\n    function gitter(spalten) {\n        return el('div', 'display: grid; grid-template-columns: ' + spalten + '; gap: 0 18px; align-items: baseline;');\n    }\n    function paar(g, name, w, stil) {\n        g.appendChild(el('div', ZELLE, name));\n        g.appendChild(el('div', ZELLE_WERT + (stil || ''), w));\n    }\n    function kopf(g, spalten) {\n        spalten.forEach(function (s) {\n            g.appendChild(el('div', ZELLE + ' font-weight: 700; color: var(--text-primary, #e8e8ee);', s));\n        });\n    }\n\n    \/** Zeichnet einen bewerteten Befund. Bekommt nur Daten, ruft nichts ab. *\/\n    function darstellen(b, ziel) {\n        ziel.innerHTML = '';\n        if (b.fehler) {\n            var text = T['fehler_' + b.fehler] || T.fehler_unbekannt;\n            if (b.fehler === 'domain' &#038;&#038; b.grund &#038;&#038; T['grund_' + b.grund]) {\n                text = text + ' ' + T['grund_' + b.grund];\n            }\n            if (b.fehler === 'zu_viele' &#038;&#038; b.limit !== null) {\n                text = text.replace('{limit}', String(b.limit));\n            }\n            ziel.appendChild(el('p', ZELLE + WARN + ' margin: 0;', text));\n            return;\n        }\n\n        \/\/ --- Ampeln ---\n        ziel.appendChild(el('div', UEBERSCHRIFT, T.h_uebersicht));\n        var g = gitter('auto auto');\n        paar(g, T.zeile_domain, b.domain);\n        paar(g, 'SPF', T['ampel_' + b.ampeln.spf], farbe(b.ampeln.spf));\n        paar(g, 'DKIM', T['ampel_' + b.ampeln.dkim], farbe(b.ampeln.dkim));\n        paar(g, 'DMARC', T['ampel_' + b.ampeln.dmarc], farbe(b.ampeln.dmarc));\n        ziel.appendChild(g);\n        ziel.appendChild(el('div', 'margin: 10px 0 0; font-size: 0.9rem; font-weight: 700;'\n            + (b.urteil === 'geschlossen' ? GUT : WARN), T['urteil_' + b.urteil]));\n\n        \/\/ --- SPF ---\n        ziel.appendChild(el('div', UEBERSCHRIFT, T.h_spf));\n        if (!b.spf.satz) {\n            ziel.appendChild(el('p', ZELLE + WARN + ' margin: 0;', T.spf_keiner));\n        } else {\n            ziel.appendChild(el('pre', VORFORM, b.spf.satz));\n            var gs = gitter('auto auto');\n            paar(gs, T.zeile_all, b.spf.all ? (T['all_' + b.spf.all] || b.spf.all) : T.wert_keiner,\n                b.spf.all === '-' ? GUT : WARN);\n            paar(gs, T.zeile_lookups,\n                (b.spf.lookups === null ? '-' : b.spf.lookups) + ' \/ ' + b.spf.limit,\n                (b.spf.lookups !== null &#038;&#038; b.spf.lookups > b.spf.limit) ? WARN\n                    : ((b.spf.lookups !== null && b.spf.lookups >= 9) ? WARN : GUT));\n            if (b.spf.kette.length) { paar(gs, T.zeile_kette, b.spf.kette.join(' \u2192 '), GRAU); }\n            ziel.appendChild(gs);\n        }<\/p>\n<p>        \/\/ --- DKIM ---\n        ziel.appendChild(el('div', UEBERSCHRIFT, T.h_dkim));\n        if (!b.dkim.length) {\n            ziel.appendChild(el('p', ZELLE + ' margin: 0;', T.dkim_keiner));\n        } else {\n            var gd = gitter('auto auto auto');\n            kopf(gd, [T.spalte_selektor, T.spalte_typ, T.spalte_bits]);\n            b.dkim.forEach(function (k) {\n                gd.appendChild(el('div', ZELLE_WERT, k.selektor));\n                gd.appendChild(el('div', ZELLE_WERT, k.typ || '-'));\n                var schwach = k.widerrufen || (k.typ === 'rsa' && typeof k.bits === 'number' && k.bits < 2048);\n                gd.appendChild(el('div', ZELLE_WERT + (schwach ? WARN : GUT),\n                    k.widerrufen ? T.dkim_widerrufen : (k.bits ? String(k.bits) : '-')));\n            });\n            ziel.appendChild(gd);\n        }\n\n        \/\/ --- DMARC ---\n        ziel.appendChild(el('div', UEBERSCHRIFT, T.h_dmarc));\n        if (!b.dmarc.satz) {\n            ziel.appendChild(el('p', ZELLE + WARN + ' margin: 0;', T.dmarc_keiner));\n        } else {\n            ziel.appendChild(el('pre', VORFORM, b.dmarc.satz));\n            var gm = gitter('auto auto');\n            paar(gm, T.zeile_politik, b.dmarc.p ? (T['p_' + b.dmarc.p] || b.dmarc.p) : T.wert_keiner,\n                b.dmarc.p === 'reject' ? GUT : WARN);\n            paar(gm, T.zeile_pct, b.dmarc.pct + ' %', b.dmarc.pct !== '100' ? WARN : '');\n            paar(gm, T.zeile_rua, b.dmarc.rua || T.wert_keiner, b.dmarc.rua ? '' : WARN);\n            paar(gm, T.zeile_ausrichtung,\n                'adkim=' + b.dmarc.adkim + '  aspf=' + b.dmarc.aspf, GRAU);\n            ziel.appendChild(gm);\n        }\n\n        \/\/ --- Umfeld ---\n        ziel.appendChild(el('div', UEBERSCHRIFT, T.h_umfeld));\n        var gu = gitter('auto auto');\n        paar(gu, T.zeile_mx, b.mx.length ? b.mx.join(', ') : T.wert_keiner, b.mx.length ? '' : WARN);\n        paar(gu, T.zeile_caa, b.caa.length ? b.caa.join(' | ') : T.wert_keiner, b.caa.length ? '' : GRAU);\n        paar(gu, T.zeile_bimi, b.bimi || T.wert_keiner, GRAU);\n        if (b.dauer !== null) { paar(gu, T.zeile_dauer, b.dauer + ' ms', GRAU); }\n        ziel.appendChild(gu);\n\n        \/\/ --- Befunde ---\n        if (b.befunde.length) {\n            ziel.appendChild(el('div', UEBERSCHRIFT, T.h_befunde));\n            var liste = el('ul', 'margin: 0 0 0 18px; padding: 0; color: var(--text-secondary, #a0a0b0); font-size: 0.87rem; line-height: 1.65;');\n            b.befunde.forEach(function (f) {\n                var text = T['befund_' + f];\n                if (text) { liste.appendChild(el('li', '', text.replace('{limit}', String(b.spf.limit)))); }\n            });\n            ziel.appendChild(liste);\n        }\n    }\n    window.LW_TEST.MA.darstellen = darstellen;\n\n    var laeuft = false;\n    btn.addEventListener('click', function () {\n        if (laeuft) { return; }\n        laeuft = true;\n        btn.disabled = true;\n        out.innerHTML = '';\n        out.appendChild(el('p', ZELLE + GRAU + ' margin: 0;', T.laeuft));\n        abfragen(wert('ma-domain'), wert('ma-selektoren')).then(function (antwort) {\n            darstellen(bewerten(antwort), out);\n            laeuft = false;\n            btn.disabled = false;\n        }, function () {\n            darstellen(bewerten({ fehler: 'netz' }), out);\n            laeuft = false;\n            btn.disabled = false;\n        });\n    });\n})();\n<\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Reads a domain&#8217;s DNS and says what actually happens to a forged message: how many of the ten allowed SPF lookups are used up, whether DKIM keys are long enough, and whether DMARC tells anyone to do something or merely watches.<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":38,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"template-tool-base.php","meta":{"footnotes":""},"tags":[91279,91144,91115],"class_list":["post-13343","page","type-page","status-publish","hentry","tag-prywatnosc-danych-pl","tag-devops","tag-web-security"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Email Authentication Checker: SPF, DKIM, DMARC, MX and CAA - Lukas Wojcik - Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/email-authentication-spf-dkim-dmarc-checker\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Email Authentication Checker: SPF, DKIM, DMARC, MX and CAA - Lukas Wojcik - Blog\" \/>\n<meta property=\"og:description\" content=\"Reads a domain&#039;s DNS and says what actually happens to a forged message: how many of the ten allowed SPF lookups are used up, whether DKIM keys are long enough, and whether DMARC tells anyone to do something or merely watches.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/email-authentication-spf-dkim-dmarc-checker\/\" \/>\n<meta property=\"og:site_name\" content=\"Lukas Wojcik - Blog\" \/>\n<meta property=\"article:modified_time\" content=\"2026-08-31T12:49:50+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/08\/og-default.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"1 minute\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/toolbox\\\/email-authentication-spf-dkim-dmarc-checker\\\/\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/toolbox\\\/email-authentication-spf-dkim-dmarc-checker\\\/\",\"name\":\"Email Authentication Checker: SPF, DKIM, DMARC, MX and CAA - Lukas Wojcik - Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\"},\"datePublished\":\"2026-08-31T12:47:01+00:00\",\"dateModified\":\"2026-08-31T12:49:50+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/toolbox\\\/email-authentication-spf-dkim-dmarc-checker\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/toolbox\\\/email-authentication-spf-dkim-dmarc-checker\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/toolbox\\\/email-authentication-spf-dkim-dmarc-checker\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Toolbox\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/toolbox\\\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Email Authentication Checker: SPF, DKIM, DMARC, MX and CAA\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\",\"name\":\"Lukas Wojcik - Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\",\"name\":\"luky\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"contentUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"width\":424,\"height\":636,\"caption\":\"luky\"},\"logo\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\"},\"sameAs\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Email Authentication Checker: SPF, DKIM, DMARC, MX and CAA - Lukas Wojcik - Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/email-authentication-spf-dkim-dmarc-checker\/","og_locale":"en_US","og_type":"article","og_title":"Email Authentication Checker: SPF, DKIM, DMARC, MX and CAA - Lukas Wojcik - Blog","og_description":"Reads a domain's DNS and says what actually happens to a forged message: how many of the ten allowed SPF lookups are used up, whether DKIM keys are long enough, and whether DMARC tells anyone to do something or merely watches.","og_url":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/email-authentication-spf-dkim-dmarc-checker\/","og_site_name":"Lukas Wojcik - Blog","article_modified_time":"2026-08-31T12:49:50+00:00","og_image":[{"width":1200,"height":630,"url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/08\/og-default.jpg","type":"image\/jpeg"}],"twitter_card":"summary_large_image","twitter_misc":{"Est. reading time":"1 minute"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/email-authentication-spf-dkim-dmarc-checker\/","url":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/email-authentication-spf-dkim-dmarc-checker\/","name":"Email Authentication Checker: SPF, DKIM, DMARC, MX and CAA - Lukas Wojcik - Blog","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#website"},"datePublished":"2026-08-31T12:47:01+00:00","dateModified":"2026-08-31T12:49:50+00:00","breadcrumb":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/email-authentication-spf-dkim-dmarc-checker\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/email-authentication-spf-dkim-dmarc-checker\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/email-authentication-spf-dkim-dmarc-checker\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.lukaswojcik.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Toolbox","item":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/"},{"@type":"ListItem","position":3,"name":"Email Authentication Checker: SPF, DKIM, DMARC, MX and CAA"}]},{"@type":"WebSite","@id":"https:\/\/www.lukaswojcik.com\/blog\/#website","url":"https:\/\/www.lukaswojcik.com\/blog\/","name":"Lukas Wojcik - Blog","description":"","publisher":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.lukaswojcik.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9","name":"luky","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","contentUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","width":424,"height":636,"caption":"luky"},"logo":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg"},"sameAs":["https:\/\/www.lukaswojcik.com\/blog"]}]}},"_links":{"self":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/13343","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/comments?post=13343"}],"version-history":[{"count":1,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/13343\/revisions"}],"predecessor-version":[{"id":13372,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/13343\/revisions\/13372"}],"up":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/38"}],"wp:attachment":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media?parent=13343"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/tags?post=13343"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}