zaggregate - a DMARC aggregate report writer for zfilter database
ORG_EMAIL=email-addr zaggregate [option [option-arg]]
reads relevant message data from the database, using the queries
configured as described in zfilter_db
(1), and formats the result according
to the XML
schema defined in ``RFC 7489,
To comply with DMARC specifications, this command should be run by cron once
per day or according to the configured honored_report_interval.
DMARC provides for sending aggregate reports to multiple URIs, subject to size
limits. Only "mailto:" URIs are considered here. The size limits refer to
the compressed and encoded content of reports, so they can be enacted only
after compression and base64 encoding (option -z). For each target address,
zaggregate verifies that either its domain part is aligned with the domain
reported or the target domain authorizes sending reports about the domain
zaggregate design goal is to ease reporting while letting users devise
how to set up actual sending. In addition, it provides for debugging its
three queries, which zfilter_db(1) does not.
Unless --pipe is used, reports are written to files in the current
directory. Two files per report, with the same base name and different
extensions. The base name is composed according to DMARC specification, that
receiver ``!'' domain ``!'' period_start ``!'' period_end [ ``!'' unique-id ]
where "receiver" is the domain part of the ORG_EMAIL environment variable,
"domain" is the one where the DMARC record was retrieved from, period
boundaries are expressed as seconds since Unix epoch, UTC, and "unique-id"
depends on option -u. The first file has an ".env" extension, and contains
the environment variables described below. The second file contains the
report; its extension is either ".xml" or ".xml.gz.b64" depending on option
Short options can be stuffed into a single argument.
Set fork for each recipient, if --pipe is also given. That may entail
more forks if a report unlikely has multiple recipients. In addition,
this flag causes the environment variable URLENCODED_RCPT to be set.
The latter can be used to set unique bounce addresses.
- -f config-filename
Specify a different configuration file.
Log to syslog (LOG_MAIL facility) rather than stderr.
If --pipe is given, write the report to a temporary file before piping.
This option is automatically enabled if there are multiple size limits.
Generate a unique identifier for each report. If generated, the unique-id
appears in the filename as well as in the body of the report. It should
also match the "Message-Id:" header field.
This option is available only if zaggregate is compiled with the UUID library.
Debug queries. If issued multiple times, it increases verbosity. This option
is automatically enabled if zdkimfilter.conf has verbose >= 10.
Zip and encode the report. This enables checking size limits. If the limit is
exceeded the report is aborted. A line is logged saying no rcpt left. DMARC
recommends sending a notice to the relevant domain so that they can increase
the report frequency, the size limit, or both.
This pipes the output to a child process. The arguments following this option
are passed to the child process, starting with the executable path.
A child is forked for each mail, setting the environment variables described
below. The report content is piped to child's standard input. If the size
limit is exceeded, the child is killed with SIGTERM. However, if there are
multiple limits or option -t is used, the report is first written to a
temporary file, and, if all size limits are exceeded, no child is forked.
Children are spawned one at a time, and waited for. If a child exit status is
not 0, the report is not considered sent, and the domain timestamp is not
Print usage and exit.
Print version and exit.
Don't update domain timestamps after report is (considered) sent.
For debugging, don't issue DNS queries but look up TXT records in KEYFILE.
The latter is a plain text file in the current directory, having a name, a
space, and text RDATA in each relevant line.
Print out the configuration file and some debug info, and exit.
Input Environment Variables
These variables are read from the environment. They are also available to any
child, of course.
The email address of the reporting organization. Its domain part is used
for the first piece of the filename ("receiver" above).
Human readable name of the reporting organization.
If set, goes to the "extra_contact_info" part of the report.
Output Environment Variables
These variables are added to child environment if --pipe
is used. Otherwise
they are written, one per line, to a *.env
The report filename. When -z is used, the real filename gets an additional
".b64" extension, but the environment variable only has ".gz". Otherwise the
extension is just ".xml".
Either "application/gzip" or "text/xml" depending on -z.
Either "base64" or "7bit" depending on -z.
The target domain, which also makes the second piece of the filename.
The lowest limit specified by target addresses. If no address specifies a
limit, the default is 18446744073709551615 (UINT64_MAX).
The "To:" header field, containing all addresses, or just one if -1
is used. If -z is used, only
addresses that accept the report size are included. In any case, addresses
which specify a non-default size limit are followed by a comment with the
This variable is empty unless -1 is used. In that case, it contains
the urlencoded target address to be used for bounces.
This variable is only set if option -u is used. It contains the uniq-id.
These queries must be configured for zaggregate to function. See
zfilter_db(1) for details on the available variables.
DMARC aggregate domain query, to select domains.
DMARC aggregate record query, given a domain, select records.
Check recipient address, so as to skip bouncing targets.
Adjust the reported perios after the report is considered sent.
Default configuration file.
- *.env and *.xml[.gz.b64]
Reports generated in the current directory.
A pipeline, where "head"
have the initial and final parts of the
report, expressed in terms of environment variables and printf escape
sequences, can be structured like so:
ORG_EMAILemail@example.com zaggregate -zul --pipe /bin/sh -c \
'(eval printf %b "\"$(<head)\""; cat -; printf %b "\"$(<tail)\"") |\
Using --pipe instead of a real pipe is necessary because a new
/bin/sh has to be spawned for each report. "eval" replaces shell variables in
"head", and is not needed for "tail" if there are none. For a fully worked
out example using that approach see zaggregate-example.sh in the tarball.
Working with files may allow greater control and flexibility.
To test database queries from the distribution directory:
ORG_EMAILfirstname.lastname@example.org src/zaggregate -vf odbx_example.conf
Alessandro Vesely <email@example.com>
- RFC 7489
Domain-based Message Authentication, Reporting, and Conformance (DMARC).
Detailed explanation of queries and their expected outcome.
Other configuration options, including honored_report_interval and
Copyright © 2012-2021 Alessandro Vesely