Zum Inhalt springen
Illustration: Aus einer offenen Archivbox ragt ein Stapel Blätter; davor liegt ein Blatt unter einer Lupe, daneben ein verschlossener Beutel.
Security

DMARC-Report lesen: rua-Berichte auswerten ohne Bezahl-Tool

Von · · 9 Min. Lesezeit

<feedback xmlns="urn:ietf:params:xml:ns:dmarc-2.0">
  <report_metadata>
    <org_name>empfaenger.example</org_name>
    <email>dmarc-reports@empfaenger.example</email>
    <report_id>20261016.beispiel.at</report_id>
    <date_range><begin>1792108800</begin><end>1792195199</end></date_range>
  </report_metadata>
  <policy_published>
    <domain>beispiel.at</domain>
    <adkim>r</adkim><aspf>r</aspf><p>none</p>
  </policy_published>
  <record>
    <row>
      <source_ip>198.51.100.7</source_ip>
      <count>312</count>
      <policy_evaluated>
        <disposition>none</disposition><dkim>fail</dkim><spf>fail</spf>
      </policy_evaluated>
    </row>
    <identifiers>
      <header_from>beispiel.at</header_from>
      <envelope_from>bounce.versanddienst.example</envelope_from>
    </identifiers>
    <auth_results>
      <dkim><domain>versanddienst.example</domain><selector>s1</selector><result>pass</result></dkim>
      <spf><domain>bounce.versanddienst.example</domain><scope>mfrom</scope><result>pass</result></spf>
    </auth_results>
  </record>
</feedback>

So ist ein DMARC-Sammelbericht aufgebaut, hier ein Beispiel nach dem Schema aus RFC 9990, gekürzt auf einen einzigen Datensatz, mit einer IP-Adresse aus dem Dokumentationsbereich und Beispieldomains. Er sagt: Am 16.10.2026 hat der Empfänger empfaenger.example 312 Mails mit beispiel.at im Absender von der Adresse 198.51.100.7 bekommen. DKIM und SPF haben beide bestanden, aber für versanddienst.example. Für DMARC hat deshalb keines gezählt, und weil die Richtlinie auf none steht, wurden die Mails trotzdem zugestellt.

Ein Bericht beantwortet eine einzige Frage: Wer verschickt Mails in deinem Namen, und bestehen sie? Er enthält keine Betreffzeilen, keine Empfänger und keinen Inhalt, nur Absender-IP, Anzahl und Prüfergebnisse. Mehr braucht man nicht, um jeden Versandweg zu finden, bevor die Richtlinie strenger wird. Den Eintrag mit Berichtsadresse anzulegen, beschreibt DMARC einrichten, dort steht auch die Kurzfassung des Lesens. Hier geht es um die Auswertung im Alltag.

Wie die Berichte ankommen#

Die Berichtsadresse steht im DMARC-Eintrag als rua:

_dmarc.beispiel.at  TXT  "v=DMARC1; p=none; rua=mailto:dmarc@beispiel.at"

Mehrere Adressen gehen durch Komma getrennt, jede mit eigenem mailto:. Ein Zusatz wie !10m hinter der Adresse begrenzt die Größe eines Berichts. Dann schicken die großen Empfänger täglich eine Mail. Google schreibt, dass es je nach Versandmenge Hunderte oder Tausende Berichte am Tag werden können, und empfiehlt dafür ein eigenes Postfach oder einen spezialisierten Dienst.

Jede Berichtsmail trägt die XML-Datei als Anhang, laut RFC 9990 mit GZIP gepackt. In der Praxis kommen auch ZIP-Dateien, Werkzeuge wie parsedmarc lesen beides. Der Dateiname folgt einem festen Muster:

empfaenger.example!beispiel.at!1792108800!1792195199.xml.gz

Empfänger, berichtete Domain, Beginn und Ende des Zeitraums in Sekunden seit 1970, UTC. Der Betreff lautet nach RFC 9990 sinngemäß Report Domain: beispiel.at Submitter: empfaenger.example Report-ID: …. Damit lassen sich Berichte im Postfach filtern, bevor man einen öffnet.

Wichtig bei fremden Adressen: Zeigt rua auf eine andere Domain, etwa einen Dienstleister, darf ein Empfänger laut RFC 9990, Abschnitt 4, dorthin nur berichten, wenn die Zieldomain zustimmt. Das tut sie mit einem TXT-Eintrag:

beispiel.at._report._dmarc.dienstleister.example  TXT  "v=DMARC1"

Fehlt er, gehen die Berichte nicht raus, und niemand bekommt eine Fehlermeldung. Dienstleister setzen den Eintrag für ihre Kunden selbst. Wer Berichte an eine eigene zweite Domain schicken lässt, muss ihn selbst anlegen.

Der Bericht Feld für Feld#

ElementBedeutungWorauf achten
report_metadata/org_namewer berichtet, etwa google.comEin Bericht je Empfänger und Tag
date_rangeZeitraum, Sekunden seit 1970, UTCmeist 24 Stunden
policy_publisheddein DMARC-Eintrag, wie der Empfänger ihn gelesen hatSteht hier etwas anderes als gedacht, liest der Empfänger einen anderen Eintrag
row/source_ipIP-Adresse, von der die Mails kamender Schlüssel für die Zuordnung
row/countAnzahl Mails von dieser Adresse mit diesem Ergebnis
policy_evaluated/dkim, /spfErgebnis für DMARC: pass nur, wenn bestanden und zur Absenderdomain passenddas, was zählt
policy_evaluated/dispositionwas der Empfänger getan hat: none, quarantine, rejectbei p=none immer none
policy_evaluated/reasonGrund, wenn der Empfänger von der Richtlinie abgewichen istetwa forwarded oder mailing_list
identifiers/header_fromdie Domain im sichtbaren From:sollte deine sein
identifiers/envelope_fromdie Umschlagadressebei Versanddiensten oft deren Domain
auth_results/dkimjede gefundene Signatur mit domain, selector, resultfür welche Domain signiert wurde
auth_results/spfSPF-Prüfung mit domain und resultfür welche Domain SPF geprüft wurde

Der häufigste Lesefehler steckt zwischen den beiden markierten Zeilen. auth_results zeigt die rohen Prüfungen, policy_evaluated das Urteil nach dem Abgleich mit dem Absender. Ein pass unten und ein fail oben ist kein Widerspruch, sondern genau der Fall aus dmarc=fail trotz SPF und DKIM pass.

Illustration: Viele kleine Umschläge laufen in einen Trichter, unten kommt ein einzelnes Blatt mit verschachtelten Klammern heraus, daneben ein leeres Terminalfenster.

Jede Quelle einem Versandweg zuordnen#

Ein Bericht nennt IP-Adressen, keine Namen. Die Zuordnung ist die eigentliche Arbeit, und sie folgt immer demselben Muster:

  1. Liste der eigenen Versandwege aufschreiben, bevor man den ersten Bericht öffnet: Postfächer, Website-Formulare, Newsletter, Shop, Rechnungsprogramm, Buchungssystem, Drucker mit Mailfunktion.
  2. Für jede unbekannte Adresse den Rückwärts-Eintrag abfragen. dig +short -x 198.51.100.7 liefert meist einen Namen, der den Betreiber verrät, etwa einen Versanddienst oder den eigenen Hoster. Fehlt der Name, hilft eine Whois-Abfrage der Adresse.
  3. Die Adresse einordnen, in eine von vier Gruppen:
GruppeBild im BerichtWas zu tun ist
eigener Weg, bestehtpolicy_evaluated mindestens einmal passnichts
eigener Weg, besteht nichtfail oben, pass für fremde Domain untenbeim Dienst eigene Absenderdomain mit DKIM einrichten
Weiterleitung oder ListeAdresse eines Mail-Anbieters oder einer Universität, DKIM pass für deine Domain, SPF failmeist nichts, DKIM trägt
fremdunbekannte Adresse, kein pass für deine Domain, oft wenige Mailsgenau das, was quarantine und reject abfangen sollen

Erst wenn die zweite Gruppe leer ist, ist der Zeitpunkt für eine strengere Richtlinie gekommen. Woran man ihn sonst noch erkennt, steht in DMARC-Policy: none, quarantine oder reject.

Ohne Bezahl-Tool auswerten#

Für eine kleine Domain reichen ein paar Berichte pro Woche und eines von drei Werkzeugen.

Einen einzelnen Bericht lesbar machen. Auf Linux und macOS:

gunzip -c 'empfaenger.example!beispiel.at!1792108800!1792195199.xml.gz' | xmllint --format -

Viele Berichte als Tabelle. Das folgende Skript braucht nur Python, liest .xml, .xml.gz und .zip und gibt je Datensatz eine Zeile aus. Weil jeder eine Mail an die rua-Adresse schicken kann, ist ein Bericht eine fremde Datei: Ist defusedxml installiert, liest das Skript damit, und es liest höchstens 50 MB je Bericht. Getestet mit dem Beispielbericht oben:

#!/usr/bin/env python3
"""DMARC-Sammelberichte als Tabelle: python3 dmarc_lesen.py *.xml.gz *.zip"""
import gzip, sys, zipfile
try:
    from defusedxml import ElementTree as ET  # pip install defusedxml
except ImportError:
    import xml.etree.ElementTree as ET

GRENZE = 50_000_000  # Bytes je Bericht, gegen gepackte Riesendateien

def lesen(pfad):
    if pfad.endswith(".gz"):
        return [gzip.open(pfad).read(GRENZE)]
    if pfad.endswith(".zip"):
        with zipfile.ZipFile(pfad) as z:
            return [z.open(n).read(GRENZE) for n in z.namelist() if n.endswith(".xml")]
    return [open(pfad, "rb").read(GRENZE)]

def t(el, pfad):
    x = el.find(pfad)
    return x.text.strip() if x is not None and x.text else "-"

for pfad in sys.argv[1:]:
    for roh in lesen(pfad):
        wurzel = ET.fromstring(roh)
        for el in wurzel.iter():  # Namensraum entfernen
            el.tag = el.tag.split("}")[-1]
        print("#", t(wurzel, "report_metadata/org_name"), "p=" + t(wurzel, "policy_published/p"))
        for r in wurzel.findall("record"):
            dk = ",".join(t(d, "domain") + ":" + t(d, "result") for d in r.findall("auth_results/dkim")) or "-"
            sp = ",".join(t(s, "domain") + ":" + t(s, "result") for s in r.findall("auth_results/spf")) or "-"
            print(t(r, "row/source_ip"), t(r, "row/count"),
                  "dkim=" + t(r, "row/policy_evaluated/dkim"), "spf=" + t(r, "row/policy_evaluated/spf"),
                  t(r, "row/policy_evaluated/disposition"), dk, sp)

Für den Beispielbericht gibt es diese Zeile aus:

# empfaenger.example p=none
198.51.100.7 312 dkim=fail spf=fail none versanddienst.example:pass bounce.versanddienst.example:pass

Laufend und mit Oberfläche: parsedmarc. Ein freies Python-Werkzeug unter Apache-2.0-Lizenz, das Sammel- und Fehlerberichte und auch die TLS-Berichte aus MTA-STS und TLS-RPT liest, gepackt oder nicht, direkt aus Dateien oder aus einem IMAP-Postfach:

pip install parsedmarc
parsedmarc -o auswertung/ berichte/*.xml.gz berichte/*.zip

Im Ordner auswertung/ liegen danach JSON- und CSV-Dateien, die jede Tabellenkalkulation öffnet. Wer täglich viele Berichte bekommt, kann parsedmarc an Elasticsearch, OpenSearch oder Grafana hängen und hat eine eigene Übersicht ohne Abo.

Messung: Wer in Tirol Berichte bekommen kann#

In eigener Sache: Am 05.10.2026 um 08:12 UTC habe ich die DMARC-Einträge derselben 149 Tiroler Domains wie in meinen bisherigen Messungen abgefragt, 34 Tourismusverbände und 115 Betriebe aus meiner Akquise-Liste, und für jede Berichtsadresse auf einer fremden Domain nachgesehen, ob dort die Freigabe nach RFC 9990 steht. Passiv per DNS-over-HTTPS bei Cloudflare, die beiden fehlenden Freigaben mit Google Public DNS gegengeprüft. Drei Domains gibt es nicht mehr, bleiben 146.

Wer bei 146 Tiroler Domains DMARC-Berichte bekommen kann Waagrechte Balken. Von 146 Domains haben 79 einen gültigen DMARC-Eintrag, 30 davon eine Berichtsadresse rua. 16 schicken die Berichte an eine fremde Domain, 2 dieser Ziele haben keine Freigabe nach RFC 9990 und bekommen deshalb keine Berichte. Eine Adresse ist ohne mailto: eingetragen. gültiger DMARC-Eintrag 79 mit Berichtsadresse rua 30 Berichte an fremde Domain 16 fremdes Ziel ohne Freigabe 2 Adresse ohne mailto: 1 Berichte möglich Dienstleister Berichte gehen verloren
Berichtsadressen bei 146 Tiroler Domains: 30 haben eine, 16 davon zeigen auf einen Dienstleister. Bei 2 fehlt dort die Freigabe, ohne die ein Empfänger keine Berichte schicken darf. Eigene Messung: _dmarc-Einträge per DNS-over-HTTPS (Cloudflare) am 05.10.2026, 08:12 UTC; Freigabe <domain>._report._dmarc.<ziel> nach RFC 9990, Abschnitt 4, abgefragt am selben Tag, die zwei fehlenden mit Google Public DNS gegengeprüft; 34 Tourismusverbände und 115 Betriebe, 3 Domains existieren nicht mehr. Nur Summen.
  • 79 Domains haben einen gültigen DMARC-Eintrag, 30 davon eine Berichtsadresse. 49 haben einen Eintrag, bekommen aber keine Berichte. Sie können nie belegen, dass alle ihre Versandwege bestehen.
  • 16 schicken die Berichte an eine fremde Domain, an 13 verschiedene Dienstleister und Anbieter, 16 an die eigene. Zwei Domains schicken an beide.
  • Bei 2 der fremden Ziele fehlt die Freigabe. Empfänger, die sich an RFC 9990 halten, schicken dorthin nichts. Die Dienste, die auf DMARC-Berichte spezialisiert sind, hatten alle ihre Freigabe gesetzt. Die Betreiber der beiden Domains sehen einen sauberen Eintrag und warten auf Berichte, die nicht kommen.
  • 1 Eintrag nennt zwei Adressen, die zweite ohne mailto:. Sie ist damit keine gültige Adresse.
  • 13 Domains haben zusätzlich ruf= für Fehlerberichte zu einzelnen Mails gesetzt. Für die Auswertung, um die es hier geht, sind die Sammelberichte entscheidend.

Namen veröffentliche ich nicht. Ob die eigene Domain einen DMARC-Eintrag mit rua hat, zeigt der E-Mail-Check, einen neuen erzeugt der DMARC-Generator.

Was nicht hilft#

Berichte an das normale Postfach schicken lassen. Nach einer Woche sind es Dutzende Anhänge zwischen Kundenmails, nach einem Monat liest sie niemand mehr.

Nur auf die Summe pass und fail schauen. Eine Prozentzahl sagt nicht, welcher Versandweg scheitert. Die Zuordnung je IP-Adresse ist die Arbeit, die den Unterschied macht.

Jede fremde IP-Adresse für einen Angriff halten. Weiterleitungen und Mailinglisten sehen im Bericht aus wie Fremde, bestehen aber meist DKIM.

Den Bericht eines einzigen Tages als Grundlage für reject nehmen. Versandwege, die einmal im Monat laufen, Rechnungen, Mahnungen, Newsletter, fehlen darin.

Eine Berichtsadresse auf einer fremden Domain ohne Freigabe. Siehe Messung.

Häufige Fragen#

Was ist ein DMARC-Report?

Ein Bericht, den empfangende Mailserver an die Adresse aus rua im DMARC-Eintrag schicken, meist täglich, als gepackte XML-Datei. Er listet je Absender-IP, wie viele Mails mit deiner Domain angekommen sind und ob SPF und DKIM für DMARC bestanden haben.

Was ist der Unterschied zwischen rua und ruf?

rua bestellt Sammelberichte, also Zahlen je IP-Adresse und Tag. ruf bestellt Fehlerberichte zu einzelnen Mails. Für die Frage, welche Versandwege scheitern, reichen die Sammelberichte.

Wie oft kommen DMARC-Berichte?

Laut Google in der Regel einmal am Tag je Empfänger. Wer viel verschickt, bekommt täglich viele Berichte, wer wenig verschickt, an manchen Tagen gar keinen.

Warum bekomme ich keine DMARC-Berichte?

Häufige Gründe: rua fehlt oder hat kein mailto:, die Adresse liegt auf einer fremden Domain ohne Freigabe unter _report._dmarc, das Postfach filtert die Anhänge als Spam, oder es wurden schlicht keine Mails an große Empfänger verschickt.

Wenn du es nicht selbst machen willst#

In eigener Sache: cyberscale bin ich, Stefan Haun aus Tirol. Im Paket E-Mail-Schutz sind vier Wochen Auswertung der DMARC-Berichte enthalten: jede Quelle einem Versandweg zugeordnet, was scheitert, repariert, und danach die Richtlinie Stufe für Stufe umgestellt.

Stand 05.10.2026. Quellen an diesem Tag abgerufen, DNS-Messung am 05.10.2026.

Quellen (7)
  • RFC 9990: DMARC Aggregate Reporting: XML-Schema mit report_metadata, policy_published, record, identifiers, auth_results (Abschnitt 3.1.1), GZIP, Dateiname und Betreff (3.5.2), Freigabe fremder Ziele unter _report._dmarc (4)
  • RFC 9989: DMARC: Tag rua, Sammel- und Fehlerberichte (4.1, 4.7)
  • RFC 7489: DMARC: Vorgänger mit Schema in Anhang C, Größenangabe hinter der Adresse, Freigabe fremder Ziele (7.1)
  • Google: About DMARC reports: Berichte in der Regel einmal täglich, Hunderte bis Tausende am Tag möglich, eigenes Postfach oder Dienst empfohlen
  • parsedmarc und Dokumentation: Apache-2.0-Lizenz, liest Sammel-, Fehler- und SMTP-TLS-Berichte, gzip und zip, Ausgabe als JSON und CSV
  • RFC 5737 und RFC 2606: Beispiel-IP-Adressen und Beispieldomains
  • Eigene Messung: DMARC-Einträge von 149 Tiroler Domains (34 Tourismusverbände, 115 Betriebe) am 05.10.2026 um 08:12 UTC per DNS-over-HTTPS (Cloudflare), Freigaben <domain>._report._dmarc.<ziel> am selben Tag, fehlende mit Google Public DNS gegengeprüft. Veröffentlicht werden nur Summen, keine Namen.

Weiterlesen