Skip to content. | Skip to navigation

Navigation

You are here: Home / Support / Guides / Tools / Email / DMARC

Personal tools

DMARC

Domain-based Message Authentication, Reporting & Conformance

DMARC is a wrapper for either or both of SPF and DKIM which provides the recipient with some rules for how to handle mail that fails either or both of SPF and DKIM tests.

In addition it provides email addresses for the recipient to send reports about the email it has received from a given domain.

DMARC falls in a grey area between benefit for the recipient and sender.

  • Senders

    How a recipient will behave when an incoming email fails SPF or DKIM tests is an unknown and as such legitimate emails from a domain might be tarred with brush of any previous spam emails "from" the domain.

    The goal of DMARC is to allow the sender to state explicitly what should be done with emails that fail the SPF and DKIM tests thus:

    limiting or eliminating the user’s exposure to potentially fraudulent & harmful messages.

    —dmarc.org

    (It's not clear, here, whom "the user" is!)

    You would think that the obvious answer would be to reject them but the mechanism allows for quarantine and none (aka monitor) policies too.

  • Recipients

    From the recipient's perspective, an incoming email failing either or both of SPF and DKIM tests simply leaves you with more evidence that the message is SPAM. The idea behind DMARC is that the sender domain will now give you explicit advice for your deliberations.

    You would think that if the sending domain has published SPF and DKIM entries and the incoming email has failed either of them then you should be in no doubt that the email is illegitimate and can be rejected. There is obviously some greater subtlety here!

Reporting

A recipient system honouring DMARC may choose to send reports to the managers of the sending domain conveying information about the emails it has received "from" the sending domain.

In the first instance, with a policy of none (aka. monitor) the sending system is able to determine whether it has setup SPF and DKIM correctly.

I see a few issues here:

  1. The disposition by the recipient is the recipient's business. If you, the sender cannot configure SPF and DKIM for your domains then you shouldn't really be expected to be taken seriously on the Internet.
  2. If a recipient sends me information relating to how others are abusing my domain what exactly am I supposed to be able to do about it? You can imagine Giant Cheapskate ISP Corp really spending time and effort managing their user base to weed out spammers because I, Joe Nobody, said there was a problem. They'll only make an effort if Global Search Corp applies restrictions to them that affect their financial base.
  3. If I, a legitimate sender, can glean information from a recipient about how my legitimate emails are being handled by a recipient such that I can correct my configuration then every spammer can do the same. "Thanks for the tip, Global Search Corp, I'll fix my setup so my spam can get through."

Basic DMARC Record

Google are one of the co-sponsors of DMARC and provide some introduction to DMARC.

The basic entry to do nothing but get reports on how Google etc. see mail from your domain add _dmarc.example.com with a TXT record of, say:

v=DMARC1; p=none; rua=mailto:postmaster@example.com

or you might want a more specific user than postmaster, say, dmarc. Google use mailauth-reports@google.com, Microsoft use an aggregator, postmaster@exacttarget.com and LinkedIn use another aggregator, d@rua.agari.com.

Perhaps these aggregators know how to "protect your brand" (lawyer-up and hit the spammers?).

Checking

dmarcian offers a DMARC inspector.

OpenDMARC

OpenDMARC should be reasonably easy to install. You can follow this install guide.

Zimbra

Installing for Postfix is a straight-forward addition to smtpd_milters in main.cf (or postconf -e).

Zimbra, being driven by other passions, is a bit more fun.

You can't set smtpd_milters directly as it will be overwritten the next time Zimbra restarts the MTA.

There is a Zimbra config variable, zimbraMtaSmtpdMilters that should define any extra milters:

zmprov ms {server} zimbraMtaSmtpdMilters inet:localhost:8893

where 8893 is the default OpenDMARC port.

Two things happen now:

  1. There is, coincidentally, an smtpd_milters bug in the 8.6 release so, in fact, nothing happens.

    The bug report notes you need to:

    zmprov ms {server} zimbraMilterServerEnabled TRUE
    

    however,

  2. This automatically enables Zimbra's default milter on port 7026:

    $ postconf smtpd_milters
    smtpd_milters = inet:localhost:8893, inet:[::1]:7026
    

    The default filter handles access control for distribution lists (I think).

    You must restart the MTA at this point to start the default milter:

    $ zmmtactl restart
    Rewriting configuration files...done.
    Stopping milter server...milter server is not running.
    Starting milter server...done.
    ...
    

    Tip

    zmmilter restart is an alternative to start the default milter though you'll need to restart the MTA to rewrite the config files anyway.

    Otherwise you'll reject all mail:

    postfix/smtpd[94955]: NOQUEUE: milter-reject: EHLO from mail-qg0-f49.google.com[209.85.192.49]: 451 4.7.1 Service unavailable - try again later; proto=SMTP helo=<mail-qg0-f49.google.com>
    

    which looks unprofessional!

Generating Reports

Generating reports is:

  1. (clearly?) optional
  2. a lot more work

We need to:

  1. enable a history file
  2. massage the data via MySQL
  3. actually generate a report

MySQL Setup

Having a MySQL DB to hand may or may not be the easiest thing to do.

If you are standalone and have a handy MySQL server then follow Steve's instructions.

Zimbra
Single Server

A simple Zimbra setup, most likely a single server, you will have a MySQL database to hand, the one that the Mailbox process uses.

To follow Steve Jenkins' guide above you'll need the MySQL root password to be able to create the opendmarc user and database. You can get that with:

zmlocalconfig -s -m nokey mysql_root_password

He uses 'secretpassword' for the opendmarc user's MySQL access which will be later used in the reporting script to retrieve the data. If you want to both keep the data "in" Zimbra and have it do the hard thinking about password randomness you can use:

zmlocalconfig -r -e mysql_opendmarc_password

which will create a new local key, mysql_opendmarc_password, and give it a random password string (the -r flag).

The opendmarc user does not have (and should not have) any rights to read zimbra's config so you'll need to stash the value in an opendmarc-readable file:

sudo -u zimbra bash -c "/opt/zimbra/bin/zmlocalconfig -s -m nokey mysql_opendmarc_password" | \
 sudo -u opendmarc bash -c "(umask 0077; cat > /etc/opendmarc/mysql_opendmarc_password)"

The reporting script can retrieve the value as above:

DBPASS="$(cat /etc/opendmarc/mysql_opendmarc_password)"
Zimbra MySQL

Complicating the issue further is that the zimbra user's mysql command is a wrapper which sets up the MySQL socket, username and password. We only want the socket.

/opt/zimbra/bin/mysql looks like:

...
exec ${mysql_directory}/bin/mysql -S ${mysql_socket} \
   -u ${zimbra_mysql_user} --password=${zimbra_mysql_password} "$@"

We only want the -S flag. You'll need to run zmlocalconfig {varname} a couple of times to determine the values of mysql_directory and mysql_socket (and anything they use in turn) but for 8.6 it is:

/opt/zimbra/mariadb/bin/mysql -S /opt/zimbra/db/mysql.sock -p

and use the mysql_root_password as for Single Server above.

Finally we can run the MySQL DB creation commands:

CREATE DATABASE opendmarc;
GRANT ALL PRIVILEGES ON opendmarc.* TO opendmarc IDENTIFIED BY 'secretpassword';
quit;

and 'secretpassword' is whatever you or zmlocalconfig -r -e mysql_opendmarc_password / zmlocalconfig -s -m nokey zimbra_opendmarc_password generated above.

and create the schema -- you can run this as zimbra:

mysql -h localhost -u opendmarc -p opendmarc < /usr/share/doc/opendmarc-1.3.1/schema.mysql

(or a different release of OpenDMARC) and you'll be prompted for the 'secretpassword' again.

Enable History File

This is a simple tweak in /etc/opendmarc.conf:

HistoryFile /var/run/opendmarc.dat

Although the home directory of opendmarc is /var/run/opendmarc so it might make more sense to set the history file to be

HistoryFile /var/run/opendmarc/history.dat

and adjust the reporting script accordingly.

Actual Reporting

I would tweak Steve's script to move the rm -rf *.$$ at the end to interoperate with the set -e slightly better:

handle_EXIT()
{
    rm -f /tmp/${HISTFILE}.$$
}

trap handle_EXIT EXIT

If part of the script fails we'll throw away yesterday's history. We don't care though as this is a courtesy report.

His script sets the reporting entity to CheatCodes.com. Whom, they?

The default value of -report-email is postmaster@{hostdomain}, i.e. your host's local name. Most probably you really want to use some variant of postconf myhostname, the name you pretend to others to be, e.g. example.com (rather than mta1.localhost). We can get that with:

postconf -h myhostname

or

/opt/zimbra/postfix/sbin/postconf -h myhostname

which we can wrap with:

PFMH=$(postconf -h myhostname)

... -report-email=postmaster@${PFMH#*.}

though you might want to do some error handling in case PFMH isn't a FQDN.

As a further note, you, the report generator, don't get to see what you're sending to others. (Possibly a good thing!) So you may want to edit /usr/sbin/opendmarc-reports around line 925 and modify it from

!$smtp->to($repdest) ||

to

!$smtp->to($repdest, "postmaster\@example.com") ||

For your own interest -- or dmarc\@example.com or whatever (and don't forget the \ otherwise Perl thinks you're trying to dereference an array called example).

Finally, you need to run it! Add a cron entry for opendmarc:

@daily /usr/local/bin/opendmarc-send-reports.sh

(Or whatever you called the script.)

Warning

opendmarc-reports makes a simple call via Perl's Net::SMTP package. It does not retry a delivery failure. So, if you have Greylisting enabled and localhost (or the sending host in a multi-server setup) is not whitelisted then then outbound email(s) are likely to be deferred and the mail is lost.

Caution!

With Zimbra, for your own outgoing email, it looks like the email will not have been signed with DKIM before DMARC sees the email. This means the DKIM part of the result will be a fail. For everything outgoing.

Zimbra

Zimbra moves in mysterious ways again.

Zimbra's MySQL instance runs on port 7306 and in addition if you specify the MySQL hostname as localhost (or ::1) then a Unix socket will be used instead which will result in a perplexing:

opendmarc-import: unable to connect to database: Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)

My Zimbra instance happens to be listening on the IPv6 localhost address:

# lsof -i:7306
COMMAND   PID   USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
mysqld  15551 zimbra   24u  IPv6  56948      0t0  TCP localhost6.localdomain6:7306 (LISTEN)
...

So I'll need to modify the reporting script with both:

DBHOST='localhost6.localdomain6'
DBPORT='7306'

and add the -dbport=N flag to the commands:

/usr/sbin/opendmarc-import -dbhost=${DBHOST} -dbport=${DBPORT} ...

(Similarly for the other two opendmarc-* commands.)

Multi-Server

A multi-server Zimbra setup is a bit more tricky as almost certainly the MTAs collecting the OpenDMARC information are not on the same boxes as the Mailbox processes which have the MySQL daemon.

So you'll probably have to collect the history files from the MTAs in one pass and merge them together on one of the Mailbox servers for processing and report generation.

Steve has a suggested script which a cursory scan suggests just cat's the history files together then processes them. YMMV.

Report Back-Chatter

As an interesting aside, suppose that both you and Global Search Corp have DMARC reporting enabled and you send a single mail to someone at Global Search Corp. Tomorrow, they will send you a DMARC report mail which will include at least the mail you sent today.

The day after that you will send them a DMARC report mail which will include at least the DMARC report mail they sent you. That means, naturally, that the day after that, they will send you a DMARC report mail that includes at least the DMARC report mail you sent them.

And so on.

Document Actions