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 records, 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 the 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 allow you to detect email spoofing and help legitimate emails deliver into the recipient’s inbox instead of the spam folder. If your domain is abused by email spoofing, then your emails are likely to land in the recipient’s spam folder if they didn’t add you to the 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


  • TXT indicates this is a TXT record.
  • Enter @ in the name field.
  • v=spf1 indicates this is an 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 untrustworthy. Possible alternatives are +all, -all, ?all, but they are rarely used.

-all means that emails sent from not-allowed hosts should be rejected, never to land in the recipient’s inbox or spam folder. I have seen it used by, but we generally don’t need such a strict policy.

Some folks might think that -all will be better as it will reject emails from untrusted hosts. Well, using -all in your SPF policy can cause your own emails to be rejected when the recipient has two SMTP servers and the main SMTP server goes offline, your emails will be temporarily stored on the backup SMTP server. When the main SMTP server comes back online, the email will be relayed from the backup SMTP server to the main SMTP server. Since you didn’t list the recipient’s backup SMTP server in your SPF policy, the email will be rejected by the recipient’s main SMTP server. So you should use ~all in your SPF policy.

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 box like below. (On Ubuntu, you need to install the bind9-dnsutils package in order to use dig command: sudo apt install bind9-dnsutils)

dig 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 the dmarcian SPF surveyor to 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/

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/

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 a restriction on incoming emails by rejecting unauthorized email and checking SPF record.

policyd-spf_time_limit = 3600
smtpd_recipient_restrictions =
   check_policy_service unix:private/policyd-spf

Save and close the file. Then restart Postfix.

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 and 20.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

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 the 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 address, then it should be signed with the private key identified by


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.

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.


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/

Generate keys using opendkim-genkey tool.

sudo opendkim-genkey -b 2048 -d -D /etc/opendkim/keys/ -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/

And change the permission, so only the opendkim user has read and write access to the file.

sudo chmod 600 /etc/opendkim/keys/

Publish Your Public Key in DNS Records

Display the public key

sudo cat /etc/opendkim/keys/

The string after the p parameter is the public key.

opendkim display public dkim record

In your 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 the key test in the next step will probably fail.

dkim record

Test DKIM Key

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

sudo opendkim-testkey -d -s default -vvv

If everything is OK, you will see Key OK in the command output.

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

Note that your DKIM record may need sometime to propagate to the Internet. Depending on the domain registrar you use, your DNS record might be propagated instantly, or it might take up to 24 hours to propagate. You can go to, enter default as the selector and enter your domain name to check DKIM record propagation.

If you see Key not secure in the command output, 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. There’s absolutely no need to worry about Key not secure. You can continue to follow this guide.

If you see the query timed out error, you need to comment out the following line in /etc/opendkim.conf file and restart opendkim.service.

TrustAnchorFile       /usr/share/dns/root.key

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 (Ubuntu 18.04)

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

or (Ubuntu 20.04)

Socket    local:/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

Save and close the file.

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




Change it to


opendkim socket

Save and close the file.

Next, we need to edit the Postfix main configuration file.

sudo nano /etc/postfix/

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 now 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 scalahosting

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 with your configuration. If you see the following message in the mail log,

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

you may want to check if the opendkim systemd service is actually running.

systemctl status opendkim

If opendkim is running and you still see the above error, you might need to edit the /etc/postfix/ file, change

 smtpd_milters = local:opendkim/opendkim.sock


 smtpd_milters = local:/opendkim/opendkim.sock

Then restart Postfix.

Your email server will also perform SPF and DKIM checks on the 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;; [email protected]; receiver=<UNKNOWN> 
	dkim=pass (2048-bit key; unprotected) [email protected] header.b="XWMRd2co";

Testing Email Score and Placement

You can also go to 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 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 scalahosting

The Struggle with Microsoft Mailboxes

In my test, the email landed in my Gmail inbox. However, it’s stilled labeled as spam in my email although both SPF and DKIM are passed. Microsoft seems to be using an internal blacklist that blocks 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: 7 effective tips to stop your emails from 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.


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: 76 Average: 4.7]

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

  • Natasha Stellar
    5 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: -> DKIM PASS
    [email protected] -> [email protected] -> [email protected] DKIM FAIL


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

  • Ajay Krishna Teja Kavuri
    3 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 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
    3 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

  • Joseph Alvini
    3 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 -s default -vvv it tells me that ‘’ 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: ~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/, line 56: overriding earlier entry: smtpsmtpd_milters=local:/var/spool/postfix/opendkim/opendkim.sock
    sendmail: warning: /etc/postfix/, line 57: overriding earlier entry: non_non_smtpd_milters=local:/var/run/opendkim/opendkim.sock
    postdrop: warning: /etc/postfix/, line 56: overriding earlier entry: smtpsmtpd_milters=local:/var/spool/postfix/opendkim/opendkim.sock
    postdrop: warning: /etc/postfix/, 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
    3 years ago

    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 (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:

           dkim=pass [email protected] header.s=default header.b=b6ARK37a;
    • 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

  • Hi.
    The log file didn’t gave me much useful information.
    The following guide works for me:
    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
    3 years 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

    ; DKIM policy record            IN     TXT    "o=!;"
    ; DKIM public key record      IN     TXT	"v=DKIM1;k=rsa" "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv/ZySexJFmPRz6d8QbRymsNi77yKUACoHevdTSltOhqSHo9YpgjxLA" "52fVm+3jQ3CIn8Z2vxDAclHEFOhnEKE/YnZaAge6BmjhgfdrtyuionhgUmH2hWqRbZeVUl4X36C4XHxvcKUroURxBKwPw474ma" "TrLubDdFq76fXmodhsgsTgBhYYThHJn47odgLynG5uo/LjoBzw8ygqRD6R41jS8ZwMKdovC5rEnoQ+w1PZK6g4rlas4si6yyZN" "bgqmjH4geSCPpfWvuBbjFn0qV79cOttSrpdIiI/3Hceod0GN8sOIUhgtRtghUjhE5yxwyhZix1sfFmNgWHwIDAQAB"
  • 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.

  • 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áň
    3 years ago

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

    Thanks for the nice tutorial.

  • Mike Lerley
    3 years 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
    3 years ago

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

    smtpd_recipient_restrictions =
       check_policy_service unix:private/policyd-spf


    smtpd_recipient_restrictions = 
      check_policy_service unix:private/policyd-spf

    otherwise SMTP clients will fail.

    • John Howard
      3 years 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!!!

  • David B
    3 years ago

    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.

    SOCKET="inet:[email protected]"


    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 -s 20190319 -vvv
    opendkim-testkey: using default configfile /etc/opendkim.conf
    opendkim-testkey: checking key ''
    opendkim-testkey: '' 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 with key in /etc/dkimkeys/dkim.key using
    # selector '2007' (e.g.
    #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 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 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
    • I can find the DKIM record of your domain without any problems, using the dig utility.

       dig TXT

      Maybe you need to comment out the following line in /etc/opendkim.conf file.

      TrustAnchorFile       /usr/share/dns/root.key
  • Yeah, that’s what’s so frustrating. The problem is opendkim-testkey times out.

    [email protected]:/etc# opendkim-testkey -d -s 20190319 -vvv
    opendkim-testkey: using default configfile /etc/opendkim.conf
    opendkim-testkey: checking key ‘’
    opendkim-testkey: ‘’ 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.

    • The important thing is that your domain can pass DKIM check and your email server can perform DKIM check on sender’s domain.
      Maybe you need to comment out the following line in /etc/opendkim.conf file.

      TrustAnchorFile       /usr/share/dns/root.key
  • John Howard
    3 years ago


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

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

    my is check_policy_service unix:private/policyd-spf


    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
    3 years ago

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


    • Please check the /var/log/mail.log file after sending out an email.

    • The problem is with adding the public key as a TXT record in DNS.
      For the public key generated with opendkim-genkey, you need to remove all the double quotes and generate a single line record.

      The single line looks should look like this (remove double quotes and other fields)
      # Valid DKIM

      For me, Gmail validates DKIM: ‘PASS’ with domain
      However, any MX check for DKIM fails.

      An email I sent to an Office365 account has the DKIM signature:
      DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple;;
      s=default; t=1621183584;

      • I have already said in the article that “You need to delete all double quotes and white spaces”.

        I don’t know what you mean by the following sentence.

        “For me, Gmail validates DKIM: ‘PASS’ with domain However, any MX check for DKIM fails.”

  • Mahendra Mahajan
    3 years 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=,[]: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
    DKIM: ‘FAIL’ with domain

    3 years ago

    Awesome tutorial.

    I’ve written a self-contained tutorial on SPF/DKIM/DMARC implementation a while ago. Feel free to check it out:

  • Sebastien
    3 years ago

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

  • Netcore
    2 years ago

    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
    2 years ago

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

    DNS record(s): PTR (NXDOMAIN)

    Could you give me some trouble shooting guide or hint?

  • Changhoon
    2 years ago

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

  • Denison
    2 years ago

    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"

    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:

  • Still 5 star rated! As excellent as previous part 1 and part 2. Continue learning next part. Many thanks.

  • Mårten Behm
    2 years ago


    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 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] does not allow your server 88.888.888.888 to use [email protected]


    What we retained as your current SPF record is:

    v=spf1 mx ~allv=spf1 mx ~all

    More information about this error: 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 years ago

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

    I think I found a typo on /etc/postfix/ 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 years 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
    2 years ago

    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.

  • Yikes… I got as far as testing the key and got the following:

    opendkim-testkey: tag without value at end of key data

    Google searches are finding nothing with opendkim-testkey: “tag without value at end of key data”

    any ideas?

    • I figured it out. I was copying ONLY the information after the P=, and not the v=DKIM, etc.

  • Norbert
    2 years ago

    Hi Team,

    First of all, this postfix guide is the best I’ve ever found on the web. Clear, informative and the best thing is that it is workink as described.

    So my question is regarding an SPF issue. I’ve implemented the SPF checks and it is working fine. However some domains i.e.,, are rejected by postfix.

    Here are a few logs….

    550 5.7.23 : Recipient address rejected: Message rejected due to: SPF fail – not authorized. Please see;[email protected];ip=;r=; from= to= proto=ESMTP helo=

    550 5.7.23 : Recipient address rejected: Message rejected due to: SPF fail – not authorized. Please see;;ip=;r=; from= to= proto=ESMTP helo=

    Is there a way to whitelist some domains? Or what can be the solution for this?

    Thanks in advanced!

    • is a private IP address. Why are you receving Amazon and outlook emails from this address?

      • Norbert
        2 years ago

        My system is a bit complicated. Basically my server is sitting at home. I cannot have a static public IP here. So I’m hosting a MikroTIK EC2 instance and all my email flow is routed through a VPN tunnel. So the is my VPN IP. I need to do like this because of the STATIC IP issue with my ISP.

        • Norbert
          2 years ago

          All other emails are flowing smoothly without any problem at all. i.e. I can receive emails from other domains i.e. yours arriving perfectly.
          Now I disabled the service by the time and the hotmail emails started to flow in.
          Do you think this is related to the private IP what postfix can see?

    • Yes. That’s the problem. You should not relay emails from VPN gateway to your mail server. Instead, you should set up a mail proxy so that your mail server can see the SMTP client’s real IP address.

      I think I will write about how to set up mail proxy in the following days.

      • Norbert
        2 years ago

        Yes, I was suspecting that as well. I keep you following with that proxy setup. #donationisontheway
        Thanks (^-^)

    • Hi Norbert,

      I just published a tutorial for setting up SMTP and IMAP proxy:

  • Ubuntu 18.04-
    I followed the tutorial and got no errors, seemed like everything should be fine, but outgoing emails did not have dkim keys included.
    After much searching, I discovered, in /var/log/syslog this error:

    Starting OpenDKIM DomainKeys Identified Mail (DKIM) Milter...
    Mar 27 14:51:48 saleem systemd[1]: opendkim.service: Can't open PID file /var/run/opendkim/ (yet?) after start: No such file or directory
    Mar 27 14:51:48 saleem opendkim[21079]: OpenDKIM Filter v2.11.0 starting (args: -x /etc/opendkim.conf)

    Again, after much searching I solved the problem with this answer:
    Namely, editing /lib/systemd/system/opendkim.service and removing the line:


    Hope this helps someone else.

    • Oh my god, I had been stuck on that for the past week to no avail. You might be a stranger but I am exceptionally grateful to you for posting this solution. I needed this to work as part of my penultimate year project in uni, and you are such a saviour<3 Thank you x1000

  • Thanks again – Got through this part too. There were 1 main part I stumbled on here. So I am sharing if other people stumble in the same place.

    Putting the DKIM public key into my DNS. (I am with OVH).
    Formatting the Output from the:
    sudo cat /etc/opendkim/keys/ command, its output tries to be helpful and splitting it up into 3 small parts. In short, you only really need two.

    Trying to follow the author’s instructions, it becomes unhelpful. The author’s instructions, quite rightly, help you compile back up to one TXT string – however for my provider this was too long (An Error)
    In short I had to… edit a text version…. of the DNS file and …apply the DKIM over two lines
    this is what it looks like:

    Line one: default._domainkey IN TXT (“part one of the code in quotes”
    Line two: “second part with bracket at end after quote”).

    This worked for me.

    • ivan006
      1 year ago

      how on earth did u “edit a text version…. of the DNS file and”?

  • Thank you for the excellent tutorial! Worked like a charm!

    I do have a question in relation to DKIM when it comes to multiple domains… what needs to be changed to accomodate sending and receiving for multiple domains on the same postfix server ?

    Any help is greatly appreciated!

  • Bernhard Hensler
    2 years ago

    Always a good sign if the comment section is longer than the post itself ; ) – excellent article, thanks for that.
    A short remark: For AWS Route53 the DNS entry “ must be split into separate strings with a single space in between, eg. “v=DKIM1;k=rsa;” “…MIIBIjAN…” “…qhkiG9w0BA…”.

  • Florian
    2 years ago

    Great Tutorial, thanks a lot!
    I am not sure what this command actually checks for:

    sudo opendkim-testkey -d -s default -vvv

    I forgot do delete some spaces in the DNS TXT entry and the check with gmail failed. However this command said “Key ok”

  • Nolan Tenpas
    2 years ago

    I do not think opendkim-genkey generates the correct type of key.
    I was seeing DKIM failures with my key on Gmail and other email checking services.
    I discovered that opendkim-genkey generates a key that is NOT of type “RSAPublicKey”.
    This type is required for DKIM checks to pass.

    I was able to generate a proper “RSAPublicKey” DKIM key using the following commands:
    # Creating DKIM private key of type RSAPublicKey (aka OpenSSL PEM format)
    sudo ssh-keygen -b 2048 -t rsa -m PKCS8 -f ./default.private
    # Turning private key into DKIM p= field (public key)
    sudo ssh-keygen -y -e -m PKCS8 -f ./default.private

    Don’t forget to ‘chown’ the new default.private file:
    sudo chown opendkim:opendkim /etc/opendkim/keys//default.private

    Set your “P=” data in your DNS DKIM entry to the public key generated by the second command.
    This resulted in passing DKIM status on Gmail and other email checkers.

    Please let me know if this helps anyone!

    • ivan006
      1 year ago

      I’m not sure this is neccersary :/ but im not sure i had major dkim problems and almost killed a village of inocents in my rage but now its working fine for god knows what reason

  • William Matheson
    2 years ago

    Good day, what if for some reason you wanted a setup where your outgoing messages were DKIM-signed, like what seems to be happening here, but you also wanted to:

    1) Accept messages from domains not using DKIM
    2) If the domain is using DKIM, and the key check fails, don’t deliver the message

    Where are such policies specified?

    • 1) OpenDKIM won’t reject emails not signed with DKIM.

      2.) It’s not ideal to reject emails just because the DKIM check fails. DKIM is more commonly used in conjunction with SPF to form a DMARC policy, which you can use to reject emails that fail DMARC verification.

      To understand how DMARC works, read this article: Creating DMARC Record to Protect Your Domain Name From Email Spoofing

      To reject emails that fail DMARC verification, read this article: Set Up OpenDMARC with Postfix on Ubuntu to Block Email Spoofing/Spam

      • William Matheson
        2 years ago

        Thanks very much for the clarification. I had it conceptualized as all three having commonly used implementations for either direction, that each had separate implementations. But DKIM appears to be a one-stop-shop. Also, perhaps the fact that SPF has policy led me to expect that DKIM had its own in-protocol policy component as well. I did go ahead and set up DMARC for incoming, following your latter article.

  • SPF: PASS with IP Learn more
    DKIM: ‘FAIL’ with domain Learn more
    DMARC: ‘PASS’ Learn more

    Still getting DKIM failed from gmail…

    • Nolan Tenpas
      2 years ago

      Hi Sameer,

      Check out my comment from a couple weeks ago.
      You might need to generate different DKIM keys (public and private) using the commands I mentioned.
      This fixed my errors.
      opendkim-genkey seems to not generate the proper key.

  • Mariusz
    2 years ago

    Hello everyone,

    I’ve set up DKIM and passed with ‘sudo opendkim-testkey -d -s default -vvv’ but everytime I send an email there is no DKIM signature, it says it’s missing, is there something else I should be doing?

  • Guy Merritt
    2 years ago

    This is really odd. I installed this awhile ago, and I don’t recall changing anything. I didn’t have this problem, before. I have spamassassin installed, as well – I read, somewhere that, for reasons I didn’t understand, this could cause the problem I am seeing. For some reason, when I check my mail server on this site you suggested it now deducts two points from my score because it says I have two DKIM records. I have no idea why this would be happening. If you have any thoughts, I’d love to hear them.

  • Ron Jones
    1 year ago

    Another awesome tutorial in the bag! Like the first three chapters, it worked like you’d tested it extensively 😉

    While I know you already know this…. I’ve been through the DKIM cat & cut & paste exercise a few times before. If there is any suggestion I could offer, it is this:

    Make sure to point out in simple terms (i.e. “break it down Romper Room style”) that… when you issue the ‘sudo cat /etc/opendkim/keys//default.txt’ command… it’s a good idea to copy and paste it into a text file, maximize that text document, and remove all the quotation marks.

    When the key is longer than a certain number of characters (2048?) it is spit out as two separate long blocks of character strings. You’ve got to remove the quotes, and drop it as a single block of text into your TXT entry.

    You *did* mention it in passing. But some folks are going to miss it, and either put two quoted blocks in the content box at their DNS provider… OR… they’ll try and make two entries. (ask me how I know 😉 )

    Great work! On to chapter 5.

  • Hello everyone,

    I have created DKIM at SMTP server and its getting passed when tested from local server.
    Now we are are using same SMTP configurations for a server and sender is allowed at SMTP. Its saying DKIM=none.
    Sender address is [email protected] Is it because we used top level domain(your-domain) to create DKIM and now sender at server is

  • Daevid Vincent
    1 year ago

    THANK YOU FOR THIS! I have been running my own Linux server for years and recently (past few years) email has been a real problem with delivery to other sites. The last straw when Gmail started blocking my server. I finally got around to trying this and got it all working! You made it easy to copy/paste and just get on with my life and not have to become an SME on all these things.

  • Hi!
    I got the key, seems to be there. But when testing it, it says: key not secure. Someone told me that: ” It is an expected consequence of not using DNSSSEC”:

    opendkim-testkey: using default configfile /etc/opendkim.conf
    opendkim-testkey: checking key ''
    opendkim-testkey: key not secure
    opendkim-testkey: key OK

    Is this normal? Am I missing something?


  • ivan006
    1 year ago

    are we meant to add both the obscure strings to the DNS record (Publish Your Public Key in DNS Records section) ?
    v=DKIM1; k=rsa; p=obscureString1 obscureString2

    • ivan006
      1 year ago

      i ask cause im getting “key not secure” maybe this is due to propagation delay or maybe its a misunderstanding regarding the fact that there’s 2 obscure strings or maybe its due to that fact that im using ubuntu 16.04 (would that be a problem?)

    • ivan006
      1 year ago

      after perusing every single comment on this thread i am a wiser man.
      the problem is that im not getting a DKIM pass from gmail.
      It might be a propagation issue :/ (as suggested by

    • As I have said in this article, when you test the DKIM key, if you see “Key OK” in the command output, your DKIM record is correct.

      If you see “Key not secure” in the command output, this is because DNSSEC isn’t enabled on your domain name. There’s absolutely no need to worry about “Key not secure”.

      • ivan006
        1 year ago

        DKIM is the bane of my existance but for some reason its working now so thanks the lordy lord

        • ivan006
          1 year ago

          and thank you dear! the angel of my existence!

  • I’ve followed your previous tutorials for setting up Postfix and Dovecot which have work perfectly. I’ve done the SPF section in this article which I have working properly. I’ve followed the DKIM instructions, opendkim and postfix are running without errors. When I send an email to any of the test sites I always see DKIM check: none.

    Running on Ubunto 18.

    At a loss, looked through all logs for any errors. Not seeing any information as to what’s happening. Even looked for ways to debug what’s happening, with no luck. Any ideas on what to even look for?

    • Add the following lines in /etc/opendkim.conf file to produce more verbose logs.

      LogWhy    yes

      Save and close the file. Restart OpenDKIM.

      sudo systemctl restart opendkim

      Now OpenDKIM will produce more verbose logs in /var/log/mail.log file.

      • Kevin Hanrahan
        1 year ago

        I’m having the same issue. I’ve got Ubuntu 20.04. I’ve followed everything, checked it multiple times, added the LogWhy, and still no errors indicated but still DKIM=none and the the checker site says not signing. opendkim is running.

        At a loss, too.

        • Kevin Hanrahan
          1 year ago

          So, after some exchange with Xiao, I ended up deleting the socket and the directory. Then I recreated them. Turns out I got my lines confuses and improperly labeled the socket. Once I deleted the directory and did it all again, that is check the configs and rebuilt the socket, worked perfectly.


        • Kevin Hanrahan
          1 year ago

          One more thing…I found in my efforts to troubleshoot this that the key.table shouldn’t have refile: at the start as the guide suggests. It has to do with how the domains are listed. When they are all on one line, you don’t use the refile. the signing.table file, since it has the wildcard, does require refile. So it would look like this:

          # Map domains in From addresses to keys used to sign messages
          KeyTable           /etc/opendkim/key.table
          SigningTable       refile:/etc/opendkim/signing.table
  • Mohamed Elkebir
    1 year ago

    Thank you for the great tutorials you are giving us with super details 🙂

    I have a question: The steps above about DKIM. Do I have to repeat it for every domain that I use in postfix admin or just the domain of the mail server?

    I mean something like this:

  • Great article! I ran into problems when I generated the 2048-bit default._domainkey, since my domain registrar did not allow for such long TXT records. It took me a long time to figure this out. However, after generating a 1024-bit key everything worked.

  • Paul Colling
    1 year ago

    I have followed this guide to send and receive email but I have 2 problems

    1. When sending an email to gmail -> I get a red icon saying – the sender did not encrypt this message

    2. When receiving email, I get the mail when I type the mail command in the linux box. But I am not receiving it in outlook (I am sending and receiving) from outlook.

    Problem 1 is more important as I want that users to see a green icon – instead of red.


    • Have you followed part 2 to enable TLS in Postfix and Dovecot? Add the following two lines in /etc/postfix/ file to enable TLS when Postfix sends outgoing emails.

      smtp_tls_security_level = may
      smtp_tls_loglevel = 1

      To enable encryption when Postfix receives emails, add the following two lines.

      smtpd_tls_security_level = may
      smtpd_tls_loglevel = 1

      Restart Postfix

      sudo systemctl restart postfix

      Check your mail log (/var/log/mail.log) to debug outlook issues.

  • peacecop kalmer:
    1 year ago

    I tested with and got a score of 1.2 and a saying that my mail nevers sees a mailbox: “SpamAssassin” scores -5.8 and identification -3. The mail still landed in Gmail’s inbox not junk folder for the first time.

  • Jerre Cope
    1 year ago

    my DMARC reports I receive all PASS the DKIM and SPF tests–except for the report from
    Same ip address, same domain–always fails the DKIM check. Have you ever encountered that?
    google, yahoo, verizon all pass.
    Excellent guides by the way 🙂

  • Hello!
    About SPF options:

    Never use: ~all – > it softfail and does nothing.
    Use: -all -> Block/DROP if someone wants to f..k with UR domain

    • Actually, Using -all in your SPF policy can cause your own emails to be rejected. I never use -all.

      The standard way to block forged emails is to use DMARC.

      Yes, an SPF policy with ~all does nothing. But its power comes into play when SPF is used together with DKIM to form a DMARC policy.

    1 year ago

    I have an error. This is my default._domainkey. What’s wrong Xiao?

    • IMRON HS
      1 year ago
      [email protected]:/home/xen# sudo opendkim-testkey -d -s default -vvv
      opendkim-testkey: using default configfile /etc/opendkim.conf
      opendkim-testkey: checking key ''
      opendkim-testkey: '' query timed out
    • Maybe you need to wait some time for your DKIM record to propagate to the Internet.

  • Daniel
    1 year ago

    I followed all your guides from DMARC and SPF / DKIM and its the best linux tutorials I ever seen… They are extremely easy to follow and I will buy you a beer for it! THANKS!

    Two recommendations…
    1. For the SPF DNS entries, if you use relay servers which my ISP require, the DNS, record you need to add those servers to the TXT record.
    2. In the SPF guide, you write simply to add a new “smtpd_recipient_restrictions =” at the end of the main.conf file. If you already have this in your main, I got warnings “warning: /etc/postfix/, line 123: overriding earlier entry: smtpd_recipient_restrictions=” in my logs until i merged the entries…

    Anyway, thanks a million!

  • Sandor
    1 year ago

    Hi xaoi. first off your guides are some of the best ive ever seen and mostly work without a hitch.

    But after i followed this guide i got it to work flawlessly with mail-tester on my main domain but when i duplicate it for the files for key/signing and hosts my first domain remains working but when i try to do it with my second the email doesnt even get sent.

    i generated the keys for both domains. updated the dns(also using the bind9 guide you provided) to include the TXT record then used this link to verify the dkim key is updated to the current one.

    Then finally when im done and i run my phpmailer script -> in SSH and while my first domain( works great my second domain ( doesnt even send email. I tested it with mail-tester and it never got it.

    What did i miss?

    • Always check your mail log (/var/log/mail.log) and Dovecot log (sudo journalctl -eu dovecot) to troubleshoot mail server problems.

  • George
    1 year ago

    This is a great article and is extremely help full.
    I managed to configure the sever as per the instruction and the DMARC ones as well.

    On final testing all seems good on the google original email but I do see an error like this :

    "Sender is not authorized by default to use '[email protected]' in 'mfrom' identity, however domain is not currently prepared for false failures (mechanism '~all' matched)"

    Dio you know how to fix this?
    My server is Ubuntu 20.04 with postfix/devcoat/spamassing and i alos have install iredmail admin.

    • If you installed iRedMail, you don’t need to follow this SPF/DKIM tutorial.

      The error is probably because you use an email address that hasn’t been created in iRedAdmin.

  • George
    1 year ago


    Thank you for the quick reply.
    All email accounts are created from within the iRedMail admin web page.

    I did this for a learning, and it helped.

    A side question do you know I can configure the the mail to act as a relay ONLY for all my all my internal servers, internal networks, I use about 4 different IP ranges.

    Currently each ubuntu server is acting as it’s own mail releay, this does work, but I would prefere to have one relay server, rather then 4.

  • Loving this whole series. This is my first time setting up a personal email server and this series has walked me through it. It is designed for the simple person that has a small knowledge of computers. There are a few things I have had to change for my setup but worked through them. The biggest issue I have faced so far was getting DKIM to pass. Working on it across two days I finally ended up having to regenerate my key and come to find out my original attempt had gotten messed up somehow. Now it works beautifully.

  • Thomas
    1 year ago

    Thanks for this article.
    Very nice and easy to follow.
    Great job.


  • Ritvik
    1 year ago

    I am not able to receive mails from otherwise it working fine. port 25 is blocked on my machine so i have smtp relay setup, and so the dkim and spf records.
    So do i need to follow this tutorial. and why am i not retrieving any mails

    • Possible causes of not receiving email

      1. Your MX record is wrong.
      2. Your mail server hostname doesn’t have DNS A record.
      3. Your firewall doesn’t allow incoming connection to port 25.
      4. Postfix isn’t listening on the public IP address.
      5. Check the mail log (/var/log/mail.log) and Dovecot log (sudo journalctl -eu dovecot) to find out if there are other errors in your configuration

      SMTP relay service will only add DKIM signature to your outgoing emails. They can not verifiy DKIM signatures of incoming emails. So you still need to follow this tutorial to set up SPF and OpenDKIM.

  • Krzysztof
    11 months ago

    Hi. Very nice tutorial.
    When I send email by mail command to my gmail account I recive email from [email protected] but if I use sendmail it is [email protected] Why so?

  • Michael Wallenius
    10 months ago


    This is one of Internet’s best tutorials! Thanks!

    I have done everything, double checked and tested. Everything improves and I get a 9/10 score from BUT it marks DKIM as not configured. But the tests made locally seems fine, then meaning that opendkim-testkey seems fine.

    My test through mail says “Your mail is not signed with DKIM”. SPF is just fina and passes with distinction 😉

    Any ideas?

    Kind regards

  • Hey there,

    thanks for this great tutorial. Everything works fine until I’ve tested my configuration with
    Mail-Tester says I have two DKIM signatures in my message. The only difference is the timestamp. One signature has 1611058629 and the other has 1611058628. How is this possible?

  • Thanks for the tutorials.
    I had to use a key of 1024 for dkim, every time I paste in a 2048 bit txt it would get changed on the vps providers web interface somehow. It was incredibly frustrating so if anybody else may have that issue too. I can pass dkim and set up dmarc now.

    your the best teacher and thx

  • To correctly setup dkim i needed to change the following based on the anwser to
    in /etc/opendkim.conf
    from KeyTable refile:/etc/opendkim/key.table to KeyTable /etc/opendkim/key.table

    in /etc/opendkim/key.table

  • Hello Xiao Guoan;

    Thanks for all your great tutorials. Just a technical question. I was unable to find clarification on the net regarding “receiver=<UNKNOWN>”. Just curious to know what it is. Thanks.

    Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=;; [email protected]; receiver=<UNKNOWN>
  • Hello, thanks for this great tutorial! I’m at the DKIM key test steps, and opendkim-testkey gives the result “unexpected reply class/type” for my domain. Any ideas here?

    • After a little more digging through syslog and other routes, I found this error was because DNS was resolving the domain inside my network (an NXDOMAIN error in syslog). Straightened out my DNS and voila! Figured I’d post back here in case anybody else ran in to something like this.

      • I am having the same issue. How did you straighten out your DNS. I am showing everything is good through my DNS service unless there is something I missed somewhere.

        • Johnny
          6 months ago

          It was actually the local DNS resolver on my network not resolving the domain to the local IP instead of public IP.

      • I’m having the exact same issue, but still do not fully understand what you are saying, even your post below this. What exactly did you do to solve this? Im running a router behind my ISP router. Could it have something to do with that, or is this a server related issue? Please help!

    • I’m having the exact same issue, but still do not fully understand what you are saying, even your post below this. What exactly did you do to solve this? Im running a router behind my ISP router. Could it have something to do with that, or is this a server related issue? Please help!

    8 months ago

    When I try my Mail server with:

    I have score 10/10, but has message:

    Your message does not contain a List-Unsubscribe header

    How to fix it Xiao? Thank you..

    • is designed for newsletter senders. If you don’t send newsletter, you don’t need the list-unsubscriber header.

      • IMRON HS
        8 months ago

        Ok thank you Xiao Guoan, what about:

        -0.001	SPF_HELO_NONE	SPF: HELO does not publish an SPF Record

        That’s no problem? How to fix it? Thanks

  • I need help. my DKIM comes back as failed when I email my google account. I have no errors or warnings in my log.
    I have made a new Key pair and it is still failing. I have compared the key in the default.txt to what I have in my DNS entry and they match. So have no idea of what could be happening.

    Do you have any insight?

  • I have gotten to the testing of the DKIM but it always fails. I use Google DNS and when I the key I removed all white space and double-quotes. Google adds double quotes and splits the key as it is too long. But now in the DKIM record checker it is still recording that there is white space. I am unsure if it is because of the way Google DNS splits it or if there is anything else I could do to change it and remove any whitespace. Thank you.

  • Padi Tetteh
    7 months ago

    Right after setting up DKIM by following every bit of the tutorial, i attempted to send a mail using roundcube mail to my gmail as a test.
    I got the following error “SMTP Error: [451] 4.7.1 Service unavailable – try again later” and my emails werent being sent at all

    I then removed with “gpasswd -d postfix opendkim”
    Now emails go through but with a Softfail for SPF and Fail for DKIM.

    I know this guide has worked for many and there are many more knowledgeable people on linuxbabe. Any help please?

  • Thanks for such a great tutorial, I do have a question, but when I attempt to run the opendkim-testkey, I get a response that the key is missing, but I have followed the steps as written up until the point of testing. Any idea why this would be?

  • I can not get dkim to work. I did find that when I check the status of opendkim I get this error: opendkim[3709]: 71DF42413F: signing table references unknown key ‘default._domainkey.example>

    Any ideas?

    • After some more research there is an issue where there can be a carriage return character stuck in the signing.table file. After removing this it is working though I still have no DKIM tag when I send test email. It shows working fine with SPF thought.

  • Thanks, this is a great guide, and very clearly explained. Everything worked perfectly.

    gmail is still marking my emails as spam 🙁 But not because of DKIM.

    I’ll have a look at some of your other articles. Thanks very much

  • I can no longer get OpenDKIM to stay running. On checking logs I find that it fails with error “opendkim[6595]: can’t configure DKIM library: failed to set nameserver list”. Any ideas from anyone on how to fix this?

  • Hello. Congratulations on the excellent series of articles. I have a problem. After configuring SPF and DKIM I no longer receive emails, but I can send normally. Would you help me?

  • Is there a way to sign all outgoing mail, but never verify incoming mail? `ExternalIgnoreList` apparently doesn’t do it. The mail is still processed, and a `Authentication-Results` header is added, only with “unprotected” for key, so that doesn’t help. I want Postfix to completely ignore incoming DKIM headers, but still always sign outgoing. Possible? Can’t find on

  • Also a big thanks (and a beer) for Xiao Guoan!

    Another remark to warn others…
    In the construction of the DKIM record I also first managed to screw up the removal of the white space.
    The strange thing was that:
    sudo opendkim-testkey -d -s default -vvv
    would report the key as OK…
    did not.
    So carefully check your work for this step!

  • Henk van der Waard
    5 months ago

    Hi Xiao,

    Real fan of your linux guides however now unfortunately run in to the following problem:
    I ran though this without tutorial problems but the the smtpd milter is used by Spamassassin as well ( as per another tutorial from you)

    so my mail log now shows the following error:

    "warning: /etc/postfix/, line 68: overriding earlier entry: smtpd_milters=local:opendkim/opendkim.sock"

    The Milter is configured in postfix as follows:

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

    This bit is very similar as the Spamassissin-Postfix config so I combined the two? mayby not the way to go?

    Obviously the opendkim socket now is overridden and does not work and Spamaassasin socket does still work. Is there a way to combine the two or am I at the complete wrong end of the stick?

    Keep up the great work!

    Thank you,

    • Use multiple milters on one line.

      smtpd_milters = local:opendkim/opendkim.sock, local:spamass/spamass.sock
      • Henk van der Waard
        5 months ago

        That actually worked. It’s now working! (After I changed the folder/file permissions to the key files, silly me, der!)
        All great now, thanks again!

  • peacecop kalmer:
    5 months ago

    A friend told me that a mail sent from my mail server via my “Nextcloud” instance had landed in his spam folder. So I sent a test mail from my mail server to my Gmail account and saw the following error message:

    spf=softfail ( domain of transitioning [email protected] does not designate 2001:7d0:4ec0:3480:7a2b:cbff:fe17:7595 as permitted sender) [email protected];

    That IP address is the inner IP address, not the public IP address. The corresponding SPF-record for on my hosting provider is:

    v=spf1 ip4: ~all

    I can’t change it to have “ip6”-address as I get the following error message in “cPanel”:

    Error: The request failed. (Error ID: ea842v) Ask your hosting provider to research this error in cPanel & WHM’s main error log.

    What’s the solution?

    • If you can’t add IPv6 address in your SPF record, you can disable IPv6 in Postfix to prevent unnecessary IPv6 connections. Simply run the following command to disable IPv6 in Postfix.

      sudo postconf -e "inet_protocols = ipv4"

      Then restart Postfix.

      sudo systemctl restart postfix

      From now on, Postfix will use only IPv4 address.

      • peacecop kalmer:
        5 months ago

        Thanks for your quick reply! Your suggestion works:

        spf=pass ( domain of [email protected] designates as permitted sender) [email protected];

        I’ve also got a suggestion from my hosting provider to write the sixth level IP address in SPF record as a range because it could be dynamic and not accessible otherwise.

  • Wojciech
    4 months ago

    Current Ubuntu (21.04) require little modification of trusted.hosts: removing asterisk from the front of domain:

    works – with asterisk I got error: not internal

    Anyway – great tutorial!


    Thank you so much, I am very new to email services and I understood everything from this tutorial. I could even set my own mail server in 3 hours thanks to you.

    I am seriously grateful. I’ve been trying to set something that actually works for over a month now and your tutorial was a lifesaver!!!

  • Hi, Thanks. Just a tiny quibble about the use of “local:” in “smtpd_milters = local:pathname” ( It should really be “unix:” rather than “local:”. It does work, for obscure reasons that are not worth mentioning, and they are exactly identical on Linux, but the “local:” syntax is completely absent from Postfix documentation (except in relation to local_transport which is very different and has nothing to do with UNIX domain sockets). Only “inet:” and “unix:” are documented (see MILTER_README and SMTPD_POLICY_README). The “local:” prefix is the correct documented syntax for /etc/opendkim.conf, but it doesn’t agree with Postfix documentation.

  • hi. very good series for mail configurations. i have problem with yahoo and gmail. they block all my emails. by this article gmail unblock me but yahoo steel not receive my emails.
    Thank you very much.excelent.

  • Gael Lafond
    2 months ago

    Ubuntu 20.04. I follow the guide but I’m getting this error in /var/log/mail.log: key data is not secure: opendkim is in group 131 which has multiple users (e.g., "postfix")
    4C6A8C55A8: error loading key ''

    Is it possible that OpenDKIM is more restrictive on Ubuntu 20.04? I will try to remove “opendkim” group from “postfix” user tomorrow, but I have a feeling that will have consequences elsewhere which will be hard to fix…

    • Gael Lafond
      2 months ago

      I fixed my issue by adding the following directive to /etc/opendkim.conf

      RequireSafeKeys       false

      It’s probably not the best approach, but that will have to do for now.

    • change the permission, so only the opendkim user has read and write access to the private key file.

      sudo chmod 600 /etc/opendkim/keys/
      • Gael Lafond
        2 months ago

        Thanks Xiao. That’s the first thing I did, but that didn’t help. The error message was still coming up. I also changed the access rights of the folder containing the key but the message was still coming up. I may give it another try. Maybe I didn’t restart the service properly or something.

  • Tahir Jamil
    2 months ago

    Hi, just perfect. Everything works fine for me.
    Now I want my email server to send emails on behalf of my another domain, just like the Mailchimp and Sendgrid do. How can I configure this? What DNS entries should I add in my another domain?

  • Did someone know the cause of “unexpected reply class/type” error?

    [email protected]:~# opendkim-testkey -d -s default -vvv
    opendkim-testkey: using default configfile /etc/opendkim.conf
    opendkim-testkey: checking key ‘’
    opendkim-testkey: ‘’ unexpected reply class/type (-1/-1)
    [email protected]:~#

    Results on about my domain says “seems to be a valid DKIM record”

  • Imraan
    3 days ago

    Your tutorials are the best!! Thanks for your time and work on this, mail servers can be confusing.

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 ( 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