aprf-reader
Reads APRF (Aggregate Performance Reporting) reports and tells you where the mail you signed landed: how much reached the inbox, how much was treated as unwanted, and how recipients reacted, day by day and per DKIM selector. It points out the days worth a look, such as a jump in unwanted mail.
Two ways to use it, with the same results:
- In your browser: aprf.dns-audit.com. Drop your reports on the page. They are read on your computer and never uploaded.
- On the command line:
pipx install aprf-reader.
Status: 0.3, beta. Reads reports in the format of draft-ietf-mailmaint-aprf-00.
What APRF is
APRF is a proposed standard for a daily report from a mailbox provider about the mail you signed with DKIM. It is an IETF working group draft, draft-ietf-mailmaint-aprf, adopted by the Mail Maintenance (MAILMAINT) working group in October 2026. Reports arrive by email as small JSON files, one per day per signing domain and selector. Comcast sends them today in a beta for comcast.net mail.
A plain-language introduction: What APRF inbox placement reports tell you, and what they don't.
Use it
Python 3.11 or later, no other dependencies. Install with
pipx, which keeps command line tools in their own
environment, or with pip (pip3 on some systems) inside a virtual environment.
pipx install aprf-reader
aprf-reader reports/ # overview in the terminal
aprf-reader APRF.mbox # a mail folder exported as mbox
aprf-reader reports/ --markdown # Markdown with daily tables
aprf-reader reports/ --html summary.html # and a page you can open or share
aprf-reader reports/ --json # the summary as data, for scripts
In a terminal you get an overview: for each stream, each count's latest value,
its daily range, and a trend line with a gap for each day with no report, then
the changes worth a look. Piped or written to a file with --md, the output
is Markdown with the full daily tables.
Point it at report files (.json, .json.gz), saved report emails (.eml),
mailbox exports (.mbox), or folders of them. The easiest way to collect reports
is a mail filter that moves them into one folder, then an export of that folder:
Gmail through Google Takeout (pick Mail and the
label), Thunderbird with the ImportExportTools NG add-on, or Apple Mail's
Mailbox > Export Mailbox. Comcast's reports come from
aprf-noreply@alerts.xfinity.com with subjects starting APRF:. Folders are searched recursively. Files it skips are listed
on stderr and at the end of the summary, each with a reason.
Each stream (provider, signing domain, selector) gets a table with one row per
day and segment, a trend line per count, and a row for each day with no report.
A change worth a look is a day when unwanted mail or negative reactions at
least doubled and grew by 200 or more, or inbox mail fell by half and by 200
or more, against the report before. Comcast counts in steps of 100, so smaller
moves are left out as rounding.
A change in the report's version field is called out, since the draft uses it
to mark a change in what a category counts.
What it does
- Read report files (
.json,.json.gz,.emland.mbox) or a folder of them, and skip duplicates and files it cannot read, with a reason for each. - Summarise placement per signing domain and selector: inbox, unwanted and recipient reactions, by day and as a trend.
- Treat the counts as what the draft says they are: rounded into buckets, so they are a signal, not exact rates.
- Write a Markdown summary and a single self-contained HTML page you can open or share. Nothing is uploaded anywhere.
- Follow the draft as it changes. The report format lives in one module
(
src/aprf_reader/report.py), so a new draft revision is a small update. - When the same day arrives twice, keep the first copy and say so. The draft has not yet decided whether a resend replaces the original.
How the web page is built
web/src/aprf.js is a JavaScript port of the Python reader.
tests/test_web_parity.py runs both on the same files (JSON, gzip, saved
emails, forwarded emails, mailbox exports, duplicates and hostile text) and
requires the same JSON, Markdown and HTML output, so the page and the command
line cannot drift apart. node web/build.js inlines everything into one
web/dist/index.html whose Content Security Policy blocks every network
request, so it also works saved to disk. A merge to main that passes the
tests deploys it to Cloudflare.
Related
- dns-audit.com checks a domain for an APRF record and where its reports would go.
License
MIT
Metadata
Release files for aprf-reader 0.3.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| aprf_reader-0.3.1.tar.gz | 21.8 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| aprf_reader-0.3.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 38.6 kB
Release files / aprf_reader-0.3.1.tar.gz
| Download URL | aprf_reader-0.3.1.tar.gz |
|---|---|
| Size | 21.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
15a8b60863f52558a443e55ee1267e5ff02c8f5930370aab8d1a241248ea0dfa
|
|
BLAKE2b-256 checksum How to use checksums |
741acebbc0333253a5dce940aebb7f76e5cd06f5d07893433eb60cbddf531f79
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 28, 2026.
Transparency logRelease files / aprf_reader-0.3.1-py3-none-any.whl
| Download URL | aprf_reader-0.3.1-py3-none-any.whl |
|---|---|
| Size | 16.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
9095b0fb63f485c636f121867cbec05ad1751332bfd2e143d1408e340428d129
|
|
BLAKE2b-256 checksum How to use checksums |
cf55246cd6f66be8a0829f36a1f34167e2aaad3ae6f6dd541a4cad662a5f84a2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 28, 2026.
Transparency logSecurity for aprf-reader 0.3.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for aprf_reader-0.3.1.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 28, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.