Set Up OpenDMARC with Postfix on Ubuntu to Block Spam/Email Spoofing
In previous articles, we discussed how you can quickly set up your own mail server by using iRedMail or Modoboa, and also several effective tips to block email spam. This tutorial will be showing you how to set up OpenDMARC with Postfix SMTP server on Ubuntu 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 check, then bad actors need to pass SPF alignment or DKIM alignment in order to pass DMARC check. 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.
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.
winsaaluminyumankara.com
has a DMARC record.
Then I checked the email headers, which shows SPF failed. There’s no DKIM signature. So DMARC check fails. This is a spoofed email.
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.
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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.
To follow this tutorial, you need to get SPF and DKIM verification working first, because DMARC depends on the SPF and DKIM verification results to make a final decision.
Setting up OpenDMARC with Postfix SMTP Server on Ubuntu 22.04, Ubuntu 20.04 or 18.04
OpenDMARC is an open-source software that can perform DMARC verification and reporting. It’s already in the Ubuntu repository, so you can run the following command to install it.
sudo apt install opendmarc
If you are asked to configure a database for OpenDMARC with dbconfig-common
, you can safely choose No. You only need to configure a database for OpenDMARC if you want to generate DMARC reports for other mailbox providers. It’s not very useful for small mail server operators like us to generate DMARC reports, so we can skip it.
Once installed, it will be automatically started. Check its status with:
systemctl status opendmarc
Output:
● opendmarc.service - OpenDMARC Milter Loaded: loaded (/lib/systemd/system/opendmarc.service; disabled; vendor preset: enabled) Active: active (running) since Tue 2018-10-30 19:49:52 CST; 23s ago Docs: man:opendmarc(8) man:opendmarc.conf(5) Main PID: 14858 (opendmarc) Tasks: 6 (limit: 1110) CGroup: /system.slice/opendmarc.service └─14858 /usr/sbin/opendmarc
Hint: If the above command doesn’t quit immediately, you can make it quit by pressing the Q key.
Note that auto-start at system boot time is disabled. We can enable it by:
sudo systemctl enable opendmarc
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.
TrustedAuthservIDs mail.yourdomain.com
If the Postfix hostname isn’t included in the TrustedAuthservIDs
, or you have a typo in the hostname, then OpenDMARC will ignore the Authentication-Results header generated by OpenDKIM, and you will find the following error message in the mail log /var/log/mail.log
opendmarc[1133]: A436A205C9 ignoring Authentication-Results at 1 from mail.yourdomain.com
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
You may want OpenDMARC to ignore SMTP clients that are successfully authenticated via SMTP AUTH. For example, I have a Postfix SMTP server running on my blog web server that uses my main mail server as a relay to send notification emails, so I want openDMARC to ignore emails that are submitted from my blog web server. This also applies to desktop/mobile mail clients that submit outgoing emails over port 587. In this case, add the following line at the end of this file.
IgnoreAuthenticatedClients true
Add the following line at the end of this file.
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.
It’s recommended to also add the following line at the end of this file. This will make OpenDMARC perform a fallback SPF check itself when it can find no SPF results in the message header.
SPFSelfValidate true
OpenDMARC is implemented as a milter (mail filter). Postfix can talk to milter applications via Unix socket. The default socket file used by OpenDMARC is /var/run/opendmarc/opendmarc.sock
. But the Postfix SMTP daemon shipped with Ubuntu runs in chroot jail, which means the SMTP daemon resolves all filenames relative to the Postfix queue directory (/var/spool/postfix
). So we need to change the socket file used by OpenDMARC.
Find the following line.
Socket local:/var/run/opendmarc/opendmarc.sock
Change it to:
Socket local:/var/spool/postfix/opendmarc/opendmarc.sock
Save and close the file.
/etc/default/opendmarc
file can also set the socket file location, but the opendmarc
package on Ubuntu 18.04 and 20.04 doesn’t read this file, so we need to set the socket file path in /etc/opendmarc.conf
file.Create a directory to hold the OpenDMARC socket file and change the ownership so that opendmarc
user and opendmarc
group can access it.
sudo mkdir -p /var/spool/postfix/opendmarc sudo chown opendmarc:opendmarc /var/spool/postfix/opendmarc -R
Change permission to 750 to restrict access, so users not in group opendmarc
can’t access this directory.
sudo chmod 750 /var/spool/postfix/opendmarc/ -R
Add user postfix
to group opendmarc
.
sudo adduser postfix opendmarc
Then restart OpenDMARC.
sudo systemctl restart opendmarc
Configure Postfix SMTP Server
Edit the main configuration file.
sudo nano /etc/postfix/main.cf
If you have already configured OpenDKIM, then you should have lines in this file like below.
# Milter configuration milter_default_action = accept milter_protocol = 6 smtpd_milters = local:opendkim/opendkim.sock non_smtpd_milters = $smtpd_milters
Now you just need to add the OpenDMARC socket file so that Postfix can talk to OpenDMARC. (Make sure it’s after the OpenDKIM socket.)
# Milter configuration
milter_default_action = accept
milter_protocol = 6
smtpd_milters = local:opendkim/opendkim.sock,local:opendmarc/opendmarc.sock
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 iRedMail
If you used iRedMail to set up your mail server, then you don’t have OpenDKIM. iRedMail uses Amavis to do DKIM signing and verification, but OpenDMARC can’t read the DKIM verification results from Amavis, which will result in DMARC check failure. So, we need to set up DKIM verification as follows.
Run the following command to install OpenDKIM.
sudo apt install opendkim
Edit OpenDKIM main configuration file.
sudo nano /etc/opendkim.conf
Find the following line
#Mode sv
By default, OpenDKIM will act as both a signer (s) and a verifier (v). Since iRedMail already uses Amavis to do DKIM signing, we just need OpenDKIM to act as a verifier, so OpenDMARC can read the verification result. Remove the #
symbol and change the mode to verifier.
Mode v
Then add the following lines at the end of this file.
#OpenDKIM user # Remember to add user postfix to group opendkim UserID opendkim # Hosts to ignore when verifying signatures ExternalIgnoreList /etc/opendkim/trusted.hosts InternalHosts /etc/opendkim/trusted.hosts Socket local:/var/spool/postfix/opendkim/opendkim.sock
Save and close the file. Add postfix
user to opendkim
group.
sudo adduser postfix opendkim
Create the trusted hosts file.
sudo mkdir /etc/opendkim/ sudo nano /etc/opendkim/trusted.hosts
Add the following lines to the newly created file.
127.0.0.1
localhost
*.your-domain.com
The above means that messages coming from the above IP addresses and domains will be trusted. Save and close the file. Then change ownership.
sudo chown -R opendkim:opendkim /etc/opendkim
Next, create a directory to hold the OpenDKIM socket file and only allow opendkim
user and group to access it.
sudo mkdir /var/spool/postfix/opendkim sudo chown opendkim:opendkim /var/spool/postfix/opendkim
If you can find the following line in /etc/default/opendkim
file.
SOCKET="local:/var/run/opendkim/opendkim.sock"
Change it to
SOCKET="local:/var/spool/postfix/opendkim/opendkim.sock"
After that, we need to edit Postfix main configuration file.
sudo nano /etc/postfix/main.cf
Add the following lines at the end of this file to connect Postfix with OpenDKIM and OpenDMARC.
# Milter configuration milter_default_action = accept milter_protocol = 6 smtpd_milters = local:opendkim/opendkim.sock,local:opendmarc/opendmarc.sock non_smtpd_milters = $smtpd_milters
Save and close the file. Restart OpenDKIM, OpenDMARC and Postfix.
sudo systemctl restart opendkim opendmarc postfix
Testing OpenDMARC Verification
Now send an email from your other email address like Gmail 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/mail.log
You will see something like below, which means OpenDMARC is working.
opendmarc[26495]: implicit authentication service: mail.linuxbabe.com opendmarc[26495]: 61DAA3EA44: gmail.com pass
Ignoring Authentication-Results
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
Postfix Can’t Connect to OpenDMARC
If you find the following error in the Postfix mail log (/var/log/mail.log
), it means Postfix can’t connect to OpenDMARC via the Unix domain socket (local:opendmarc/opendmarc.sock
).
connect to Milter service local:opendmarc/opendmarc.sock: No such file or directory
you should check if the opendmarc service is running.
sudo systemctl status opendmarc
If opendmarc
service is running but the above error still exists, then you can configure OpenDMARC to use TCP/IP socket instead of Unix domain socket in order to fix this error. (Unix domain socket is usually faster than TCP/IP socket. If it doesn’t work on your server, then you should use TCP/IP socket.)
sudo nano /etc/opendmarc.conf
Find the following line:
Socket local:/var/spool/postfix/opendmarc/opendmarc.sock
Replace it with
Socket inet:8893@localhost
So OpenDMARC will be listening on the 127.0.0.1:8893
TCP/IP socket. Save and close the file. Then edit Postfix main config file.
sudo nano /etc/postfix/main.cf
Find the following line:
smtpd_milters = local:opendkim/opendkim.sock,local:opendmarc/opendmarc.sock
Replace it with:
smtpd_milters = local:opendkim/opendkim.sock,inet:127.0.0.1:8893
So Postfix will connect to OpenDMARC via the TCP/IP socket. Restart OpenDMARC and Postfix.
sudo systemctl restart opendmarc postfix
Testing OpenDMARC with Telnet
You can use telnet to spoof another domain name, such as paypal.com. First, run the following command on your local computer 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 the hold queue.
How to Whitelist an IP Address in OpenDMARC
If you want to allow your other server to relay emails via port 25 of your main mail server which runs OpenDMARC, then you should whitelist the IP address of the other server in OpenDMARC, because OpenDMARC will check the From:
domain in relay emails as well.
Edit OpenDMARC config file.
sudo nano /etc/opendmarc.conf
Add the following line at the end of this file.
IgnoreHosts /etc/opendmarc/ignore.hosts
Save and close the file. Then create the /etc/opendmarc/
directory.
sudo mkdir /etc/opendmarc/
Create the ignore.hosts
file.
sudo nano /etc/opendmarc/ignore.hosts
Add the IP addresses you want to whitelist in this file like so:
127.0.0.1 12.34.56.78
Save and close the file. Then restart OpenDMARC.
sudo systemctl restart opendmarc
Conclusion
I hope this tutorial helped you set up OpenDMARC with Postfix SMTP server on Ubuntu 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 🙂
Very important. And a thorough discussion. But way too complex. You can set up DMARC with minimal coding using Cloudflare. iRedMail already enables DKIM and SPF.
Despite all of this you can still be subject to spoofing. And what if you have 10 domain names.
OpenDMARC can’t read the iRedMail SPF and DKIM verification results, which means the DMARC check will always fail. So I use the method described in this article on my iRedMail server.
Sorry, but I don’t know how to perform DMARC check using Cloudflare. This article is about DMARC check on inbound emails. You can have 10 domain names on the mail server. You just need to set up OpenDMARC once and it will check every inbound email.
Protecting your own domain name from being used by spoofers is another subject, you can learn it here.
DMARC can only protect the exact domain name. It does not prevent spoofing with lookalike domain names (paypal.com vs paypa1.com)
Email server is complex.
It’s the best tutorial that I have ever seen till now on the subject
These email tutorials have been absolutely superb, thank you.
This, as well as the SPF & DKIM tutorials are a breath of fresh air amid loads of convoluted email configuration pages. Thanks for breaking it down so well
Beware of a small mistake. There is no need to change the value of AuthservID, usually its left unset and opendmarc uses the default hostname. Since you changed it, you caused opendmarc to break, and not recognize the current host. Which is why, you needed to set TrustedAuthservIDs manually.
If those two settings are left unset, then both will use the default hostname and everything will work fine.
That’s not a mistake. Your method works. My method works too.
However, the default setting won’t work if Amavis is used to verify DKIM signature. That’s why I modified those two settings to prevent that from happening 🙂
Hi Xiao,
I have a Modoboa server and I don’t have an opendkim.sock file; do I have to create one? If so, what’s the configuration?
On Modoboa, you have the following lines in
/etc/postfix/main.cf
OpenDKIM is listening on TCP socket 127.0.0.1:12345, instead of an Unix socket. Add the OpenDMARC socket after that.
Save and close the file. Then restart Postfix.
Note that on Modoboa, incoming emails will be sent to Amavis first, then sent back to Postfix via the localhost interface (127.0.0.1). OpenDMARC will ignore emails coming from localhost, and the emails won’t be verified by OpenDMARC. To solve this problem, you need to add the following line in
/etc/opendmarc.conf
Save and closet the file. Then create an empty
/etc/opendmarc.hosts
file.Restart OpenDMARC.
Hi Xiao,
Excellent tutorial, thanks for helping me configure the OpenDKIM and OpenDMARC files.
Really nice tutorial!
can this be used with multiple domains? if a postfix server is serving multiple domains.
OpenDMARC checks every incoming email message. You need to install and configure OpenDMARC only once. There’s no further actions required in regards to OpenDAMRC when you add additional domains on the mail server.
nice. thank you. awesome guide by the way.
Very good tutorial, that falls in line with your other awesome tutorials on email server configuration!
Just two remarks:
1. You need to link it here: https://www.linuxbabe.com/mail-server/setup-basic-postfix-mail-sever-ubuntu
2. When one followed through with your tutorials, your telnet example doesn’t work, since the SPF check already terminates the connection… 😄
You should not set your SPF record to reject an email just because SPF check fails.
Use
not
Thanks for the tip!!
And I need better glasses. I couldn’t distinguish between “-” and “~” from the automatic SPF entry generation of my vhost provider…
Why not? If you only send email from certain servers, telling any recipient to ignore emails from any other server is good, and the whole point of SPF. If you have a situation where you send emails from other servers and don’t know what they are, there is a place for that, but the majority of domains could have SPF records ending with -all and that would be good for the whole internet!
Because there are backup SMTP servers.
If the recipient’s main SMTP server is offline, then the sender would try the backup SMTP server, which would relay the email to the main SMTP server once it’s online. Because the sender doesn’t list the recipient’s backup SMTP server in the SPF policy, the email would be rejected if
-all
is used in the sender’s SPF policy.If
-all
SPF policy is so good, there’s no need for DMARC to exist.There IS a valid purpose for “-all” in SPF:
* Our email server handles email for many domains
* But it never, EVER, sends email under its own domain.
* That’s what the other reader was hinting at: any domain that NEVER sends email, can use “v=spf1 -all” !!!
* Until I set that up, I was frustrated by people thinking my IP address was a spam source… because they thought my domain was a spam source. In reality, others were spoofing us.
DMARC nicely shut that down. 🙂
There IS still an issue: subdomains are not handled well. It would be good to block all subdomains other than the “real” ones.
Hi Xiao,
A quick question.
Here in the file .
TrustedAuthservIDs
So only one domain can be written or can we add multiple domains-like
TrustedAuthservIDs ….
Or any other file for multiple domains?
You need to add one only hostname for TrustedAuthservID and that is your Postfix hostname. No matter how many domains you host on your email server, you use only one Postfix hostname.
Anyway, you can add multiple hostnames for TrustedAuthservIDs, if you want. This has no effect when you have only one hostname in your Postfix configuration.
Thanks Xiao.
Thank you for all these tutorials. Awesome work done and helped lots of user like me who have not had much experience with linux.
Thank you again.
Wondering if you have any plan to write any tutorial for “how to change Roundcube skin/logo”.
Hi Xiao,
a short question. How do I have to configure the postfix main.cf if DKIM is handled over Amavis?
I’ve been following many of your tutorial. I must say, it is easy to follow and to understand. Thank you for the sharing.
Great tutorial, thank you, but in the end I went with the DMARC Spamassassin Plugin – https://github.com/bigio/spamassassin-dmarc as this allows you to use the DMARC info as part of a wider assessment – not just a global accept / reject the email.
If an incoming email passes OpenDMARC verification, it will still be checked by SpamAssassin. Passing DMARC verification doesn’t mean it always goes into the inbox.
Integrating SpamAssassin with DMARC is very simple. Just add the following custom rule in the SpamaAssassin
/etc/spamassassin/local.cf
file, so emails that fails DMARC verification will be assigned a score (3.0).Excellent; all works. Thank you.
I received an email with my own email address, e.g. from [email protected] and to: [email protected], saying that the password for my email account had expired, which is obviously a phishing email.
How to block this kind of spoofing email? I am using iredmail on centos.
Thank you very much for your help.
Set your doamin DMARC policy to p=reject.
Just a quick question. Why do you have smtp milters point to smtpd milters?
This makes openDKIM and openDMARC run twice, when mail is picked up from the queue after spamassassin for example.
non_smtpd_milters
is for new mail that does not arrive via the Postfix smtpd server. This includes local submission via the sendmail command line, new mail that arrives via the Postfix qmqpd server, and old mail that is re-injected into the queue with “postsuper -r”.This is not what makes OpenDKIM and OpenDMARC run twice. Under
You need to add the following line:
This stops it from running twice after Amavis.
Sincerest of thanks. Can confirm, these steps worked on Ubuntu Server 22.04.1
What a massive help this has been. I’m a non-Linux person thrust in to a position of Linux Admin and while I’ve learned a lot over the last year or so, there are just some many parts and pieces. Just email alone can be like… postfix, spamassassin, amavis, opendkim, opendmarc, dovecot… making sure I don’t miss anything when trying to factor in all of the various moving parts is tough.
I can’t believe this article is only about 6 months old! It is SO well written and explains everything SO clearly. It makes me want to do even better on my own articles! Thanks so much!
Hello, very great tutorial but I do have a question :). Even if my DMARC policy is p=reject, the example with the telnet goes into my inbox.
When I send an email from gmail, in the header I don’t have anything like “dmarc=pass” but in my email log, I don’t have any error:
Followed your tutorials so far! Great tutorials but in the “Testing OpenDmarc with Telnet” I followed your instructions step by step and get this error in the /var/log/mail.log
“May 20 00:50:15 mail opendmarc[8088]: 4QNQ924Z4Qz5x86: RFC5322 requirement error: not exactly one Date field”
I mean, it does show that opendmarc is rejecting invalid emails, but I want to make sure it actually follows dmarc records. Wondering what I have to do to make it pass the RFC requirements
Thanks ~ Kali
are this tutorial still work?
i have read on maillist opendmarc are dead.
Apr 6 22:06:39 mail opendkim[154821]: 4VBdwp4Jtkz2QWPp: key retrieval failed (s=20230601, d=gmail.com): ‘20230601._domainkey.gmail.com’ query timed out
Apr 6 22:06:39 mail opendmarc[155577]: 4VBdwp4Jtkz2QWPp: gmail.com fail
i have error like this
and when i try to send email use telnet like tutorial on the above my opemdmarc not reject but sending emai to my mail server with success how to prevent this?
i have server mail behind sophos fw and i have two public ip, first for main domain as web server and the second for mail server. thank in advance
Hello,
I used this guide to set up OpenDMARC and OpenDKIM – and that part worked great! However, using iredmail, amavis is still performing its checks, even when the enable_dkim_verification is set to 0. Is there some way that amavis may be getting invoked by postfix or opendmarc/dkim?
I am trying to get all three values into the same authentication-results header to satisfy email client checking of messages.
Thanks!
Super super super helpful. Thank you!
So in combination with your tutorial for setting up SPF and DKIM: https://www.linuxbabe.com/mail-server/setting-up-dkim-and-spf
I think the OpenDMARC milter gets called before policyd-spf, because I’m seeing the “Authentication-Results: OpenDMARC; spf=pass” line as well as the “Received-SPF” header in my emails.
Is there a way to do SPF checking *before* OpenDMARC, so that my SPF checker isn’t redundant?
Thanks a lot!!! Very nice tutorial!