Parse and evaluate DMARC aggregate reports from XML, XML.GZ, or PST-extracted attachments.
Project description
dmark
dmark is a local CLI for bulk DMARC aggregate report evaluation.
It handles:
.xmland.xml.gzDMARC report files- Optional extraction of DMARC attachments from a
.pstexport - Local web UI for upload or folder-path analysis
- Domain-level pass/fail metrics and actionable recommendations
Why this helps
For large mailboxes (thousands of DMARC report emails), this tool gives you:
- DMARC pass/fail rates
- Authentication vs alignment split (DKIM auth vs aligned, SPF auth vs aligned)
- DKIM/SPF alignment rates
- Policy/disposition summary
- Top failing source IPs
- Sender inventory (top senders, new since last run, optional approved-sender tagging)
- Historical Trend Score (all observed traffic) with factor-by-factor point deductions
- Severity-ranked issues with likely causes and a concrete action plan
- Policy impact simulator (estimated affected volume at
p=quarantine/p=reject) - Dual scoring: deliverability safety + anti-spoofing posture
- Four-pillar posture view: protection posture, deliverability safety, authentication coverage, and attack pressure
- Daily trend charts in the web UI (stacked source-category volume + split legitimate-vs-attack fail rates, UTC buckets)
- Receiver-side relay classification for known infrastructure patterns (e.g.,
cloud-sec-av.com) - Auto sender classification for common M365 outbound and receiver-side relay patterns
- Dynamic M365-specific action plan output (DKIM enablement + selector CNAME guidance)
- Optional live DNS diagnostics (DMARC/SPF TXT + DKIM selector CNAME/TXT checks) to tailor remediation steps
Install
From PyPI:
python -m pip install dmark
From this repo (editable/dev):
python -m pip install -e .
Workflow for Outlook ("new Outlook")
- Export your DMARC-report folder as a
.pstfile. - Extract report attachments:
dmark extract-pst C:\path\to\dmarc-folder-export.pst --out-dir .\extracted-reports
- Analyze extracted files:
dmark analyze .\extracted-reports --json-out .\dmarc-summary.json
If you already have .xml / .xml.gz files:
dmark analyze C:\path\to\reports
Enable DNS-informed guidance:
dmark analyze C:\path\to\reports --resolve-dns
Web UI
Start the local web app:
dmark serve --host 127.0.0.1 --port 8080
Then open:
http://127.0.0.1:8080
UI modes:
- Analyze local path: best for large sets (e.g., 4300 reports) without browser upload overhead.
- Analyze upload: good for small batches and spot checks.
- Analyze PST upload: upload one
.pst, extract DMARC report attachments, and analyze in one step.- PST uploads now run as background jobs and show live stage updates in the UI (
queued,extracting,analyzing,complete/error) including parsed file progress during analysis. - Web UI analysis includes DNS diagnostics to verify DMARC/SPF/DKIM record state and refine action plans.
- Results include per-domain daily trend charts below the summary table.
- PST uploads now run as background jobs and show live stage updates in the UI (
You can change upload size limit:
dmark serve --max-upload-mb 500
Default web upload limit is 1024 MB.
Parsing is multithreaded by default (parse_workers=auto).
On the first large run, the app auto-tunes worker count on a sample and caches the result in .dmark_cache/parse_tuning.json.
You can still override manually:
dmark serve --parse-workers 16
dmark analyze C:\path\to\reports --parse-workers 16
Summary computation now reports incremental progress during "Computing domain summaries" as reports are aggregated.
PST upload extraction still requires one backend:
pypffavailable in Python, orreadpstavailable inPATH, or- bundled
.NET PSTParsehelper (usepstparse-dotnetengine)
Quick backend check/install from CLI:
dmark setup-pst
dmark setup-pst --install-pstparse-dotnet
PST extraction backends
extract-pst uses:
pypff(if installed), otherwisereadpst(if available inPATH), otherwise- bundled
.NET PSTParsehelper
If extraction fails, install one of those backends and rerun.
Example output
Human summary:
- Files scanned / parsed / parse errors
- Duplicate reports skipped
- Per-domain:
- policy mode and consistency
- historical trend score and enforcement readiness
- trend score drivers (what cost points)
- attack pressure on unauthorized/pending-review traffic (separate from legit delivery risk)
- key issues (category, severity, confidence, evidence, likely cause)
- prioritized action plan
- policy impact simulation for
quarantine/reject - readiness gate with explicit basis (all traffic vs approved senders)
- messages, DMARC pass/fail rate
- DKIM/SPF auth pass vs aligned pass rates
- top sender inventory with "new since last run" indicator
- disposition totals
- top failing sources
- per-source evidence details (header-from/envelope-from, DKIM selector/domain/result, SPF domain/result, dispositions/overrides)
- recommendation summary
Machine-readable JSON:
--json-out path\to\summary.json
Notes
- Duplicate aggregate reports are deduped by
(org_name, report_id, begin, end, policy_domain). - Relaxed alignment is approximated with subdomain checks to keep this dependency-free.
- For public-suffix-accurate alignment logic, add PSL-based domain normalization in a future iteration.
- Web UI uses Flask and runs locally on your machine.
- Evidence in reports is aggregate-record level (DMARC XML buckets), not individual message traces.
- Sender history is cached in
.dmark_cache/sender_history.jsonto flag "new sender" sources between runs. - Deliverability safety/readiness calculations automatically exclude sender traffic classified as receiver-side relay noise.
- Forwarding/indirect flow often breaks SPF while DKIM may still survive; override reasons are treated as confidence modifiers.
- Optional approved-sender config:
{
"domains": {
"example.com": ["203.0.113.1", "198.51.100.9"]
}
}
Save as .dmark_cache/approved_senders.json to drive readiness and impact analysis on approved sender volume.
Dev test
python -m unittest discover -s tests -v
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dmark-0.1.0.tar.gz.
File metadata
- Download URL: dmark-0.1.0.tar.gz
- Upload date:
- Size: 61.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
22791e7f7823dfec3a1645cb4ef11d0c02b2a0c9561f1da91e0bc3ab6290359b
|
|
| MD5 |
a68dbd3eb55365ea760d611da0259faf
|
|
| BLAKE2b-256 |
e5d07b9f95f37c54dc366a68d0c8e2c0b001b0dbe8e9a0d65f03a654495e5520
|
Provenance
The following attestation bundles were made for dmark-0.1.0.tar.gz:
Publisher:
publish-pypi.yml on scotttromley/dmark
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dmark-0.1.0.tar.gz -
Subject digest:
22791e7f7823dfec3a1645cb4ef11d0c02b2a0c9561f1da91e0bc3ab6290359b - Sigstore transparency entry: 974741019
- Sigstore integration time:
-
Permalink:
scotttromley/dmark@d587899d6cb2e72693243d257a2fa0a0a9311eb6 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/scotttromley
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@d587899d6cb2e72693243d257a2fa0a0a9311eb6 -
Trigger Event:
push
-
Statement type:
File details
Details for the file dmark-0.1.0-py3-none-any.whl.
File metadata
- Download URL: dmark-0.1.0-py3-none-any.whl
- Upload date:
- Size: 57.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
99d29736543ead753c940eee0cb364439b4ac925f8c028f92b80c2ba63616aa9
|
|
| MD5 |
84400bb2944478d47f93539916532408
|
|
| BLAKE2b-256 |
55010895a4bee281de43a09cdf0ada7cd14a6fdcab3715a81ebfd9d32fecab61
|
Provenance
The following attestation bundles were made for dmark-0.1.0-py3-none-any.whl:
Publisher:
publish-pypi.yml on scotttromley/dmark
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dmark-0.1.0-py3-none-any.whl -
Subject digest:
99d29736543ead753c940eee0cb364439b4ac925f8c028f92b80c2ba63616aa9 - Sigstore transparency entry: 974741031
- Sigstore integration time:
-
Permalink:
scotttromley/dmark@d587899d6cb2e72693243d257a2fa0a0a9311eb6 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/scotttromley
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@d587899d6cb2e72693243d257a2fa0a0a9311eb6 -
Trigger Event:
push
-
Statement type: