Skip to main content

Crate dmarc_report_parser

Crate dmarc_report_parser 

Source
Expand description

DMARC aggregate report parser (RFC 7489).

Parse DMARC aggregate feedback reports from their XML representation as defined in RFC 7489 Appendix C.

§Library usage

dmarc-report-parser exposes a small, focused API for parsing DMARC aggregate feedback reports from their XML representation as defined in RFC 7489 Appendix C.

§Parsing a report

The primary entry point is parse, which accepts an XML string and returns a Report:

let xml = r#"<?xml version="1.0" encoding="UTF-8"?>
<feedback>
  <report_metadata>
    <org_name>Example Corp</org_name>
    <email>dmarc@example.com</email>
    <report_id>abc123</report_id>
    <date_range>
      <begin>1609459200</begin>
      <end>1609545600</end>
    </date_range>
  </report_metadata>
  <policy_published>
    <domain>example.com</domain>
    <adkim>r</adkim>
    <aspf>r</aspf>
    <p>none</p>
    <sp>none</sp>
    <pct>100</pct>
  </policy_published>
  <record>
    <row>
      <source_ip>192.0.2.1</source_ip>
      <count>5</count>
      <policy_evaluated>
        <disposition>none</disposition>
        <dkim>pass</dkim>
        <spf>pass</spf>
      </policy_evaluated>
    </row>
    <identifiers>
      <envelope_from>example.com</envelope_from>
      <header_from>example.com</header_from>
    </identifiers>
    <auth_results>
      <spf>
        <domain>example.com</domain>
        <result>pass</result>
      </spf>
    </auth_results>
  </record>
</feedback>"#;

let report = dmarc_report_parser::parse(xml).unwrap();
assert_eq!(report.report_metadata.org_name, "Example Corp");

If you have raw bytes instead of a string, use parse_bytes:

let report = dmarc_report_parser::parse_bytes(xml_bytes).unwrap();

§Trait-based parsing

Report implements FromStr, TryFrom<&str>, and [TryFrom<&[u8]>] so you can use whichever style fits your code:

use std::str::FromStr;
use dmarc_report_parser::Report;

// Using FromStr
let report = Report::from_str(xml).unwrap();

// Using str::parse
let report: Report = xml.parse().unwrap();

// Using TryFrom
let report = Report::try_from(xml).unwrap();

§Error handling

Both parse and parse_bytes return Result<Report, Error>. The Error type has two variants:

  • Error::Parse — the XML is malformed or does not match the DMARC report schema.
  • Error::Utf8 — the input bytes are not valid UTF-8 (only from parse_bytes / TryFrom<&[u8]>).

§Combining multiple reports

If you have several parsed reports and want to view them together — for example to compute totals across a quarter’s worth of feedback — wrap them in an Aggregate. It does not fabricate merged metadata; instead it preserves each underlying Report and lets you iterate every record paired with its source report.

use dmarc_report_parser::{parse, Aggregate};

let reports = vec![parse(xml).unwrap(), parse(xml).unwrap()];
let agg = Aggregate::from_reports(reports);

assert_eq!(agg.reports.len(), 2);
assert_eq!(agg.total_messages(), 8);
assert_eq!(agg.date_span(), Some((0, 86_400)));

for (report, record) in agg.records() {
    println!(
        "{} sent {} message(s) (from report {})",
        record.row.source_ip,
        record.row.count,
        report.report_metadata.report_id,
    );
}

§Working with the report

Once parsed, you can access every field of the RFC 7489 schema through the strongly-typed structs:

use dmarc_report_parser::{parse, DmarcResult};

let report = parse(xml).unwrap();

// Iterate over records and check results
for record in &report.records {
    let ip = &record.row.source_ip;
    let count = record.row.count;
    let dkim = record.row.policy_evaluated.dkim;
    let spf = record.row.policy_evaluated.spf;

    if dkim == DmarcResult::Fail || spf == DmarcResult::Fail {
        println!("{ip} sent {count} message(s) that failed DMARC");
    }
}

§CLI

§CLI usage

The dmarc-report binary is an optional CLI tool for rendering DMARC aggregate reports in the terminal, as HTML, or as Markdown. It is built when the cli Cargo feature is enabled.

§Installation

cargo install dmarc-report-parser --features cli

§Synopsis

dmarc-report [OPTIONS] <FILES>...

§Arguments

ArgumentDescription
<FILES>...One or more DMARC report files (.xml, .xml.gz, .gz, or .zip). When more than one file is given, the output is an aggregate view across all of them.

§Options

OptionDefaultDescription
-f, --format <FORMAT>terminalOutput format: terminal, html, or markdown
-o, --output <FILE>stdoutWrite rendered output to a file
-h, --helpPrint help information
-V, --versionPrint version

§Output formats

§Terminal (default)

Produces colorized, human-readable output suitable for viewing in a terminal emulator. Passing and failing results are highlighted with colors.

dmarc-report report.xml

§HTML

Generates a standalone HTML document with embedded CSS styles. This can be opened directly in a browser or served from a web server.

dmarc-report report.xml --format html --output report.html

§Markdown

Renders the report as Markdown tables. Useful for pasting into issues, wikis, or other documentation.

dmarc-report report.xml.gz --format markdown

§Supported input formats

The CLI automatically detects the file format from the file extension:

ExtensionHandling
.xmlParsed directly as XML
.gz, .xml.gzDecompressed with gzip, then parsed
.zipThe first .xml entry is extracted and parsed

§Aggregating multiple reports

Pass two or more files to render them as a single aggregate view. The output contains:

  • An overview with the total reports, records, messages, and the combined date span.
  • A reports section listing each contributing report (organisation, report ID, domain, period, record and message counts).
  • A combined records table with an extra Report column that identifies which report each row came from.

Each report retains its own metadata; nothing is fabricated by combining fields like policy_published across reports.

# Aggregate every gzip-compressed report in the current directory
dmarc-report *.xml.gz

# Render an aggregate as a single HTML document
dmarc-report q1/*.xml q2/*.xml --format html --output combined.html

§Examples

# View a plain XML report in the terminal
dmarc-report report.xml

# View a gzip-compressed report
dmarc-report report.xml.gz

# Extract and view a report from a zip archive
dmarc-report report.zip

# Save an HTML report to disk
dmarc-report report.xml --format html --output report.html

# Pipe Markdown output into another tool
dmarc-report report.xml --format markdown | less

# Aggregate multiple reports into one Markdown table
dmarc-report jan/*.xml.gz --format markdown

Structs§

Aggregate
A combined view across multiple DMARC aggregate reports.
AuthResults
Authentication results for a message (AuthResultType).
DateRange
UTC time range covered by a report, expressed as Unix timestamps.
DkimAuthResult
Result of evaluating a single DKIM signature (DKIMAuthResultType).
Identifiers
Message identifiers (IdentifierType).
PolicyEvaluated
Results of applying DMARC to the messages in this row (PolicyEvaluatedType).
PolicyOverrideReason
A reason why the applied policy may differ from the published policy (PolicyOverrideReasonType).
PolicyPublished
The DMARC policy published for the organizational domain (PolicyPublishedType).
Record
A single message record within a feedback report (RecordType).
Report
Top-level DMARC aggregate feedback report (<feedback>).
ReportMetadata
Report generator metadata (ReportMetadataType).
Row
Per-message data row (RowType).
SpfAuthResult
Result of an SPF check (SPFAuthResultType).

Enums§

AlignmentMode
DKIM / SPF alignment mode (AlignmentType).
Disposition
Policy action applied to a message (DispositionType).
DkimResult
DKIM verification result (DKIMResultType), per RFC 5451.
DmarcResult
The DMARC-aligned authentication result (DMARCResultType).
Error
Errors that can occur while parsing a DMARC aggregate report.
PolicyOverride
Reason type for a policy override (PolicyOverrideType).
SpfDomainScope
SPF identity scope (SPFDomainScope).
SpfResult
SPF evaluation result (SPFResultType), per RFC 7208.

Functions§

parse
Parse a DMARC aggregate report from an XML string.
parse_bytes
Parse a DMARC aggregate report from a byte slice.