{"id":15555,"date":"2026-09-05T14:01:06","date_gmt":"2026-09-05T12:01:06","guid":{"rendered":"https:\/\/www.lukaswojcik.com\/blog\/toolbox\/mail-transport-security-checker-mta-sts-tls-rpt-dane\/"},"modified":"2026-09-05T14:01:06","modified_gmt":"2026-09-05T12:01:06","slug":"mail-transport-security-checker-mta-sts-tls-rpt-dane","status":"publish","type":"page","link":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/mail-transport-security-checker-mta-sts-tls-rpt-dane\/","title":{"rendered":"Mail Transport Security Checker: MTA-STS, TLS-RPT, DANE and STARTTLS"},"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;\">SPF, DKIM and DMARC say who may send. They say nothing about whether the mail travels encrypted. Between two mail servers, TLS is opportunistic by default: if STARTTLS fails or a certificate is wrong, the mail goes in plain text, and nobody notices. MTA-STS and DANE turn that into a requirement. This check reads the MX records, opens an SMTP connection to up to three of them from this server, negotiates STARTTLS and reads the certificate, fetches the MTA-STS policy and the TLS-RPT record, and looks up TLSA records for DANE. No mail is sent; after the handshake the connection is closed with QUIT.<\/p>\n<div style=\"margin-bottom: 14px;\">\n        <label for=\"mt-domain\" style=\"color: var(--text-secondary, #a0a0b0); display: block; font-size: 0.85rem; margin-bottom: 5px;\">Domain (the part after the @)<\/label><br \/>\n        <input id=\"mt-domain\" type=\"text\" value=\"gmail.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<p style=\"color: var(--text-secondary, #a0a0b0); font-size: 0.82rem; margin-bottom: 16px;\">From this server: DNS queries, one request for the MTA-STS policy, and one or two SMTP connections on port 25 to each of up to three MX hosts, ending with QUIT before any envelope. MX hosts in private, loopback and link-local networks are never contacted. The query is protected by reCAPTCHA v3; the calling IP address and the domain are stored for one hour to limit the rate.<\/p>\n<p>    <button id=\"mt-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 mail transport<\/button><\/p>\n<div id=\"mt-ausgabe\" style=\"margin-top: 22px;\"><\/div>\n<p style=\"color: var(--text-secondary, #a0a0b0); font-size: 0.8rem; margin: 24px 0 0;\">Limits worth knowing: only the first three MX hosts and one address each are tested; some hosting providers greylist or refuse unknown senders before EHLO, which shows here as unreachable while real mail still flows; whether TLS 1.0 or 1.1 would be accepted is not probed; the DNSSEC signal is the AD flag of a public resolver, not a validation done here; and MTA-STS is judged from this server&#039;s view of DNS and the policy, while a sending server may have an older policy cached.<\/p>\n<\/div>\n<p><script>\n(function () {\n    'use strict';<\/p>\n<p>    const T = {\"einleitung\":\"SPF, DKIM and DMARC say who may send. They say nothing about whether the mail travels encrypted. Between two mail servers, TLS is opportunistic by default: if STARTTLS fails or a certificate is wrong, the mail goes in plain text, and nobody notices. MTA-STS and DANE turn that into a requirement. This check reads the MX records, opens an SMTP connection to up to three of them from this server, negotiates STARTTLS and reads the certificate, fetches the MTA-STS policy and the TLS-RPT record, and looks up TLSA records for DANE. No mail is sent; after the handshake the connection is closed with QUIT.\",\"label_domain\":\"Domain (the part after the @)\",\"datenschutz\":\"From this server: DNS queries, one request for the MTA-STS policy, and one or two SMTP connections on port 25 to each of up to three MX hosts, ending with QUIT before any envelope. MX hosts in private, loopback and link-local networks are never contacted. The query is protected by reCAPTCHA v3; the calling IP address and the domain are stored for one hour to limit the rate.\",\"knopf\":\"Check mail transport\",\"laeuft\":\"Reading DNS, opening SMTP connections...\",\"grenze\":\"Limits worth knowing: only the first three MX hosts and one address each are tested; some hosting providers greylist or refuse unknown senders before EHLO, which shows here as unreachable while real mail still flows; whether TLS 1.0 or 1.1 would be accepted is not probed; the DNSSEC signal is the AD flag of a public resolver, not a validation done here; and MTA-STS is judged from this server\\u0027s view of DNS and the policy, while a sending server may have an older policy cached.\",\"schutz_titel\":\"Protection level\",\"schutz_dane\":\"DANE: certificate pinned in DNS\",\"schutz_dane_erklaerung\":\"Every checked MX carries a TLSA record that matches the certificate it presents. A DANE-aware sender refuses to deliver in plain text or to a wrong certificate, without any policy fetch.\",\"schutz_mta_sts_enforce\":\"MTA-STS in enforce mode\",\"schutz_mta_sts_enforce_erklaerung\":\"The policy requires TLS with a valid certificate on the named MX hosts, and the hosts meet it. Senders that support MTA-STS refuse plain-text delivery.\",\"schutz_mta_sts_enforce_gebrochen\":\"MTA-STS enforce, but a host does not meet it\",\"schutz_mta_sts_enforce_gebrochen_erklaerung\":\"The policy demands what at least one MX host does not deliver. A sender honouring the policy will not deliver to that host.\",\"schutz_mta_sts_testing\":\"MTA-STS in testing mode\",\"schutz_mta_sts_testing_erklaerung\":\"The policy exists but only asks for reports. Delivery still falls back to plain text when TLS fails.\",\"schutz_opportunistisch\":\"Opportunistic TLS only\",\"schutz_opportunistisch_erklaerung\":\"STARTTLS works, but nothing requires it. A sender that cannot negotiate TLS, or is prevented from doing so on the path, delivers in plain text.\",\"schutz_unerreichbar\":\"MX hosts did not answer from here\",\"schutz_unerreichbar_erklaerung\":\"No SMTP connection could be completed, so nothing about the transport could be measured. Greylisting or a firewall is the usual cause.\",\"schutz_klartext\":\"Plain text: STARTTLS not offered\",\"schutz_klartext_erklaerung\":\"At least one MX host does not offer STARTTLS. Mail to it travels unencrypted.\",\"schutz_kein_mx\":\"No mail delivery\",\"schutz_kein_mx_erklaerung\":\"The domain has no MX records, or a null MX that declares it does not accept mail.\",\"h_richtlinien\":\"Policies\",\"zeile_domain\":\"Domain\",\"zeile_mx\":\"MX records\",\"zeile_sts_dns\":\"MTA-STS in DNS\",\"zeile_policy\":\"MTA-STS policy\",\"zeile_tlsrpt\":\"TLS-RPT\",\"zeile_dauer\":\"Took\",\"zeile_limit\":\"Checks left this hour\",\"policy_kurz\":\"mode {mode}, max_age {tage} days, mx: {mx}\",\"policy_status_kurz\":\"not readable (HTTP {status})\",\"wert_keine\":\"none\",\"wert_null_mx\":\"null MX (no mail)\",\"wert_gesperrt\":\"not contacted\",\"h_hosts\":\"MX hosts\",\"spalte_host\":\"MX\",\"spalte_ip\":\"Address\",\"spalte_starttls\":\"STARTTLS\",\"spalte_tls\":\"TLS\",\"spalte_verifiziert\":\"Chain verifies\",\"spalte_zert\":\"Certificate\",\"spalte_name\":\"Name matches\",\"spalte_tlsa\":\"TLSA\",\"spalte_dnssec\":\"DNSSEC\",\"rest_tage\":\"{tage} days left\",\"tlsa_passt\":\"matches\",\"tlsa_passt_nicht\":\"does not match\",\"fehlgeschlagen\":\"failed\",\"h_policy_text\":\"Policy file as served\",\"h_befunde\":\"Findings\",\"stufe_hoch\":\"High\",\"stufe_mittel\":\"Medium\",\"stufe_niedrig\":\"Low\",\"stufe_info\":\"Information\",\"stufe_gut\":\"In order\",\"keine_befunde\":\"Nothing to report.\",\"urteil_gut\":\"Transport encryption is consistent with what the domain announces.\",\"urteil_warnung\":\"Works today, with something that weakens the guarantee or is about to break.\",\"urteil_kritisch\":\"At least one finding means plain-text delivery or refused delivery.\",\"ja\":\"yes\",\"nein\":\"no\",\"fehler_kein_token\":\"The check could not be started because reCAPTCHA did not load.\",\"fehler_captcha\":\"reCAPTCHA classified the request as automated. Reloading the page normally helps.\",\"fehler_zu_viele\":\"The limit of {limit} checks per hour for this address has been reached.\",\"fehler_adresse\":\"That domain cannot be used.\",\"fehler_zaehler\":\"The rate counter is unavailable, so nothing was checked.\",\"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 input is too long.\",\"grund_kein_punkt\":\"The domain needs at least one dot.\",\"grund_hostform\":\"Enter a domain name, not an IP address.\",\"grund_gesperrter_bereich\":\"The host resolves into a private or reserved network. Those are never contacted.\",\"grund_kein_dns\":\"The MX host name does not resolve.\",\"grund_null_mx\":\"A null MX names no host.\",\"befund_mx_fehlt\":\"No MX records for {domain} || Without MX records, senders fall back to the A record of the domain itself, which usually is a web server. Mail to this domain is either undeliverable or lands somewhere unintended.\",\"befund_null_mx\":\"Null MX: the domain declares it accepts no mail || An MX record with priority 0 and an empty target (RFC 7505) tells senders not to try. Correct for domains that only send or do not use mail at all.\",\"befund_mx_liste\":\"{n} MX record(s): {liste} || The first {geprueft} host(s) by priority were contacted.\",\"befund_sts_dns_ok\":\"MTA-STS announced in DNS (id {id}) || The TXT record at _mta-sts tells senders that a policy exists. The id changes whenever the policy changes, so senders know when to refetch it.\",\"befund_sts_id_fehlt\":\"MTA-STS record without an id || The id field is required; senders use it to detect policy changes. Without it, a cached policy may never be refreshed.\",\"befund_sts_dns_mehrfach\":\"{n} MTA-STS records in DNS || Only one is allowed. Senders that find several treat the domain as having no policy at all.\",\"befund_sts_dns_ungueltig\":\"Unreadable MTA-STS record: {txt} || The record does not start with v=STSv1. Senders ignore it, and the policy file, if any, is never fetched.\",\"befund_sts_policy_unlesbar\":\"MTA-STS policy file does not parse ({grund}) || The file at mta-sts.\\u003Cdomain\\u003E\\\/.well-known\\\/mta-sts.txt needs version, mode, max_age and, unless the mode is none, at least one mx line. Senders that cannot parse it behave as if there were no policy.\",\"befund_sts_policy_ok\":\"MTA-STS policy: mode {mode}, max_age {max_age} s ({tage} days), mx {mx} || Senders cache this policy for max_age and apply it to every delivery in that time.\",\"befund_sts_mode_testing\":\"MTA-STS mode testing || Failures are reported via TLS-RPT but delivery still falls back to plain text. Testing is the right start; enforce is the goal once the reports stay clean.\",\"befund_sts_mode_none\":\"MTA-STS mode none || The policy explicitly turns MTA-STS off, usually to retire an earlier policy. It gives no protection.\",\"befund_sts_max_age_kurz\":\"Short max_age: {max_age} s || Senders forget the policy this quickly and must refetch it. Values of a week or more are usual; RFC 8461 suggests two weeks or longer once the policy is stable.\",\"befund_sts_policy_unbekannt\":\"Unknown fields in the policy: {liste} || Senders ignore fields they do not know. A typo in mode or max_age would show as a missing field, not here.\",\"befund_sts_policy_ohne_dns\":\"Policy file exists, but no MTA-STS record in DNS || Senders only fetch the policy after finding the TXT record at _mta-sts.\\u003Cdomain\\u003E. Without it, the file is never read.\",\"befund_sts_policy_content_type\":\"Policy served as {typ} || The policy must be served as text\\\/plain. Some senders refuse other content types.\",\"befund_sts_mx_fehlt_in_policy\":\"MX host(s) not covered by the policy: {liste} || In mode {mode}, a sender honouring MTA-STS will not deliver to these hosts because the policy does not name them. Every MX host must match an mx line, exactly or via a one-level wildcard.\",\"befund_sts_mx_gedeckt\":\"All {n} MX hosts are covered by the policy || Each MX host matches an mx line of the policy.\",\"befund_sts_policy_weiterleitung\":\"Policy fetch was redirected (HTTP {status}) || RFC 8461 forbids following redirects when fetching the policy. Senders treat this as a fetch failure and fall back to whatever policy they cached, or to none.\",\"befund_sts_policy_status\":\"Policy fetch returned HTTP {status} || The MTA-STS record announces a policy, but the file could not be read. Senders that have never cached it treat the domain as unprotected.\",\"befund_sts_policy_fehlt\":\"Policy file not reachable at {url} ({grund}) || The DNS record announces MTA-STS, but the https host mta-sts.\\u003Cdomain\\u003E does not answer or has no valid certificate. The DNS record alone protects nothing.\",\"befund_sts_fehlt\":\"No MTA-STS for {domain} || Without a policy, TLS between mail servers remains opportunistic: a sender that cannot negotiate it delivers in plain text. MTA-STS needs a TXT record, a small https host and a text file; testing mode first, then enforce.\",\"befund_tlsrpt_ungueltig\":\"TLS-RPT record unusable ({rua}) || The rua field must name a mailto: or https: destination. Without a valid one, senders have nowhere to send their daily reports.\",\"befund_tlsrpt_ok\":\"TLS-RPT reports go to {rua} || Senders that support TLS-RPT send a daily summary of TLS failures there. This is how a broken MTA-STS or DANE setup becomes visible before mail is lost.\",\"befund_tlsrpt_mehrfach\":\"{n} TLS-RPT records || Only one is allowed; several are treated as none.\",\"befund_tlsrpt_fehlt\":\"No TLS-RPT for {domain} || Failures of MTA-STS or DANE stay invisible to the receiving side. A TXT record at _smtp._tls with rua=mailto: is all it takes.\",\"befund_mx_gesperrt\":\"MX {host} not contacted ({grund}) || The host resolves into a range this check never connects to, or does not resolve at all.\",\"befund_smtp_unerreichbar\":\"No SMTP connection to {host} ({fehler}) || Port 25 did not answer from here within the time limit. Greylisting, a firewall that only admits known senders, or a host that is down. Real mail flow may still work.\",\"befund_starttls_fehlt\":\"{host} does not offer STARTTLS || The EHLO response lists no STARTTLS. Every sender delivers to this host in plain text, whatever the policies say.\",\"befund_handshake_fehlgeschlagen\":\"TLS handshake with {host} failed ({fehler}) || STARTTLS was offered, but the TLS negotiation did not complete even without verification. Senders fall back to plain text or defer.\",\"befund_cert_abgelaufen\":\"Certificate of {host} expired on {datum} || Under MTA-STS enforce or DANE, senders refuse delivery. With opportunistic TLS the mail still flows, encrypted to an expired certificate.\",\"befund_cert_laeuft_ab\":\"Certificate of {host} expires in {tage} day(s), on {datum} || Less than two weeks. Automated renewal should have run by now; a check of the renewal job is due.\",\"befund_cert_selbstsigniert\":\"{host} presents a self-signed certificate || Acceptable only for opportunistic TLS. MTA-STS requires a certificate from a public CA; DANE with usage 3 can pin it instead.\",\"befund_dane_passt\":\"DANE: TLSA record for {host} matches the certificate ({usage} {selector} {matching}, {n} record(s)) || A DANE-aware sender verifies the certificate against DNS and refuses anything else. Usage 3 pins the leaf, usage 2 the issuing CA.\",\"befund_dane_passt_nicht\":\"DANE: TLSA record(s) for {host} do not match the presented certificate ({n} record(s)) || DANE-aware senders refuse delivery to this host. The usual cause is a renewed certificate with a new key while the TLSA record still holds the old hash. Rolling keys under DANE means publishing the new record before switching.\",\"befund_dane_ohne_dnssec\":\"TLSA record for {host} without DNSSEC validation || The resolver did not set the AD flag. DANE only counts when the record is DNSSEC-signed; unsigned TLSA records are ignored by senders.\",\"befund_starttls_ok\":\"STARTTLS works on all {n} MX host(s) || Each contacted host offered STARTTLS and completed a TLS handshake.\",\"befund_tls_alt\":\"Old TLS version negotiated: {liste} || TLS 1.0 and 1.1 are deprecated; senders that only accept 1.2 and 1.3 fall back to plain text or refuse. The host should offer TLS 1.2 and 1.3.\",\"befund_cert_name_passt_nicht\":\"Certificate does not cover the MX name: {liste} || For opportunistic TLS this goes unnoticed. MTA-STS requires the certificate to match the MX host name; under enforce, senders refuse delivery.\",\"befund_cert_name_passt\":\"Certificates cover the MX names on all {n} host(s) || Each host presents a certificate that names it.\",\"befund_cert_nicht_verifiziert\":\"Certificate chain does not verify: {liste} || The chain does not lead to a trusted root from here. MTA-STS enforce requires a valid chain; opportunistic senders accept it anyway.\",\"befund_dane_fehlt\":\"No DANE (TLSA) records || DANE binds the certificate to DNS and needs DNSSEC on the zone. It is the stronger mechanism, but it depends on the sender supporting it; MTA-STS is the more widely honoured one. Both can coexist.\",\"befund_dnssec_ad\":\"The zone answers with DNSSEC validation || The resolver set the AD flag on the TLSA query, so the MX zone is signed. That is the prerequisite for DANE.\"};<\/p>\n<p>    var ENDPUNKT = '\/lw-mailtls.php';\n    var SITEKEY = '6LcrPkEtAAAAAPo1QCOf-IIM2fCL0UfdJz4y2iSY';\n    var STUFEN = ['hoch', 'mittel', 'niedrig', 'info', 'gut'];\n    var SCHUTZ = ['dane', 'mta_sts_enforce', 'mta_sts_enforce_gebrochen', 'mta_sts_testing', 'opportunistisch', 'unerreichbar', 'klartext', 'kein_mx'];<\/p>\n<p>    function liste(w) { return Array.isArray(w) ? w : []; }\n    function zahl(w) { return (typeof w === 'number' && isFinite(w)) ? w : null; }\n    function text(schluessel, daten) {\n        var t = T[schluessel];\n        if (typeof t !== 'string') { return null; }\n        return t.replace(\/\\{([a-z_0-9]+)\\}\/g, function (m, k) {\n            return (daten && daten[k] !== undefined && daten[k] !== null) ? String(daten[k]) : m;\n        });\n    }\n    function drei(w) { return (w === true || w === false) ? w : null; }<\/p>\n<p>    function host(h) {\n        h = (h && typeof h === 'object') ? h : {};\n        return { host: h.host ? String(h.host) : '', prio: zahl(h.prio), ip: h.ip ? String(h.ip) : null, gesperrt: h.gesperrt ? String(h.gesperrt) : null,\n                 starttls: drei(h.starttls), protokoll: h.protokoll ? String(h.protokoll) : null, cipher: h.cipher ? String(h.cipher) : null, verifiziert: drei(h.verifiziert),\n                 zertCn: h.zert_cn ? String(h.zert_cn) : null, zertBis: h.zert_bis ? String(h.zert_bis) : null, zertTage: zahl(h.zert_tage), namePasst: drei(h.name_passt),\n                 tlsa: zahl(h.tlsa), tlsaPasst: drei(h.tlsa_passt), dnssec: drei(h.dnssec), fehler: h.fehler ? String(h.fehler) : null, dauer: zahl(h.dauer_ms) };\n    }<\/p>\n<p>    function bewerten(antwort) {\n        var a = antwort || {};\n        if (a.fehler) { return { fehler: String(a.fehler), grund: a.grund || null, limit: zahl(a.limit) }; }\n        var befunde = liste(a.befunde).map(function (f) {\n            return { key: String(f.key || ''), stufe: STUFEN.indexOf(f.stufe) === -1 ? 'info' : f.stufe, daten: (f.daten && typeof f.daten === 'object') ? f.daten : {} };\n        });\n        var gruppen = {};\n        STUFEN.forEach(function (s) { gruppen[s] = befunde.filter(function (f) { return f.stufe === s; }); });\n        var sts = (a.sts && typeof a.sts === 'object') ? a.sts : {};\n        var pol = (sts.policy && typeof sts.policy === 'object') ? sts.policy : null;\n        return {\n            fehler: null, domain: a.domain ? String(a.domain) : '',\n            urteil: (a.urteil === 'gut' || a.urteil === 'warnung' || a.urteil === 'kritisch') ? a.urteil : 'kritisch',\n            stufe: SCHUTZ.indexOf(a.stufe) === -1 ? 'kein_mx' : a.stufe,\n            mx: liste(a.mx).map(function (m) { return { host: m && m.host ? String(m.host) : '', prio: zahl(m ? m.prio : null) }; }),\n            hosts: liste(a.hosts).map(host),\n            stsDns: (sts.dns && typeof sts.dns === 'object') ? { id: sts.dns.id ? String(sts.dns.id) : null } : null,\n            stsTxt: liste(sts.txt).map(String),\n            policy: pol ? { mode: pol.mode ? String(pol.mode) : '-', maxAge: zahl(pol.max_age), mx: liste(pol.mx).map(String) } : null,\n            policyUrl: sts.policy_url ? String(sts.policy_url) : null, policyStatus: zahl(sts.policy_status), policyText: sts.policy_text ? String(sts.policy_text) : '',\n            tlsrpt: (a.tlsrpt && typeof a.tlsrpt === 'object') ? liste(a.tlsrpt.rua).map(String) : null, tlsrptTxt: liste(a.tlsrpt_txt).map(String),\n            befunde: befunde, gruppen: gruppen, dauer: zahl(a.dauer_ms), limitRest: zahl(a.limit_rest)\n        };\n    }<\/p>\n<p>    function skriptLaden() {\n        return new Promise(function (auf) {\n            if (window.grecaptcha) { auf(true); return; }\n            var s = document.createElement('script');\n            s.src = 'https:\/\/www.google.com\/recaptcha\/api.js?render=' + SITEKEY;\n            s.onload = function () { auf(true); }; s.onerror = function () { auf(false); };\n            document.head.appendChild(s);\n            setTimeout(function () { auf(!!window.grecaptcha); }, 8000);\n        });\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 (auf) {\n                var fertig = false;\n                function einmal(w) { if (!fertig) { fertig = true; auf(w); } }\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: 'mailtls' }).then(function (t) { einmal(t || null); }, function () { einmal(null); });\n                    });\n                } catch (e) { einmal(null); }\n            });\n        }, function () { return null; });\n    }\n    function abfragen(domain) {\n        return tokenHolen().then(function (token) {\n            return fetch(ENDPUNKT, { method: 'POST', headers: { 'Content-Type': 'application\/json' }, body: JSON.stringify({ domain: domain, token: token || '' }) })\n                .then(function (r) { return r.json().then(function (j) { return j; }, function () { return { fehler: 'antwort' }; }); }, function () { return { fehler: 'netz' }; });\n        });\n    }<\/p>\n<p>    window.LW_TEST = window.LW_TEST || {};\n    window.LW_TEST.MT = { bewerten: bewerten, darstellen: null, text: text, ENDPUNKT: ENDPUNKT, STUFEN: STUFEN, SCHUTZ: SCHUTZ, T: T };<\/p>\n<p>    var btn = document.getElementById('mt-btn');\n    var out = document.getElementById('mt-ausgabe');\n    if (!btn || !out) { return; }<\/p>\n<p>    function el(tag, stil, txt) { var e = document.createElement(tag); if (stil) { e.setAttribute('style', stil); } if (txt !== undefined && txt !== null) { e.textContent = txt; } return e; }\n    function wert(id) { var e = document.getElementById(id); return e ? e.value : ''; }\n    var UEBERSCHRIFT = 'font-family: \"Nunito Sans\", sans-serif; font-weight: 700; color: var(--text-primary, #e8e8ee); font-size: 0.95rem; margin: 22px 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 KASTEN = 'background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); border-radius: 8px; padding: 14px 16px; margin: 0 0 10px;';\n    var GUT = ' color: #7ee787;', WARN = ' color: #ffa94d;', ROT = ' color: #ff7b72;', GRAU = ' color: #8a8a99;';\n    var FARBEN = { hoch: '#ff7b72', mittel: '#ffa94d', niedrig: '#e3b341', info: '#8a8a99', gut: '#7ee787' };\n    var URTEIL = { gut: GUT, warnung: WARN, kritisch: ROT };\n    var SCHUTZ_FARBE = { dane: GUT, mta_sts_enforce: GUT, mta_sts_enforce_gebrochen: ROT, mta_sts_testing: WARN, opportunistisch: '', unerreichbar: WARN, klartext: ROT, kein_mx: GRAU };\n    function gitter(sp) { return el('div', 'display: grid; grid-template-columns: ' + sp + '; gap: 0 18px; align-items: baseline;'); }\n    function paar(g, n, w, stil) { g.appendChild(el('div', ZELLE, n)); g.appendChild(el('div', ZELLE_WERT + (stil || ''), w)); }\n    function janein(w) { return w === true ? T.ja : (w === false ? T.nein : '-'); }\n    function farbe(w) { return w === true ? GUT : (w === false ? ROT : GRAU); }<\/p>\n<p>    function darstellen(b, ziel) {\n        ziel.innerHTML = '';\n        if (b.fehler) {\n            var txt = T['fehler_' + b.fehler] || T.fehler_unbekannt;\n            if (b.grund && T['grund_' + b.grund]) { txt = txt + ' ' + T['grund_' + b.grund]; }\n            if (b.limit !== null) { txt = txt.replace('{limit}', String(b.limit)); }\n            ziel.appendChild(el('p', ZELLE + WARN + ' margin: 0;', txt));\n            return;\n        }\n        ziel.appendChild(el('div', 'font-size: 1.05rem; font-weight: 700; margin: 0 0 6px;' + URTEIL[b.urteil], T['urteil_' + b.urteil]));\n        ziel.appendChild(el('div', 'font-size: 0.95rem; font-weight: 700; margin: 0 0 4px;' + SCHUTZ_FARBE[b.stufe], T.schutz_titel + ': ' + T['schutz_' + b.stufe]));\n        ziel.appendChild(el('p', ZELLE + ' margin: 0 0 12px; line-height: 1.55;', T['schutz_' + b.stufe + '_erklaerung']));<\/p>\n<p>        ziel.appendChild(el('div', UEBERSCHRIFT, T.h_richtlinien));\n        var g = gitter('auto auto');\n        paar(g, T.zeile_domain, b.domain);\n        paar(g, T.zeile_mx, b.mx.length ? b.mx.map(function (m) { return m.prio + ' ' + (m.host || T.wert_null_mx); }).join(', ') : T.wert_keine, b.mx.length ? '' : ROT);\n        paar(g, T.zeile_sts_dns, b.stsDns ? ('v=STSv1' + (b.stsDns.id ? ', id=' + b.stsDns.id : '')) : (b.stsTxt.length ? b.stsTxt[0] : T.wert_keine), b.stsDns ? GUT : (b.stsTxt.length ? WARN : ''));\n        paar(g, T.zeile_policy, b.policy ? (text('policy_kurz', { mode: b.policy.mode, tage: b.policy.maxAge === null ? '?' : Math.round(b.policy.maxAge \/ 8640) \/ 10, mx: b.policy.mx.join(', ') || '-' })) : (b.policyStatus !== null ? text('policy_status_kurz', { status: b.policyStatus }) : T.wert_keine), b.policy && b.policy.mode === 'enforce' ? GUT : (b.policy ? WARN : ''));\n        paar(g, T.zeile_tlsrpt, b.tlsrpt ? b.tlsrpt.join(', ') : (b.tlsrptTxt.length ? b.tlsrptTxt[0] : T.wert_keine), b.tlsrpt ? GUT : '');\n        if (b.dauer !== null) { paar(g, T.zeile_dauer, b.dauer + ' ms', GRAU); }\n        if (b.limitRest !== null) { paar(g, T.zeile_limit, String(b.limitRest), GRAU); }\n        ziel.appendChild(g);<\/p>\n<p>        if (b.hosts.length) {\n            ziel.appendChild(el('div', UEBERSCHRIFT, T.h_hosts));\n            var huelle = el('div', 'overflow-x: auto;');\n            var gp = gitter('auto auto auto auto auto auto auto auto auto');\n            [T.spalte_host, T.spalte_ip, T.spalte_starttls, T.spalte_tls, T.spalte_verifiziert, T.spalte_zert, T.spalte_name, T.spalte_tlsa, T.spalte_dnssec].forEach(function (s) { gp.appendChild(el('div', ZELLE + ' font-weight: 700; color: var(--text-primary, #e8e8ee); white-space: nowrap;', s)); });\n            b.hosts.forEach(function (h) {\n                gp.appendChild(el('div', ZELLE_WERT + ' white-space: nowrap;', (h.prio !== null ? h.prio + ' ' : '') + (h.host || T.wert_null_mx)));\n                if (h.gesperrt) { gp.appendChild(el('div', ZELLE_WERT + GRAU + ' grid-column: span 8; white-space: normal;', T.wert_gesperrt + (T['grund_' + h.gesperrt] ? ' \u2013 ' + T['grund_' + h.gesperrt] : ''))); return; }\n                gp.appendChild(el('div', ZELLE_WERT + GRAU, h.ip || '-'));\n                if (h.starttls === null && h.fehler) { gp.appendChild(el('div', ZELLE_WERT + ROT + ' grid-column: span 7; white-space: normal;', T.fehlgeschlagen + ' (' + h.fehler + ')')); return; }\n                gp.appendChild(el('div', ZELLE_WERT + farbe(h.starttls), janein(h.starttls)));\n                gp.appendChild(el('div', ZELLE_WERT + (h.protokoll ? (\/1\\.[23]\/.test(h.protokoll) ? GUT : WARN) : GRAU), h.protokoll || (h.fehler ? T.fehlgeschlagen : '-')));\n                gp.appendChild(el('div', ZELLE_WERT + farbe(h.verifiziert), janein(h.verifiziert)));\n                gp.appendChild(el('div', ZELLE_WERT + (h.zertTage !== null && h.zertTage < 14 ? WARN : GRAU), h.zertCn ? h.zertCn + (h.zertTage !== null ? ' (' + text('rest_tage', { tage: h.zertTage }) + ')' : '') : '-'));\n                gp.appendChild(el('div', ZELLE_WERT + farbe(h.namePasst), janein(h.namePasst)));\n                gp.appendChild(el('div', ZELLE_WERT + (h.tlsa ? farbe(h.tlsaPasst) : GRAU), h.tlsa ? (h.tlsa + ' ' + (h.tlsaPasst === true ? T.tlsa_passt : (h.tlsaPasst === false ? T.tlsa_passt_nicht : ''))) : T.wert_keine));\n                gp.appendChild(el('div', ZELLE_WERT + (h.dnssec === true ? GUT : GRAU), janein(h.dnssec)));\n            });\n            huelle.appendChild(gp);\n            ziel.appendChild(huelle);\n        }\n\n        if (b.policyText) {\n            ziel.appendChild(el('div', UEBERSCHRIFT, T.h_policy_text));\n            var pre = el('pre', KASTEN + ' font-family: monospace; font-size: 0.82rem; color: var(--text-primary, #e8e8ee); white-space: pre-wrap; margin: 0;', b.policyText);\n            ziel.appendChild(pre);\n        }\n\n        ziel.appendChild(el('div', UEBERSCHRIFT, T.h_befunde));\n        var irgendwas = false;\n        STUFEN.forEach(function (s) {\n            var gr = b.gruppen[s];\n            if (!gr.length) { return; }\n            irgendwas = true;\n            ziel.appendChild(el('div', 'font-weight: 700; font-size: 0.82rem; text-transform: uppercase; letter-spacing: 0.5px; margin: 14px 0 6px; color: ' + FARBEN[s] + ';', T['stufe_' + s] + ' (' + gr.length + ')'));\n            gr.forEach(function (f) {\n                var k = el('div', KASTEN + ' border-left: 3px solid ' + FARBEN[s] + ';');\n                var t = text('befund_' + f.key, f.daten) || f.key;\n                var teile = t.split(' || ');\n                k.appendChild(el('div', 'color: var(--text-primary, #e8e8ee); font-size: 0.9rem; font-weight: 700;', teile[0]));\n                if (teile[1]) { k.appendChild(el('div', ZELLE + ' padding: 6px 0 0; line-height: 1.55;', teile[1])); }\n                ziel.appendChild(k);\n            });\n        });\n        if (!irgendwas) { ziel.appendChild(el('p', ZELLE + ' margin: 0;', T.keine_befunde)); }\n    }\n    window.LW_TEST.MT.darstellen = darstellen;\n\n    var laeuft = false;\n    btn.addEventListener('click', function () {\n        if (laeuft) { return; }\n        laeuft = true; btn.disabled = true;\n        out.innerHTML = '';\n        out.appendChild(el('p', ZELLE + GRAU + ' margin: 0;', T.laeuft));\n        abfragen(wert('mt-domain')).then(function (a) { darstellen(bewerten(a), out); laeuft = false; btn.disabled = false; },\n            function () { darstellen(bewerten({ fehler: 'netz' }), out); laeuft = false; btn.disabled = false; });\n    });\n})();\n<\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Checks what a sending mail server finds when it delivers to a domain: the MX hosts, whether STARTTLS is offered and which TLS version and certificate come back, whether an MTA-STS policy and a TLS-RPT address exist and are consistent, and whether DANE records match the certificates.<\/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":[92722,91243,91115],"class_list":["post-15555","page","type-page","status-publish","hentry","tag-email","tag-networking","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>Mail Transport Security Checker: MTA-STS, TLS-RPT, DANE and STARTTLS - 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\/mail-transport-security-checker-mta-sts-tls-rpt-dane\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Mail Transport Security Checker: MTA-STS, TLS-RPT, DANE and STARTTLS - Lukas Wojcik - Blog\" \/>\n<meta property=\"og:description\" content=\"Checks what a sending mail server finds when it delivers to a domain: the MX hosts, whether STARTTLS is offered and which TLS version and certificate come back, whether an MTA-STS policy and a TLS-RPT address exist and are consistent, and whether DANE records match the certificates.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/mail-transport-security-checker-mta-sts-tls-rpt-dane\/\" \/>\n<meta property=\"og:site_name\" content=\"Lukas Wojcik - Blog\" \/>\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\\\/mail-transport-security-checker-mta-sts-tls-rpt-dane\\\/\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/toolbox\\\/mail-transport-security-checker-mta-sts-tls-rpt-dane\\\/\",\"name\":\"Mail Transport Security Checker: MTA-STS, TLS-RPT, DANE and STARTTLS - Lukas Wojcik - Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\"},\"datePublished\":\"2026-09-05T12:01:06+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/toolbox\\\/mail-transport-security-checker-mta-sts-tls-rpt-dane\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/toolbox\\\/mail-transport-security-checker-mta-sts-tls-rpt-dane\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/toolbox\\\/mail-transport-security-checker-mta-sts-tls-rpt-dane\\\/#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\":\"Mail Transport Security Checker: MTA-STS, TLS-RPT, DANE and STARTTLS\"}]},{\"@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":"Mail Transport Security Checker: MTA-STS, TLS-RPT, DANE and STARTTLS - 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\/mail-transport-security-checker-mta-sts-tls-rpt-dane\/","og_locale":"en_US","og_type":"article","og_title":"Mail Transport Security Checker: MTA-STS, TLS-RPT, DANE and STARTTLS - Lukas Wojcik - Blog","og_description":"Checks what a sending mail server finds when it delivers to a domain: the MX hosts, whether STARTTLS is offered and which TLS version and certificate come back, whether an MTA-STS policy and a TLS-RPT address exist and are consistent, and whether DANE records match the certificates.","og_url":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/mail-transport-security-checker-mta-sts-tls-rpt-dane\/","og_site_name":"Lukas Wojcik - Blog","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\/mail-transport-security-checker-mta-sts-tls-rpt-dane\/","url":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/mail-transport-security-checker-mta-sts-tls-rpt-dane\/","name":"Mail Transport Security Checker: MTA-STS, TLS-RPT, DANE and STARTTLS - Lukas Wojcik - Blog","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#website"},"datePublished":"2026-09-05T12:01:06+00:00","breadcrumb":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/mail-transport-security-checker-mta-sts-tls-rpt-dane\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/mail-transport-security-checker-mta-sts-tls-rpt-dane\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/mail-transport-security-checker-mta-sts-tls-rpt-dane\/#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":"Mail Transport Security Checker: MTA-STS, TLS-RPT, DANE and STARTTLS"}]},{"@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\/15555","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=15555"}],"version-history":[{"count":0,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/15555\/revisions"}],"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=15555"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/tags?post=15555"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}