Set Up OpenDMARC with Postfix on CentOS/RHEL to Block Email Spoofing

In previous articles, we discussed several effective tips to block email spam. This tutorial will be showing you how to set up OpenDMARC with Postfix SMTP server on CentOS/RHEL to block email spoofing and spam. OpenDMARC is an open source DMARC email policy filter for MTAs (Message Transport Agent, aka SMTP server).

What is DMARC

DMARC (Domain-based Message Authentication, Reporting and Conformance) is an Internet standard (RFC 7489) that allows domain owners to prevent their domain names from being used by email spoofers. Before DMARC is invented, it is very easy for bad actors to use other people’s domain name in the From address.

If a domain owner created DMARC DNS record for his/her domain name and a receiving email server implemented DMARC verification, then bad actors need to pass SPF alignment or DKIM alignment in order to pass DMARC verification. If DMARC check fails, the spoofed email could be rejected. Never to be seen by end users. It’s difficult for the bad actor to pass SPF or DKIM, unless the domain owner’s email server is compromised.

OpenDMARC-Postfix-CentOS-RHEL

Email Spoofing Example

A spammer sent me a ransom email using winsaaluminyumankara.com in the From address. The whois information of winsaaluminyumankara.com is public. Clearly the spammer is not a person responsible for this domain name.

dmarc setup

winsaaluminyumankara.com has a DMARC record.

opendmarc-postfix-centos 8

Then I checked the email headers, which shows SPF failed. There’s no DKIM signature. So DMARC check fails. This is a spoofed email.

opendmarc postfix

This goes to show that not only big brands are being used by email spoofers, any domain names on the Internet could be impersonated by bad actors. Unfortunately the DMARC policy for this domain name is p=none, which tells receiving email server to do nothing special if DMARC check fails. If the policy is to p=reject, then my Postfix SMTP server would reject this email with OpenDMARC.

Paypal and Facebook have created a reject DMARC policy for their domain name.

opendmarc configuration

So if a bad actor tries to spoof Paypal or Facebook, my email server can reject the spoofed email with OpenDMARC. There are many other well-known domain names that deployed a reject DMARC policy, as can be seen in the table below.

  • bankofamerica.com
  • yahoo.com
  • chase.com
  • wellsfargo.com
  • facebook.com
  • google.com
  • youtube.com
  • twitter.com
  • reddit.com
  • instagram.com
  • linkedin.com
  • medium.com
  • pinterest.com
  • dropbox.com
  • microsoft.com
  • whatsapp.com

The secure mailbox provider Protonmail is using Postfix and OpenDMARC to perform DMARC checks on inbound emails and I will show you how to do the same on your own Postfix SMTP server.

Prerequisites

This tutorial is for mailbox providers and anyone who run their own mail server, to protect their users from being scammed by email spoofing. If you are a domain name owner and want to prevent your domain name from being used by email spoofers, please read this article to create DMARC record and analyze DMARC report. I also recommend you to read that article if you don’t fully understand DMARC.

You should have a DKIM verification service running on your mail server before you set up OpenDMARC. OpenDMARC should be used in conjunction with OpenDKIM. If you use Amavis to do DKIM signing and verification, then I recommend switching from Amavis to OpenDKIM. That’s because OpenDMARC can’t read the DKIM verification results from Amavis. You don’t have to completely uninstall Amavis. Simply disable DKIM in Amavis, then install and configure OpenDKIM.

If you don’t like to switch to OpenDKIM, then you need to integrate Amavis with Postfix via the milter interface, which will be explained at the end of this article.

Step 1: Install and Configure OpenDMARC on CentOS/RHEL

OpenDMARC is an open source software that can perform DMARC check and reporting. You can install it on CentOS/RHEL from the EPEL repository.

sudo dnf install epel-release

sudo dnf install opendmarc

Start OpenDMARC.

sudo systemctl start opendmarc

Enable auto-start at boot time.

sudo systemctl enable opendmarc

OpenDMARC listens on 127.0.0.1:8893. Run the following command to check its status.

systemctl status opendmarc

Output:

 opendmarc.service - Domain-based Message Authentication, Reporting & Conformance (DMARC) Milter
   Loaded: loaded (/usr/lib/systemd/system/opendmarc.service; enabled; vendor preset: disabled)
   Active: active (running) since Sun 2020-03-08 23:52:59 EDT; 1min 4s ago
     Docs: man:opendmarc(8)
           man:opendmarc.conf(5)
           man:opendmarc-import(8)
           man:opendmarc-reports(8)
           http://www.trusteddomain.org/opendmarc/
 Main PID: 19987 (opendmarc)
    Tasks: 3 (limit: 5047)
   Memory: 1.1M
   CGroup: /system.slice/opendmarc.service
           └─19987 /usr/sbin/opendmarc -c /etc/opendmarc.conf -P /var/run/opendmarc/opendmarc.pid

Then edit the main configuration file with your text editor.

sudo nano /etc/opendmarc.conf

Find the following line:

# AuthservID name

By default OpenDMARC uses the MTA hostname as the AuthserveID, but it’s better to use a different name for the authentication service, because Amavisd-new will overwrite the authentication results header added by OpenDMARC. You can change it to the following, which will be very easy for you to see which program adds which authentication-results header.

AuthservID OpenDMARC

Next, add the following line. Replace the hostname with your real Postfix hostname. This tells OpenDMARC to trust authentication result with mail.yourdomain.com in the ID. This is needed when you have OpenDKIM running to do DKIM verification. If the Postfix hostname isn’t included in the TrustedAuthservIDs, then OpenDMARC will ignore the Authentication-Results header generated by OpenDKIM.

TrustedAuthservIDs mail.yourdomain.com

Then find the following line.

# IgnoreAuthenticatedClients false

Change the value to true to ignore SMTP clients that are successfully authenticated via SMTP AUTH, which includes desktop/mobile mail clients that submit outgoing emails over port 587.

IgnoreAuthenticatedClients true

Then find this line:

# RejectFailures false

By default, OpenDMARC won’t reject emails that fail DMARC check, even if the domain’s policy is set to p=reject. If you prefer to reject emails that fail DMARC check when the domain’s policy is set to p=reject, then uncomment this line and change false to true.

RejectFailures true

Find the following line.

# RequiredHeaders  false

Change it to:

RequiredHeaders    true

This will reject emails that don’t conform to email header standards as described in RFC5322. For example, if an incoming email doesn’t have From: header or date: header, it will be rejected. A From: field from which no domain name could be extracted will also be rejected.

By default, OpenDMARC on CentOS/RHEL will ignore any SPF results in the email headers and performs SPF checks itself. This is controlled by the following two parameters.

SPFIgnoreResults true

SPFSelfValidate true

If you prefer to use other SPF check service on your mail server, then tell OpenDMARC to trust SPF results in the email headers and only perform SPF checks when it can’t find SPF results in the headers.

SPFIgnoreResults false

SPFSelfValidate true

Save and close the file. Then restart OpenDMARC for the changes to take effect.

sudo systemctl restart opendmarc

Step 2: Integrate OpenDMARC with Postfix SMTP Server

If you use OpenDKIM

Edit the Postfix main configuration file.

sudo nano /etc/postfix/main.cf

If you followed my DKIM tutorial on CentOS 8/RHEL 8, then you should have lines in this file like below. OpenDKIM is listening on 127.0.0.1:8891.

# Milter configuration
milter_default_action = accept
milter_protocol = 6
smtpd_milters = inet:127.0.0.1:8891
non_smtpd_milters = $smtpd_milters

Now you just need to add the OpenDMARC socket so that Postfix can talk to OpenDMARC. (Make sure it’s after the OpenDKIM socket.) OpenDMARC listens on 127.0.0.1:8893.

# Milter configuration
milter_default_action = accept
milter_protocol = 6
smtpd_milters = inet:127.0.0.1:8891,inet:127.0.0.1:8893
non_smtpd_milters = $smtpd_milters

Save and close the file. Then restart Postfix for the change to take effect.

sudo systemctl restart postfix

If you use Amavis

If you use Amavis for DKIM signing and verification like in iRedMail, then OpenDMARC can’t read the DKIM verification results from Amavis. You can install OpenDKIM to verify DKIM signature.

Install OpenDKIM from the EPEL (Extra Packages for Enterprise Linux) repository.

sudo dnf install epel-release

sudo dnf install opendkim

By default, the opendkim package on CentOS/RHEL runs in verification mode only. It won’t add DKIM signatures to outgoing emails. This is what we want because Amavis will add DKIM signatures. Edit OpenDKIM configuration file.

sudo nano /etc/opendkim.conf

Find the following line.

KeyFile   /etc/opendkim/keys/default.private

Since we don’t want OpenDKIM to sign outgoing emails, we need to comment out this line, then save and close the file.

Edit Postfix main configuration file.

sudo nano /etc/postfix/main.cf

Add the following lines at the end of this file, so Postfix will be able to call OpenDKIM via the milter protocol. Note that you should use 127.0.0.1 as the address. Don’t use localhost.

# Milter configuration
milter_default_action = accept
milter_protocol = 6
smtpd_milters = inet:127.0.0.1:8891,inet:127.0.0.1:8893
non_smtpd_milters = $smtpd_milters

Save and close the file. Then add postfix user to opendkim group.

sudo gpasswd -a postfix opendkim

Restart postfix service.

sudo systemctl restart postfix

Now we can start the opendkim service.

sudo systemctl start opendkim

And enable auto-start at boot time.

sudo systemctl enable opendkim

Step 3: Testing OpenDMARC Verification

Now send an email from your other email address to your domain address. After that, check the email headers. If OpenDMARC is working correctly, you can see the DMARC verification results like below.

Authentication-Results: OpenDMARC; dmarc=pass (p=none dis=none) header.from=gmail.com

I sent an email from my Gmail account to my domain email address and it passed DMARC verification. If you don’t see this email header, then check your mail logs.

sudo nano /var/log/maillog

You will see something like below, which means OpenDMARC is working.

opendmarc[26495]: 61DAA3EA44: gmail.com pass

If you see the following message.

ignoring Authentication-Results at 1 from mail.linuxbabe.com

it means OpenDMARC is ignoring the SPF and DKIM verification results, so OpenDMARC isn’t working. You need to add the following line in /etc/opendmarc.conf file, then restart OpenDMARC.

TrustedAuthservIDs mail.yourdomain.com

If you change the Postfix myhostname parameter, remember to add the new hostname to TrustedAuthservIDs. You can add multiple hostnames, separated by comma.

TrustedAuthservIDs mail.yourdomain.com,mail2.yourdomain.com

Testing OpenDMARC with Telnet

You can use telnet to spoof another domain name, such as paypal.com. First, run the following command to connect to port 25 of your mail server.

telnet mail.yourdomain.com 25

Then use the following steps to send a spoof email. (You type in the bold texts.)

HELO mail.paypal.com
250 mail.yourdomain.com
MAIL FROM:<[email protected]>
250 2.1.0 Ok
RCPT TO:<[email protected]>
250 2.1.5 Ok
DATA
354 End data with <CR><LF>.<CR><LF>
From:     [email protected]
To:       [email protected]
Subject:  Please update your password.

Click this link to update your password.
.
550 5.7.1 rejected by DMARC policy for paypal.com
quit

As you can see, my mail server rejected this email because it didn’t pass DMARC check and Paypal deployed a p=reject policy.

Note: If a domain’s DMARC policy is set to p=quarantine, then OpenDMARC milter will put the spoofed email into the Postifx hold queue indefinitely. The postmaster can list all messages in the queue with postqueue -p command and use the postsuper command line utility to release messages in hold queue.

(Optional) Integrate Amavis with Postfix via Milter

As explained in the prerequisites section, I recommend switching from Amavis to OpenDKIM, but if you don’t like to switch, then you need to integrate Amavis with Postfix via the milter interface, so that OpenDMARC can read the DKIM verification result from Amavis.

Install the amavisd-milter package on CentOS/RHEL.

sudo dnf install amavisd-milter

Start the service.

sudo systemctl start amavisd-milter

Enable auto-start at boot time.

sudo systemctl enable amavisd-milter

Amavisd-milter listens on Unix socket at /run/amavisd/amavisd-milter.sock. Edit Postfix main configuration file.

sudo nano /etc/postfix/main.cf

Add the following lines at the end of the file. Note that you should place the amavisd-milter Unix socket before the OpenDMARC TCP socket.

# Milter configuration
milter_default_action = accept
milter_protocol = 6
smtpd_milters = unix:/run/amavisd/amavisd-milter.sock,inet:127.0.0.1:8893
non_smtpd_milters = $smtpd_milters

Also comment out the following line, so Postfix won’t pass incoming emails to Amavis twice.

content_filter = smtp-amavis:[127.0.0.1]:10024

Save and close the file. Then add postfix to the amavis group, so Postfix will be able to access the Amavis Unix socket.

sudo gpasswd -a postfix amavis

Outgoing emails submitted from authenticated users should not be passed to Amavis via the milter interface, because Amavis won’t add DKIM signature. They should use 127.0.0.1:10026 as usual, so that DKIM signature will be added. Edit the Postfix master.cf file.

sudo nano /etc/postfix/master.cf

Find the submission component. It should look as follows if you followed my Amavis tutorial on CentOS/RHEL.

submission     inet     n    -    y   -    -    smtpd
 -o syslog_name=postfix/submission
 -o smtpd_tls_security_level=encrypt
 -o smtpd_tls_wrappermode=no
 -o smtpd_sasl_auth_enable=yes
 -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
 -o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject
 -o smtpd_sasl_type=dovecot
 -o smtpd_sasl_path=private/auth
 -o content_filter=smtp-amavis:[127.0.0.1]:10026

Now add the following option at the end.

-o smtpd_milters=

Like this:

submission     inet     n    -    y   -    -    smtpd
 -o syslog_name=postfix/submission
 -o smtpd_tls_security_level=encrypt
 -o smtpd_tls_wrappermode=no
 -o smtpd_sasl_auth_enable=yes
 -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
 -o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject
 -o smtpd_sasl_type=dovecot
 -o smtpd_sasl_path=private/auth
 -o content_filter=smtp-amavis:[127.0.0.1]:10026
 -o smtpd_milters=

This will make the Postfix submission serivce use no milter at all, so that emails submitted from authenticated users won’t be passed to Amavis via the milter interface. Note that you should not add any space before the equal sign (=).

You should also add this line to the smtps component.

smtps     inet  n       -       y       -       -       smtpd
  -o syslog_name=postfix/smtps
  -o smtpd_tls_wrappermode=yes
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject
  -o smtpd_sasl_type=dovecot
  -o smtpd_sasl_path=private/auth
  -o content_filter=smtp-amavis:[127.0.0.1]:10026
  -o smtpd_milters=

Save and close the file.  Restart Postfix for the changes to take effect.

sudo systemctl restart postfix

Now OpenDMARC will be able to read the DKIM verification result from Amavis, and Amavis will continue adding DKIM signature for authenticated users.

Wrapping Up

I hope this tutorial helped you set up OpenDMARC with Postfix SMTP server on CentOS/RHEL to block email spoofing and spam. As always, if you found this post useful, then subscribe to our free newsletter to get more tips and tricks. Take care 🙂

Rate this tutorial
[Total: 3 Average: 5]

9 Responses to “Set Up OpenDMARC with Postfix on CentOS/RHEL to Block Email Spoofing

  • Aleksandr
    4 years ago

    Very competent articles on setting up a mail server thank you very much! But I encountered problem mail sent via port 587, it does not reach the recipient safely, I have been struggling with the problem for 3 days.
    i need your help

     Mar 29 02:07:14 cxweb postfix/submission/smtpd[22180]: connect from unknown[77.79.135.68]
    Mar 29 02:07:14 cxweb postfix/submission/smtpd[22180]: Anonymous TLS connection established from unknown[77.79.135.68]: TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
    Mar 29 02:07:14 cxweb postfix/submission/smtpd[22180]: C3F1FE80068: client=unknown[77.79.135.68], sasl_method=LOGIN, sasl_username=no-reply
    Mar 29 02:07:14 cxweb postfix/cleanup[22192]: C3F1FE80068: message-id=
    Mar 29 02:07:14 cxweb opendkim[21079]: C3F1FE80068: no signing table match for '[email protected]'
    Mar 29 02:07:14 cxweb opendkim[21079]: C3F1FE80068: no signature data
    Mar 29 02:07:14 cxweb postfix/qmgr[6473]: C3F1FE80068: from=, size=682, nrcpt=1 (queue active)
    Mar 29 02:07:14 cxweb postfix/submission/smtpd[22180]: disconnect from unknown[77.79.135.68] ehlo=2 starttls=1 auth=1 mail=1 rcpt=1 data=1 quit=1 commands=8
    Mar 29 02:07:15 cxweb postfix/smtp[22193]: C3F1FE80068: host mx01.mail.com[74.208.5.22] refused to talk to me: 554-mail.com (mxgmxus007) Nemesis ESMTP Service not available 554-No SMTP service 554-IP address is black listed. 554 For explanation visit https://www.gmx.net/mail/senderguidelines?ip=77.79.135.68&c=bl
    Mar 29 02:07:15 cxweb postfix/smtp[22193]: C3F1FE80068: to=, relay=mx00.mail.com[74.208.5.20]:25, delay=0.82, delays=0.15/0/0.67/0, dsn=4.0.0, status=deferred (host mx00.mail.com[74.208.5.20] refused to talk to me: 554-mail.com (mxgmxus009) Nemesis ESMTP Service not available 554-No SMTP service 554-IP address is black listed. 554 For explanation visit https://www.gmx.net/mail/senderguidelines?ip=77.79.135.68&c=bl)
    Mar 29 02:10:35 cxweb postfix/anvil[22183]: statistics: max connection rate 4/60s for (submission:77.79.135.68) at Mar 29 02:07:14
    Mar 29 02:10:35 cxweb postfix/anvil[22183]: statistics: max connection count 1 for (submission:77.79.135.68) at Mar 29 02:06:25
    Mar 29 02:10:35 cxweb postfix/anvil[22183]: statistics: max cache size 1 at Mar 29 02:06:25
    Mar 29 02:11:51 cxweb clamd[16797]: SelfCheck: Database status OK.
    Mar 29 02:12:33 cxweb postfix/qmgr[6473]: 3B47FE80059: from=, size=658, nrcpt=1 (queue active)
    Mar 29 02:12:33 cxweb postfix/qmgr[6473]: 921ECE80055: from=, size=682, nrcpt=1 (queue active)
    Mar 29 02:12:33 cxweb postfix/qmgr[6473]: B8D21E8005F: from=, size=682, nrcpt=1 (queue active)
    Mar 29 02:12:33 cxweb postfix/qmgr[6473]: C3F1FE80068: from=, size=682, nrcpt=1 (queue active)
    Mar 29 02:12:33 cxweb postfix/smtp[25446]: 921ECE80055: host mx01.mail.com[74.208.5.22] refused to talk to me: 554-mail.com (mxgmxus007) Nemesis ESMTP Service not available 554-No SMTP service 554-IP address is black listed. 554 For explanation visit https://www.gmx.net/mail/senderguidelines?ip=77.79.135.68&c=bl
    Mar 29 02:12:33 cxweb postfix/smtp[25448]: C3F1FE80068: host mx00.mail.com[74.208.5.20] refused to talk to me: 554-mail.com (mxgmxus009) Nemesis ESMTP Service not available 554-No SMTP service 554-IP address is black listed. 554 For explanation visit https://www.gmx.net/mail/senderguidelines?ip=77.79.135.68&c=bl
    Mar 29 02:12:33 cxweb postfix/smtp[25447]: B8D21E8005F: host mx00.mail.com[74.208.5.20] refused to talk to me: 554-mail.com (mxgmxus010) Nemesis ESMTP Service not available 554-No SMTP service 554-IP address is black listed. 554 For explanation visit https://www.gmx.net/mail/senderguidelines?ip=77.79.135.68&c=bl
    Mar 29 02:12:33 cxweb postfix/smtp[25445]: 3B47FE80059: host mx00.mail.com[74.208.5.20] refused to talk to me: 554-mail.com (mxgmxus010) Nemesis ESMTP Service not available 554-No SMTP service 554-IP address is black listed. 554 For explanation visit https://www.gmx.net/mail/senderguidelines?ip=77.79.135.68&c=bl
     
  • Aleksandr
    4 years ago

    I don’t understand why I am on the black list because the PTR record is connected, so far I send only test emails, and there can be no spam mailings from the word at all

    • Xiao Guoan (Admin)
      4 years ago

      Being on a blacklist has nothing to do with PTR record. GMX uses an internal blacklist. There can be several reasons your IP address is blacklisted.

      As I said, You should go to https://postmaster.gmx.net/en/contact and use the contact form to request delisting of your IP address.

  • Aleksandr
    4 years ago

    Blacklist Reason TTL ResponseTime
    LISTED BARRACUDA 77.79.135.68 was listed 900 31 Ignore
    LISTED RATS Dyna 77.79.135.68 was listed 2100 94 Ignore
    LISTED SORBS DUHL 77.79.135.68 was listed 3600 0 Ignore
    LISTED SORBS SPAM 77.79.135.68 was listed 3600 16 Ignore
    LISTED Spamhaus ZEN 77.79.135.68 was listed 300 0 Ignore

    my ip is in the black lists of these services – yesterday I sent a form to unlock ip on gmx.net, but apparently this is not enough – how to understand why this incident occurs?

    • Xiao Guoan (Admin)
      4 years ago

      You need to go to the website of each of the blaclists and request delisting.
      https://www.spamhaus.org/lookup/
      https://www.barracudacentral.org/lookups
      http://www.sorbs.net/delisting/overview.shtml
      https://www.spamrats.com/rats-dyna.php

      However, it seems your IP address is a dynamic IP address at home. They are likely to refuse to delist your IP address. It’s a bad practice to run a mail server with a dynamic IP address. If you want to send email, I recommend setting up SMTP and IMAP proxy for your mail server.

  • Dennis
    1 year ago

    I didn do this optional amavis milter, and I have a problem.
    if I enable Selinux than amavisd doesn’t work I get this error. It works only when Selinux is disabled. Any idea what to do?
    May 1 22:46:06 akvarij amavis[152032]: perl=5.026003, user=, EUID: 971 (971); group=, EGID: 969 969 (969 969)
    May 1 22:46:07 akvarij amavis[152035]: (!)Net::Server: 2022/05/01-22:46:07 Can’t connect to TCP port 10026 on 127.0.0.1 [Permission denied]\n at line 64 in file /usr/share/perl5/vendor_perl/Net/Server/Proto/TCP.pm

  • McLemore
    5 months ago

    The instructions aren’t quite sufficient for RHEL 9 / Rocky 9. I found this page very helpful so I’d like to give back.

    /etc/opendmarc.conf now defaults to a socket instead of to a port:
    Socket local:/run/opendmarc/opendmarc.sock

    Which needs to be changed to:
    Socket inet:8893@localhost

    Now opendmarc.conf and /etc/postfix/main.cf can match. (Alternatively, set up postfix to use the milter on a socket.)

    Then to test (besides the above):
    systemctl restart opendmarc
    netstat -ltup |grep open [to confirm opendkim and opendmarc are listening
    grep dmarc /var/log/maillog

Leave a Comment

  • Comments with links are moderated by admin before published.
  • Your email address will not be published.
  • Use <pre> ... </pre> HTML tag to quote the output from your terminal/console.
  • Please use the community (https://community.linuxbabe.com) for questions unrelated to this article.
  • I don't have time to answer every question. Making a donation would incentivize me to spend more time answering questions.

The maximum upload file size: 2 MB. You can upload: image. Links to YouTube, Facebook, Twitter and other services inserted in the comment text will be automatically embedded. Drop file here