Part 4: How to Set up SPF and DKIM with Postfix on Ubuntu Server

After completing part 1 and part 2, we have a working Postfix SMTP server and Dovecot IMAP server. We can send and receive email using a desktop email client. Although I have correct MX, A and PTR record, my emails were flagged as spam by Gmail and Outlook mail. So in this part, we are going to look at how to improve email delivery to recipient’s inbox by setting up SPF and DKIM on Ubuntu server.

What are SPF and DKIM Records?

SPF and DKIM are two types of TXT records in DNS that can help prevent email spoofing and ensure legitimate emails are delivered into the recipient’s inbox instead of spam folder. If your domain is abused by email spoofing, then your emails are likely to landed in recipient’s spam folder if they didn’t add you in address book.

SPF (Sender Policy Framework) record specifies which hosts or IP addresses are allowed to send emails on behalf of a domain. You should allow only your own email server or your ISP’s server to send emails for your domain.

DKIM (DomainKeys Identified Mail) uses a private key to add a signature to emails sent from your domain. Receiving SMTP servers verify the signature by using the corresponding public key, which is published in your DNS manager.

Create an SPF Record in DNS

In your DNS management interface, create a new TXT record like below.

TXT  @   v=spf1 mx ~all

create spf record in DNS

Explanation:

  • TXT indicates this is a TXT record.
  • Enter @ in the name field.
  • v=spf1 indicates this is a SPF record and the SPF record version is SPF1.
  • mx means all hosts listed in the MX records are allowed to send emails for your domain and all other hosts are disallowed.
  • ~all indicates that emails from your domain should only come from hosts specified in the SPF record. Emails that are from other hosts will be flagged as forged. Possible alternatives are +all, -all, ?all, but they are rarely used.

Note that some DNS managers require you to wrap the SPF record with quotes like below.

TXT  @   "v=spf1 mx ~all"

To check if your SPF record is propagated to the public Internet, you can use the dig utility on your Linux machine like below:

dig your-domain.com txt

The txt option tells dig that we only want to query TXT records.

use dig utility to query spf record

You can also use online SPF validator such as spf.myisp.ch to see which hosts are allowed to send emails for your domain and debug your SPF record if any error occurs. The dmarcian SPF surveyor can help test your SPF record syntax.

Configuring SPF Policy Agent

We also need to tell our Postfix SMTP server to check for SPF record of incoming emails. This doesn’t help ensure outgoing email delivery but help with detecting forged incoming emails.

First install required packages:

sudo apt install postfix-policyd-spf-python

Then edit the Postfix master process configuration file.

sudo nano /etc/postfix/master.cf

Add the following lines at the end of the file, which tells Postfix to start the SPF policy daemon when it’s starting itself.

policyd-spf  unix  -       n       n       -       0       spawn
    user=policyd-spf argv=/usr/bin/policyd-spf

Save and close the file. Next, edit Postfix main configuration file.

sudo nano /etc/postfix/main.cf

Append the following lines at the end of the file. The first line specifies the Postfix policy agent timeout setting. The following lines will impose restriction on incoming emails by rejecting unauthorized email and checking SPF record.

policyd-spf_time_limit = 3600
smtpd_recipient_restrictions =
   permit_mynetworks,
   permit_sasl_authenticated,
   reject_unauth_destination,
   check_policy_service unix:private/policyd-spf

Save and close the file. Then restart Postfix.

sudo service postfix restart

or

sudo systemctl restart postfix

Next time, when you receive an email from a domain that has an SPF record, you can see the SPF check results in the raw email header. The following header indicates the sender sent the email from an authorized host.

Received-SPF: Pass (sender SPF authorized).

Setting up DKIM

First install OpenDKIM which is an open source implementation of the DKIM sender authentication system.

sudo apt install opendkim opendkim-tools

Then add postfix user to opendkim group.

sudo gpasswd -a postfix opendkim

Edit OpenDKIM main configuration file.

sudo nano /etc/opendkim.conf

Uncomment the following lines. Replace simple with relaxed/simple.

Canonicalization   simple
Mode               sv
SubDomains         no

Then add the following lines below #ADSPAction continue line. If your file doesn’t have #ADSPAction continue line, then just add them below SubDomains  no.

AutoRestart         yes
AutoRestartRate     10/1M
Background          yes
DNSTimeout          5
SignatureAlgorithm  rsa-sha256

Add the following lines at the end of this file. (Note that On Ubuntu 18.04, the UserID is already set to opendkim)

#OpenDKIM user
# Remember to add user postfix to group opendkim
UserID             opendkim

# Map domains in From addresses to keys used to sign messages
KeyTable           refile:/etc/opendkim/key.table
SigningTable       refile:/etc/opendkim/signing.table

# Hosts to ignore when verifying signatures
ExternalIgnoreList  /etc/opendkim/trusted.hosts

# A set of internal hosts whose mail should be signed
InternalHosts       /etc/opendkim/trusted.hosts

The final configuration file is as follows:

# This is a basic configuration that can easily be adapted to suit a standard
# installation. For more advanced options, see opendkim.conf(5) and/or
# /usr/share/doc/opendkim/examples/opendkim.conf.sample.

# Log to syslog
Syslog			yes
# Required to use local socket with MTAs that access the socket as a non-
# privileged user (e.g. Postfix)
UMask			002

# Sign for example.com with key in /etc/mail/dkim.key using
# selector '2007' (e.g. 2007._domainkey.example.com)
#Domain			example.com
#KeyFile		/etc/mail/dkim.key
#Selector		2007

# Commonly-used options; the commented-out versions show the defaults.
Canonicalization	relaxed/simple
Mode			sv
SubDomains		no
#ADSPAction             continue
AutoRestart     	yes
AutoRestartRate     	10/1M
Background      	yes
DNSTimeout      	5
SignatureAlgorithm  	rsa-sha256

# Always oversign From (sign using actual From and a null From to prevent
# malicious signatures header fields (From and/or others) between the signer
# and the verifier.  From is oversigned by default in the Debian pacakge
# because it is often the identity key used by reputation systems and thus
# somewhat security sensitive.
OversignHeaders		From

# List domains to use for RFC 6541 DKIM Authorized Third-Party Signatures
# (ATPS) (experimental)

#ATPSDomains		example.com

#OpenDKIM user
# Remember to add user postfix to group opendkim
UserID                 opendkim

# Map domains in From addresses to keys used to sign messages
KeyTable            refile:/etc/opendkim/key.table
SigningTable        refile:/etc/opendkim/signing.table

# Hosts to ignore when verifying signatures
ExternalIgnoreList  /etc/opendkim/trusted.hosts

# A set of internal hosts whose mail should be signed
InternalHosts /etc/opendkim/trusted.hosts

Save and close the file.

Create Signing Table, Key Table and Trusted Hosts File

Create a directory structure for OpenDKIM

sudo mkdir /etc/opendkim

sudo mkdir /etc/opendkim/keys

Change owner from root to opendkim and make sure only opendkim user can read and write to the keys directory.

sudo chown -R opendkim:opendkim /etc/opendkim

sudo chmod go-rw /etc/opendkim/keys

Create the signing table.

sudo nano /etc/opendkim/signing.table

Add this line to the file. This tells OpenDKIM that if a sender on your server is using a @your-domain.com address, then it should be signed with the private key identified by default._domainkey.your-domain.com.

*@your-domain.com    default._domainkey.your-domain.com

Save and close the file. Then create the key table.

sudo nano /etc/opendkim/key.table

Add the following line, which tells the location of the private key.

default._domainkey.your-domain.com     your-domain.com:default:/etc/opendkim/keys/your-domain.com/default.private

Save and close the file. Next, create the trusted hosts file.

sudo nano /etc/opendkim/trusted.hosts

Add the following lines to the newly created file. This tells OpenDKIM that if an email is coming from localhost or from the same domain, then OpenDKIM should not perform DKIM verification on the email.

127.0.0.1
localhost

*.your-domain.com

Save and close the file.

Generate Private/Public Keypair

Since DKIM is used to sign outgoing messages and verify incoming messages, we need to generate a private key for signing and a public key for remote verifier. Public key will be published in DNS.

Create a separate folder for the domain.

sudo mkdir /etc/opendkim/keys/your-domain.com

Generate keys using opendkim-genkey tool.

sudo opendkim-genkey -b 2048 -d your-domain.com -D /etc/opendkim/keys/your-domain.com -s default -v

The above command will create 2048 bits keys. -d (domain) specifies the domain. -D (directory) specifies the directory where the keys will be stored and we use default as the selector (-s), also known as the name. Once the command is executed, the private key will be written to default.private file and the public key will be written to default.txt file.

Make opendkim as the owner of the private key.

sudo chown opendkim:opendkim /etc/opendkim/keys/your-domain.com/default.private

Publish Your Public Key in DNS Records

Display the public key

sudo cat /etc/opendkim/keys/your-domain.com/default.txt

The string after the p parameter is the public key.

add dkim record

In you DNS manager, create a TXT record, enter default._domainkey in the name field. Then go back to the terminal window, copy everything in the parentheses and paste it into the value field of the DNS record. You need to delete all double quotes and white spaces in the value field. If you don’t delete them, then key test in the next step will fail.

dkim record

Test DKIM Key

Enter the following command on Ubuntu server to test your key.

sudo opendkim-testkey -d your-domain.com -s default -vvv

If everything is OK, you will see

opendkim-testkey: using default configfile /etc/opendkim.conf
opendkim-testkey: checking key 'default._domainkey.your-domain.com'
opendkim-testkey: key secure
opendkim-testkey: key OK

If you see “Key not secure”, don’t panic. This is because DNSSEC isn’t enabled on your domain name. DNSSEC is a security standard for secure DNS query. Most domain names haven’t enabled DNSSEC. You can continue to follow this guide.

Connect Postfix to OpenDKIM

Postfix can talk to OpenDKIM via a Unix socket file. The default socket file used by OpenDKIM is /var/run/opendkim/opendkim.sock, as shown in /etc/opendkim.conf file. But the postfix SMTP daemon shipped with Ubuntu runs in a 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 OpenDKIM Unix socket file.

Create a directory to hold the OpenDKIM socket file and allow only opendkim user and postfix group to access it.

sudo mkdir /var/spool/postfix/opendkim

sudo chown opendkim:postfix /var/spool/postfix/opendkim

Then edit the OpenDKIM main configuration file.

sudo nano /etc/opendkim.conf

Find the following line:

Socket local:/var/run/opendkim/opendkim.sock

Replace it with the following line. (If you can’t find the above line, then add the following line.)

Socket local:/var/spool/postfix/opendkim/opendkim.sock

If you can find the following line in /etc/default/opendkim file.

SOCKET="local:/var/run/opendkim/opendkim.sock"

or

SOCKET=local:$RUNDIR/opendkim.sock

Change it to

SOCKET="local:/var/spool/postfix/opendkim/opendkim.sock"

opendkim socket

Save and close the file.

Next, we need to 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.

# Milter configuration
milter_default_action = accept
milter_protocol = 6
smtpd_milters = local:opendkim/opendkim.sock
non_smtpd_milters = $smtpd_milters

Save and close the file. Then restart opendkim and postfix service.

sudo systemctl restart opendkim postfix

SPF and DKIM Check

You can also send a test email from your mail server to your Gmail account to see if SPF and DKIM checks are passed. On the right side of an opened email message in Gmail, if you click the show original button from the drop-down menu, you can see the authentication results.

Gmail SPF and DKIM check

If your message is not signed and DKIM check failed, you may want to check postfix log (/var/log/mail.log) to see what’s wrong in your configuration. If you see the following message in the mail log, you may want to check if the opendkim systemd service is actually running.

warning: connect to Milter service local:opendkim/opendkim.sock: No such file or directory

If opendkim is running and you still see the above error, you might need to change smtpd_milters = local:opendkim/opendkim.sock to smtpd_milters = local:/opendkim/opendkim.sock in /etc/postfix/main.cf file.

Your email server will also perform SPF and DKIM check on sender’s domain. You can see the results in the email headers. The following is SPF and DKIM check on a sender using Gmail.

Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=2607:f8b0:4864:20::c2d; helo=mail-yw1-xc2d.google.com; [email protected]; receiver=<UNKNOWN> 
Authentication-Results: email.linuxbabe.com;
	dkim=pass (2048-bit key; unprotected) header.d=gmail.com [email protected] header.b="XWMRd2co";
	dkim-atps=neutral

Testing Email Score and Placement

Now you can go to https://www.mail-tester.com. You will see a unique email address. Send an email from your domain to this address and then check your score. As you can see, I got a perfect score.

imporve email server reputation

Mail-tester.com can only show you a sender score. There’s another service called GlockApps that allow you to check if your email is placed in the recipient’s inbox or spam folder, or rejected outright. It supports many popular email providers like Gmail, Outlook, Hotmail, YahooMail, iCloud mail, etc

glockapps email placement test

The Struggle with Microsoft Mailboxes

In my test, the email landed in my Gmail inbox. However, it’s stilled labeled as spam in my outlook.com email although both SPF and DKIM are passed. Microsoft seems to be using an internal blacklist that block many legitimate IP addresses. If your emails are rejected by outlook or hotmail, you need to submit the sender information form. After that, your email will be accepted by outlook/hotmail, but may still be labeled as spam.

What if Your Emails Are Still Being Marked as Spam?

I have more tips for you in this article: How to stop your emails being marked as spam.

Next Step

In part 5, we will see how to create DMARC record to protect your domain from email spoofing. As always, if you found this post useful, please subscribe to our free newsletter or follow us on Twitter or like our Facebook page.

Note

In this article, I used umask 002 in the /etc/opendkim.conf file. A visitor commented below that this solved his problem. However, on Ubuntu 18.04 the default umask in /etc/opendkim.conf file is set to 007, which works fine on my production servers. The umask defines the permission of the OpenDKIM socket file (/var/spool/postfix/opendkim/opendkim.sock)

  • 002: Users not in the opendkim group have read and execute permission, but no write permission.
  • 007: Users not in the opendkim group have no read, write, or execute permission.

If I remember correctly, the umask 002 value is the default on Ubuntu 14.04 and 16.04, so I used it when I was writing this article for a Ubuntu 16.04 server.

If you added postfix user to the opendkim group, there should be no need to change the umask to 002.

sudo gpasswd -a postfix opendkim

I listed this command in the installing OpenDKIM section, but why some people don’t pay attention? I wonder.

Rate this tutorial
[Total: 62 Average: 4.6]

72 Responses to “Part 4: How to Set up SPF and DKIM with Postfix on Ubuntu Server

  • Natasha Stellar
    3 years ago

    Thanks for the guide!
    I have a forwarding/relay address and I’ve been trying to set up postsrsd, but for the life of me it still fails DKIM checks! Wondering if this series can be expanded to provide Sender Rewriting Scheme (SRS)?

    eg:
    mydomain.com -> gmail.com DKIM PASS
    [email protected] -> [email protected] -> [email protected] DKIM FAIL

    Cheers

  • this tutorial rocks! Got DKIM to work..finally!! …Thanks

  • Ajay Krishna Teja Kavuri
    2 years ago

    Great tutorial cheers!! I have followed all the instructions to setup opendkim on aws ubuntu 14.04. Now, I am using Route 53 for DNS records management. I got KEY OK as described in the tutorial. But I have my mail server pointing to mail.mydomain.com and I don’t see dkim=pass when I test my installation. What should I change to make it work for subdomains?

  • You might want to suggest to add to opendkm.conf
    LogWhy yes
    So it will print what the problem is. I spent several hours figuring out permissions issues.

  • Anne-Catherine AYE
    2 years ago

    I have a problem with the file sudo nano /etc/default/opendkim and i can’t check the DKIM
    This post saved me
    https://serverfault.com/a/847442/438721

  • Joseph Alvini
    2 years ago

    OK So I have a question. I followed everything step by step and even double and triple checked everything but every time I go to sudo opendkim-testkey -d your-domain.com -s default -vvv it tells me that ‘default._domainkey.MYDOMAIN.com’ record not found… Is there a reason its doing this and if so is there a way that I can uninstall and reinstall DKIM so that I can start over?

  • very Nice tutorial. Everything works fine for me but can I use the smtp variable on a mailer. Like gammadyne mailer

  • OpenDKIM Filter: Unable to bind to port local:/var/run/postfix/opendkim/opendkim.sock: No such file or directory

  • Thanks for this. FYI, after following this guide, my SPF checks failed with SOFTFAIL. I had to update the SPF TXT record with my server’s IP address in order to get the SPF check to pass. Example:
    v=spf1 mx ip4:11.22.33.44 ~all

  • Ubuntu 18.04 >>> No matter what config files i edited, the service couldn’t work with /var/spool/postfix/opendkim, so i manually created the folder /run/opendkim or /var/run/opendkim and gave it ownership permissions to opendkim user & group.

    The service started successfully, and the opendkim service created it’s PID in the created folder. Everything works normal now.

    • Never mind, please disregard my above post. It was a mistake done on my own end which resulted in the opendkim PID not working.

  • Hi.
    Thanks for this awesome guide.
    I have done my best to follow the guide, and I get the following error when I check the DKIM by sending a mail by using the following command:
    echo “test email” | sendmail [email protected]

     [email protected]
    sendmail: warning: /etc/postfix/main.cf, line 56: overriding earlier entry: smtpsmtpd_milters=local:/var/spool/postfix/opendkim/opendkim.sock
    sendmail: warning: /etc/postfix/main.cf, line 57: overriding earlier entry: non_non_smtpd_milters=local:/var/run/opendkim/opendkim.sock
    postdrop: warning: /etc/postfix/main.cf, line 56: overriding earlier entry: smtpsmtpd_milters=local:/var/spool/postfix/opendkim/opendkim.sock
    postdrop: warning: /etc/postfix/main.cf, line 57: overriding earlier entry: non_non_smtpd_milters=local:/var/run/opendkim/opendkim.sock
    

    The opendkim.sock is empty, and when I try to open it by using Nano, it creates an empty file like if it hasn’t been created. I have no idea on what I’ve messed up.
    I have even followed the guide twice to make sure I didn’t messed up anything, but I must have made a small mistake somewhere. Any idea on what I have done wrong?
    Best regards SLJ.

  • Hi.
    Thanks for your reply. That was exactly the issue. An other guide which didn’t worked told me to put in those lines at an other place in the file.

    I keep trying to get SPF and DKIM to work by following the guide, but i’m having the following problems which I have no idea on how to solve:

    1. As soon as I have configured the SPF on Postfix, the server won’t send any mails at all. I’m doing exactly all the steps which is explain the section: Configuring SPF Policy Agent.

    2. I thought I could avoid setting up SPF and just set up DKIM, but the same happens. Postfix restarts without any errors.
    When I test the DKIM by using the following command: echo “test email” | sendmail [email protected]
    I don’t get anything at all in the output. It’s just like doing a command which the console accepts without any comments or output.

    I’m running a Mailman server. I don’t know if that makes any difference.

    When testing the DKIM key, it says it’s not secure and then it says it’s okay. So I expect that part to be fine. But I don’t know why it says it’s not secure.
    Do you have any ideas on how to bug fix this, or any clue on what’s wrong?

  • But, as explained, the mailserver stops working both when I set up SPF on the server, and when I connect DKIM to Postfix. It doesn’t give me any errors, and no mails comes through Mailman.

  • Hi.
    Do you have any clue on why it won’t work for me? As soon as I set up SPF or DKIM, the Postfix mailserver stops working, and no mails comes through the mailinglists on the Mailman server. Any tips on how to bugfix on this is very much welcome.

  • Wojciech Jakubas
    1 year ago

    Hi,
    Thank you for this detailed tutorial.I have not used ubuntu but Raspian on Raspberry Pi 3B and it worked according to your instructions 🙂

    I have 3 observations:

    1. In one of your statement there is incorrect phrase “… end of this the file.” but you should really have “… end of this file.” or “… end of the file.”. Not both 😉

    2. When testing setting with email using command “echo “test email” | sendmail [email protected]” there is no ‘From’ option. This would mean that email it was sent from would be @your-domain.com (in my case it would be user ‘pi’) and when you do not have such account created, report would not be delivered. Is this correct?
    Maybe it will be worth adding i.e. “-aFrom:[email protected]”?
    Funny enough, I have not recived report even using that option with specified From value 🙁

    3. As per your suggestion, I have used Gmail to verify DKIM record and it looks very much correct, but it has landed in Spam folder anyway. I believe google use some other parameters to mark emails as spam.
    This is what I got in the headers from Gmail raw message:

    Authentication-Results: mx.google.com;
           dkim=pass [email protected] header.s=default header.b=b6ARK37a;
           spf=pass
    • 1. Thanks for pointing out the grammar error. Just fixed it.

      2. If there’s no From address, then Postfix will append the domain name to the username, so [email protected] is the From address and report will be sent to that address. You can use a command line mail client to see the report.

      If you are setting up a email server on a Raspberry Pi in your home, there’s a high chance that your ISP blocks port 25. Ask your ISP if
      that’s the case.

      3. Yes, there are other factors. You can test your email score at mail-tester.com

  • Hi.
    The log file didn’t gave me much useful information.
    The following guide works for me:
    https://mladenadamovic.wordpress.com/2018/01/17/how-to-install-and-configure-dkim-with-postfix-on-ubuntu-xenial-16-04-lts/
    Setting up SPF and DKIM this way does not crash my server. Not even if the DKIM key do not match. I managed to get it all working by following this guide.
    I’m not posting this to say that your guide is bad. It is really awesome, and gives a lot of great information. I’m posting the link to the other guide in case other people are having trouble on getting your guide to work. Maybe you will find it useful.
    Feel free to remove this comment if you don’t feel it fits here.

  • Superb tutorial. Tried many others and kept getting the configuration wrong. This time around it is working! Kudos mate, well done!

  • Nishant
    1 year ago

    Worked in first attempt, just be careful if you are using bind9, you need to craft the record and split the key. Use below example for bind9. (Do not remove ending dot(.) after your-domain.com

    ; DKIM policy record
    _domainkey.your-domain.com.            IN     TXT    "o=!;"
    ; DKIM public key record
    default._domainkey.your-domain.com.      IN     TXT	"v=DKIM1;k=rsa" "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv/ZySexJFmPRz6d8QbRymsNi77yKUACoHevdTSltOhqSHo9YpgjxLA" "52fVm+3jQ3CIn8Z2vxDAclHEFOhnEKE/YnZaAge6BmjhgfdrtyuionhgUmH2hWqRbZeVUl4X36C4XHxvcKUroURxBKwPw474ma" "TrLubDdFq76fXmodhsgsTgBhYYThHJn47odgLynG5uo/LjoBzw8ygqRD6R41jS8ZwMKdovC5rEnoQ+w1PZK6g4rlas4si6yyZN" "bgqmjH4geSCPpfWvuBbjFn0qV79cOttSrpdIiI/3Hceod0GN8sOIUhgtRtghUjhE5yxwyhZix1sfFmNgWHwIDAQAB"
  • gerard
    1 year ago

    Followed carefully, but I get this error in mail.log

    localhost postfix/smtpd[32756]: warning: connect to Milter service local:/opendkim/opendkim.sock: No such file or directory

    I’m on Ubuntu 12.04
    There wasn’t a line with Socket, so I added it
    Any suggestion on what I did wrong?

    • Ubuntu 12.04 is out of support cycle and I haven’t used openDKIM on 12.04. I suggest changing the socket file location in both /etc/default/opendkim and /etc/opendkim.conf file.

      Then restart openDKIM and Postfix, cd into /var/spool/postfix/opendkim/ directory to see if the opendkim.sock can be found. If not, it’s likely a permission problem.

  • gerard
    1 year ago

    Finally! I got it to work on by removing the first slash:

    smtpd_milters = local:opendkim/opendkim.sock

    instead of

    smtpd_milters = local:/opendkim/opendkim.sock

    Now the DKIM pass

  • Petr Šobáň
    1 year ago

    Díky za pěkný návod….

    Thanks for the nice tutorial.

  • Mike Lerley
    1 year ago

    This is an awesome guide. Worked perfectly for me. Thanks so much!

  • Hello great tutorial but i have two problems:

    1. When i am testing the configuration i got this message: “key not secure, key OK”. Why isn`t secure?
    2. Even if on mail-test i have 10/10, gmail is getting all my mails in spam. Any ideea?

    Thank you for your good job

  • polarise
    11 months ago

    After following your instructions everything was OK. The only part you would need to update is to extend the /etc/postfix/main.cf if one is using SASL:

    smtpd_recipient_restrictions =
       reject_unauth_destination,
       check_policy_service unix:private/policyd-spf
    

    to

    smtpd_recipient_restrictions = 
      permit_mynetworks 
      permit_sasl_authenticated 
      reject_unauth_destination 
      check_policy_service unix:private/policyd-spf
    

    otherwise SMTP clients will fail.

    • John Howard
      10 months ago

      Thank you so much for this comment.

      If you have a “reject: RCPT from” in your mail.log when using SMTP this fixes it.

  • Thank you for this AWESOME tutorial!!!

  • This is a really good tutorial, one of the best I’ve seen.

    I experienced the problem that some of my smtp processes were running in a chroot jail and others were not.

    This was easily fixed by using a network instead of file sockets.
    /etc/default/opendkim

    SOCKET="inet:[email protected]"

    /etc/postfix/main.cf

    smtpd_milters = inet:localhost:8891

    I now get 10/10, thanks so much for the tutorial!

  • Hi Thanks for the tutorial. I have been stuck on query timed out for days now. Tried specifying nameservers, turning off firewall. I search the logs and there is nothing. tail -f /var/log/syslog never shows anything happening when I run opendkim-testkey.

    [email protected]:/etc# opendkim-testkey -d mydomain.com -s 20190319 -vvv
    opendkim-testkey: using default configfile /etc/opendkim.conf
    opendkim-testkey: checking key '20190319._domainkey.mydomain.com'
    opendkim-testkey: '20190319._domainkey.mydomain.com' query timed out
    [email protected]:/etc#
    # This is a basic configuration that can easily be adapted to suit a standard
    # installation. For more advanced options, see opendkim.conf(5) and/or
    # /usr/share/doc/opendkim/examples/opendkim.conf.sample.
    
    # Log to syslog
    Syslog                  yes
    LogWhy  Yes
    # Required to use local socket with MTAs that access the socket as a non-
    # privileged user (e.g. Postfix)
    UMask                   002
    
    # Sign for example.com with key in /etc/dkimkeys/dkim.key using
    # selector '2007' (e.g. 2007._domainkey.example.com)
    #Domain                 example.com
    #KeyFile                /etc/dkimkeys/dkim.key
    #Selector               2007
    
    # Commonly-used options; the commented-out versions show the defaults.
    Canonicalization        relaxed/simple
    Mode                    sv
    SubDomains              no
    #ADSPAction             continue
    AutoRestart         yes
    AutoRestartRate     10/1M
    Background          yes
    DNSTimeout          5
    SignatureAlgorithm  rsa-sha256
    # Always oversign From (sign using actual From and a null From to prevent
    # malicious signatures header fields (From and/or others) between the signer
    # and the verifier.  From is oversigned by default in the Debian pacakge
    # because it is often the identity key used by reputation systems and thus
    # somewhat security sensitive.
    OversignHeaders         From
    
    ##  ResolverConfiguration filename
    ##      default (none)
    ##
    ##  Specifies a configuration file to be passed to the Unbound library that
    ##  performs DNS queries applying the DNSSEC protocol.  See the Unbound
    ##  documentation at http://unbound.net for the expected content of this file.
    ##  The results of using this and the TrustAnchorFile setting at the same
    ##  time are undefined.
    ##  In Debian, /etc/unbound/unbound.conf is shipped as part of the Suggested
    ##  unbound package
    
    # ResolverConfiguration     /etc/unbound/unbound.conf
    
    ##  TrustAnchorFile filename
    ##      default (none)
    ##
    ## Specifies a file from which trust anchor data should be read when doing
    ## DNS queries and applying the DNSSEC protocol.  See the Unbound documentation
    ## at http://unbound.net for the expected format of this file.
    
    TrustAnchorFile       /usr/share/dns/root.key
    
    #OpenDKIM user
    # Remember to add user postfix to group opendkim
    UserID             opendkim
    
    # Map domains in From addresses to keys used to sign messages
    KeyTable           /etc/opendkim/key.table
    SigningTable       refile:/etc/opendkim/signing.table
    
    # Hosts to ignore when verifying signatures
    ExternalIgnoreList  /etc/opendkim/trusted.hosts
    InternalHosts       /etc/opendkim/trusted.hosts
  • Yeah, that’s what’s so frustrating. The problem is opendkim-testkey times out.

    [email protected]:/etc# opendkim-testkey -d mydomain.com -s 20190319 -vvv
    opendkim-testkey: using default configfile /etc/opendkim.conf
    opendkim-testkey: checking key ‘20190319._domainkey.mydomain.com’
    opendkim-testkey: ‘20190319._domainkey.mydomain.com’ query timed out

    And with the dig command and in opendkim.conf you can specify the nameserver used. So I used the same dns nameserver for both.

  • John Howard
    10 months ago

    Hi,

    I get a “warning: connect to private/policyd-spf: No such file or directory”

    even though I can open /usr/bin/policyd-spf

    my main.cf is check_policy_service unix:private/policyd-spf

    and master.cf

    policyd-spf  unix  -       n       n       -       0       spawn
        user=policyd-spf argv=/usr/bin/policyd-spf
    • Check if file /var/spool/postfix/private/policyd-spf exists.

      • the file is not there for me. I get tthsi warning. Ubuntu 18

        /usr/bin/policyd-spf is there.

        I’m wondering what process is writing /var/spool/postfix/private/policyd-spf becuase the permissions for private are

        drwx—— 2 postfix root 4096 Oct 15 15:55 private

        where does user policyd-spf come in?

  • Mahendra Mahajan
    9 months ago

    Hi Have setup DLKIM and SPF and DMARC showing pass into Gmail but DKIM showing ‘FAIL’ with domain.

    Thanks
    Mahendra

  • Mahendra Mahajan
    9 months ago

    Hi Xiao,

    Thank you your reply.

    I have checked mail log and found email successfully send to destination email address below i have mention log and google email original message.

    Can you please check and help me out this.

    May 4 05:24:56 makeabetterday postfix/qmgr[18458]: 0E898100C16: from=, size=420, nrcpt=1 (queue active)
    May 4 05:24:56 makeabetterday postfix/smtp[18466]: 0E898100C16: to=, relay=gmail-smtp-in.l.google.com[74.125.195.27]:25, delay=0.48, delays=0.01/0.01/0.13/0.33, dsn=2.0.0, status=sent (250 2.0.0 OK 1556947496 r20si5523976pls.19 – gsmtp)
    May 4 05:24:56 makeabetterday postfix/qmgr[18458]: 0E898100C16: removed

    SPF: PASS with IP 52.26.165.93
    DKIM: ‘FAIL’ with domain makeabetterday.co.uk
    DMARC: ‘PASS’

  • Awesome tutorial.

    I’ve written a self-contained tutorial on SPF/DKIM/DMARC implementation a while ago. Feel free to check it out: https://dmarcly.com/blog/how-to-implement-dmarc-dkim-spf-to-stop-email-spoofing-phishing-the-definitive-guide.

  • Sebastien
    9 months ago

    In the /etc/postfix/main.cf, change unix:private/policyd-spf to unix:private/policy-spf

  • Excellent guide, thank you!

    Using this guide as of August 2019 on Ubuntu 18.04 (LTS) I found one issue with the opendkim socket permissions.

    I found that changing the UserID in opendkim.conf to opendkim:postfix resolved the issue for me.

  • Changhoon
    3 months ago

    Thanks for tutorial.
    I did everything on Ubuntu 18.04. And for now I have one error.
    The following msg is from verifier.port25.com
    ———————————————————-
    “iprev” check details:
    ———————————————————-
    Result: fail (reverse lookup failed (NXDOMAIN))
    ID(s) verified: policy.iprev=

    DNS record(s):
    x.x.x.x.in-addr.arpa. PTR (NXDOMAIN)

    Could you give me some trouble shooting guide or hint?

  • Changhoon
    3 months ago

    I found a resolution.
    My reverse domain does not be registered.

  • Hello
    Very nice tutorials
    Everything works as intended for me. but when am sending to gmail recipient my emals are going to the spam folder even though dkim and spf verification passed

  • I spent some time pondering the DKIM key to be added to the DNS.

    A full explanation was not given for this.

    The public key comes like:

    v=DKIM1; h=sha256; k=rsa; p="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvhVHwGH9fgTYFFF2I/RZpMqvOPxpYifgHSdSeiAUU5PIUV2ruihqPXxH4HxAcjiFg9jerVGi3hNhBhcinNOGylG5axCmcr1UinEtmxzUGyQD7NCvOomlrQdj5ewfrlbIWH9CfjaqBY4syUYFm0FAATkQnWimvVO+ge5ZVuIYyiesmjrvK+e4v/QtPCH6gJlMzEpTnbXo8+ahCq"
    	  "499b0jdq0686AnFrnnxhL+E7WjmXsZ+h4c2HCNtP6APUF7V3y9liqmGZAk8JLkxXmvRMcuay8awFWVhDKK7iEe473RXIYk9e/LJYIbbgyjYAGdYQdF1KGJisUdFP5QNYxayVt2lwIDAQAB"

    I was not sure if the second quoted part needs to be included, and if so how.

    It needs to be included as the same string, like:

    p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvhVHwGH9fgTYFFF2I/RZpMqvOPxpYifgHSdSeiAUU5PIUV2ruihqPXxH4HxAcjiFg9jerVGi3hNhBhcinNOGylG5axCmcr1UinEtmxzUGyQD7NCvOomlrQdj5ewfrlbIWH9CfjaqBY4syUYFm0FAATkQnWimvVO+ge5ZVuIYyiesmjrvK+e4v/QtPCH6gJlMzEpTnbXo8+ahCq"499b0jdq0686AnFrnnxhL+E7WjmXsZ+h4c2HCNtP6APUF7V3y9liqmGZAk8JLkxXmvRMcuay8awFWVhDKK7iEe473RXIYk9e/LJYIbbgyjYAGdYQdF1KGJisUdFP5QNYxayVt2lwIDAQAB
  • Still 5 star rated! As excellent as previous part 1 and part 2. Continue learning next part. Many thanks.

  • Great guide, thank you.

    just to follow ‘opendkim’ bad permission issue may it is good to mention that

    sudo usermod -a -G opendkim postfix

    really helps (mainly with umask 002).

  • Ralf Oertner
    2 months ago

    Hello!

    Thank you for your great how to.
    After checking everything a few times.
    I can’t fix the error:

    postfix/smtpd[27778]: error: unsupported dictionary type: local

    Iam running ubuntu 16.04

    Asking Google didn’t help – can you please help me?

    Thank you!

  • Mårten Behm
    2 months ago

    Hi,

    Thanks, I am so happy I got my email server to work! But I want it to work even better, and when I test in mail-tester.com I get minus three for “You are not allowed to use one of your sender email addresses”. More specifically, I get these comments (and some more below them):

    ————————————————————————————————————-
    [SPF] nnnn.link does not allow your server 88.888.888.888 to use [email protected]

    and

    What we retained as your current SPF record is:

    v=spf1 mx ~allv=spf1 mx ~all

    More information about this error:

    nnnn.link: Junk encountered in record ‘v=spf1 mx ~allv=spf1 mx ~all’
    ———————————————————————————————–

    Any clues as to what might be the matter?

  • Jérôme Texier
    2 weeks ago

    HI, thank you very much for very well documented tutorial series. Nice work !

    I think I found a typo on /etc/postfix/main.cf to allow postfix to connect to Milter service

    smtpd_milters = local:/opendkim/opendkim.sock

    should be :

    smtpd_milters = local:opendkim/opendkim.sock

    Without that I had a warning error on /var/log/mail.log and dkim wasn’t applied.

    postfix/submission/smtpd[22555]: warning: connect to Milter service local:/opendkim/opendkim.sock: Permission denied
    • After playing with Amavis, it turns out that

      smtpd_milters = local:/opendkim/opendkim.sock

      works with Postfix, Dovecot and OpenKIM. But if Postfix is integrated with Amavis or other software, then we probably need to use

      smtpd_milters = local:opendkim/opendkim.sock
      • Jérôme Texier
        2 days ago

        Hi Xiao,
        note that Amavis is not installed on my Ubuntu 18.04.03 server working with Postfix 3.3.0 & Opendkim (2.11.0~alpha-11) but I had to remove the starting / from smtp_milters path in order to connect to Milter service.

    • Ok. I think using smtpd_milters = local:opendkim/opendkim.sock as default is better.

  • Thank you for this extremely straightforward and simple tutorial. Allow me to add something I learned that wasn’t obvious when first processing through the tutorial:

    * If your Postfix is running as a relay for authenticated hosts, you must put the IP addresses of those hosts in the trusted.hosts file

  • Tony Turner
    6 seconds ago

    Xiao,
    Thank you for your tutorials. I’ve used several of them and they are well written and concise. I really appreciate you taking the time to explain the how’s and why’s of the thing you do instead of just a series of cut and paste commands… it makes it much easier to troubleshoot when you know how the pieces are put together. You my friend are a great teacher.

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.