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

Explanation:

  • 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 facebook.com, 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 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 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/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 a 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 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

Find the following line.

Syslog               yes

By default,  OpenDKIM logs will be saved in /var/log/mail.log file. Add the following line so OpenDKIM will generate more detailed logs for debugging.

Logwhy               yes

opendkim logwhy yes

Locate the following lines.

#Domain                 example.com
#KeyFile                /etc/dkimkeys/dkim.key
#Selector               2007

By default, they are commented out. Please don’t uncomment them.

Then, find the following lines. Uncomment them and 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

ubuntu opendkim canonicalization

Next, 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 the following two lines 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. The second line tells that your sub-domains will be signed by the private key as well.

*@your-domain.com    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 only sign the email but not perform DKIM verification on the email.

127.0.0.1
localhost

.your-domain.com

Save and close the file.

Note: You should not add an asterisk in the domain name like this: *.your-domain.com. There should be only a dot before the domain name.

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

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

sudo chmod 600 /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.

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 between 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 your-domain.com -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 'default._domainkey.your-domain.com'
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 https://www.dmarcanalyzer.com/dkim/dkim-check/, 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 22.04/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.

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

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

Postfix Can’t Connect to OpenDKIM

If your message is not signed and DKIM check failed, you can check postfix log (/var/log/mail.log) to see what’s wrong with your configuration. If you find the following error in the Postfix mail log (/var/log/mail.log),

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

you should check if the opendkim systemd service is actually running.

systemctl status opendkim

If opendkim is running and you still see the above error, it means Postfix can’t connect to OpenDKIM via the Unix domain socket (local:opendkim/opendkim.sock).

To fix this error, you can configure OpenDKIM to use TCP/IP socket instead of Unix domain socket. (Unix domain socket is usually faster than TCP/IP socket. If it doesn’t work on your server, then you should use TCP/IP socket.)

sudo nano /etc/opendkim.conf

Find the following line:

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

Replace it with

Socket     inet:[email protected]

So OpenDKIM will be listening on the 127.0.0.1:8892 TCP/IP socket. Save and close the file. Then edit Postfix main config file.

sudo nano /etc/postfix/main.cf

Find the following line:

smtpd_milters = local:opendkim/opendkim.sock

Replace it with:

smtpd_milters = inet:127.0.0.1:8892

So Postfix will connect to OpenDKIM via the TCP/IP socket. Restart OpenDKIM and Postfix.

sudo systemctl restart opendkim postfix

Checking the OpenDKIM Logs

Sometimes, the OpenDKIM journal logs may help you find out what’s wrong.

sudo journalctl -eu opendkim

Configuration Error in Email Client

DKIM signing could fail if you don’t use the correct SMTP/IMAP settings in your email client.

Correct Settings:

  • SMTP protocol: enter mail.your-domain.com as the server name, choose port 587 and STARTTLS. Choose normal password as the authentication method.
  • IMAP protocol: enter mail.your-domain.com as the server name, choose port 143 and STARTTLS. Choose normal password as the authentication method.

or

  • SMTP protocol: enter mail.your-domain.com as the server name, choose port 465 and SSL/TLS. Choose normal password as the authentication method.
  • IMAP protocol: enter mail.your-domain.com as the server name, choose port 993 and SSL/TLS. Choose normal password as the authentication method.

Wrong Settings:

  • Use port 25 as the SMTP port in mail clients to submit outgoing emails.
  • No encryption method was selected.

Port 25 should be used for SMTP server to SMTP server communication. Please don’t use it in your email client to submit outgoing emails.

You should select an encryption method (STARTTLS or SSL/TLS) in your email client.

Testing Email Score and Placement

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

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 uses an internal blacklist that blocks many legitimate IP addresses. If your emails are rejected by Outlook or Hotmail, you need to follow the tutorial linked below to bypass the Microsoft Outlook blacklist.

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.

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 and skip this command? I wonder.

Rate this tutorial
[Total: 105 Average: 4.8]

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

  • Natasha Stellar
    6 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]om -> [email protected] -> [email protected] DKIM FAIL

    Cheers

    • howardbarnes
      4 months ago

      This is a fine tutorial. However, I was unable to pass the dkim checks until I
      substituted a dash (-) for a tilde (~) in the spf record of my registrar. Any idea
      why this could be?

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

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

    • Xiao Guo An (Admin)
      3 years ago

      “Record not found” means that it can’t find your DKIM DNS record. DNS record can take some time to propagate to the Internet.

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

    • Xiao Guo-An (Admin)
      4 years ago

      You should ask them before buying their product.

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

    • Xiao Guo-An (Admin)
      4 years ago

      Hi, the socket should be local:/var/spool/postfix/opendkim/opendkim.sock

  • 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.

    • Xiao Guo-An (Admin)
      4 years ago

      Looks like you have duplicate configurations in /etc/postfix/main.cf file. Don’t worry about the content of opendkim.sock.

  • 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?

    • Xiao Guo-An (Admin)
      4 years ago

      You won’t see anything on the command line when you send a test email to [email protected] You will receive the report in your mailbox.

  • 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.

    • Xiao Guo-An (Admin)
      4 years ago

      You should take a look at Postfix log file (/var/log/mail.log). If SPF or DKIM is not working, you will see errors in that file.

  • Wojciech Jakubas
    4 years 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
    • Xiao Guo-An (Admin)
      4 years ago

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

    • Xiao Guo-An (Admin)
      4 years ago

      I think the only difference is that I use Unix domain docket. The article you followed uses TCP/IP socket.

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

  • Nishant
    4 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 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"
    • Xiao Guoan (Admin)
      2 years ago

      The DKIM record output by OpenDKIM is in BIND format.
      opendkim-key-bind-format
      If you run your own authoritative DNS server with BIND9, simply copy the entire DKIM record output by OpenDKIM, don’t delete anything, and paste it to your BIND zone file.

      The following screenshot shows an example DKIM record in a BIND zone file.
      DKIM-record-in-bind-zone-file

  • 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?

    • Xiao Guo-An (Admin)
      4 years ago

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

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

    Thanks for the nice tutorial.

  • Mike Lerley
    4 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

    • Xiao Guo An (Admin)
      3 years ago

      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.

      If your emails get into the spam folder, I have more tips for you in this article: How to stop your emails being marked as spam.

  • polarise
    4 years 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
      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
    4 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.
    /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
    • Xiao Guo An (Admin)
      4 years ago

      I can find the DKIM record of your domain without any problems, using the dig utility.

       dig TXT 20190319._domainkey.yourdomain.com

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

    • Xiao Guo An (Admin)
      4 years ago

      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

    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
    • Xiao Guo An (Admin)
      3 years ago

      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.

    Thanks
    Mahendra

    • Xiao Guo An (Admin)
      3 years ago

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

    • George
      1 year ago

      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
      v=DKIM1;p=KAABIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/fedRNEFQvCdtN0akUCMG686J7Kv7DfjP6CBNYbq0zppCF+gEnXmeRIAG1BNGtqE0DnpiOaePwXpuAC+izWHE4pBltSwczhTOz7dNHxQV3YmPs3pg12Zqm4ARuD9sCdJky/Tz+uPHUYp8GUuAJPOmqmg3lWw9AooPOYfJMLte5BeQ7KtSiyxirT5VfZdYj0VJXvvlIKT8X92OYWN8G0212XiFLyyQuxJixQL04BMG0bvBW8xrNDiNuiAkDGea/nUxKRMnuVKOvAa5JAhi/hNikCOP9NCibllwZLlS2E94bY9FVw+ymbBt0f4MMn/xxxxxxxxxxx

      For me, Gmail validates DKIM: ‘PASS’ with domain domain.co.uk
      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; d=domain.co.uk;
      s=default; t=1621183584;
      bh=NjeG3ZIwgH4wJjwmfOvaciQLFeNV4RmKNznppTYJ

      • Xiao Guoan (Admin)
        1 year ago

        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 domain.co.uk. 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=, 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’

    • Xiao Guo An (Admin)
      3 years ago

      If you can’t find DKIM errors in the mail.log file, check if your DKIM record is entered correctly in DNS.

  • DMARCLY
    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: https://dmarcly.com/blog/how-to-implement-dmarc-dkim-spf-to-stop-email-spoofing-phishing-the-definitive-guide.

  • Sebastien
    3 years ago

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

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

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

  • Denison
    3 years ago

    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
    • Xiao Guoan (Admin)
      3 years ago

      I think I have said in this article that you need to delete all double quotes and white spaces.

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

  • Mårten Behm
    3 years 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?

    • Xiao Guoan (Admin)
      3 years ago

      Your SPF record is incorrect. It should be v=spf1 mx ~all, not v=spf1 mx ~allv=spf1 mx ~all

  • Jérôme Texier
    3 years 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
    • Xiao Guoan (Admin)
      3 years ago

      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
        3 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.

    • Xiao Guoan (Admin)
      3 years ago

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

  • 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
    3 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. amazone.co.uk, hotmail.com, outlook.com 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 http://www.openspf.net/Why?s=mfrom;[email protected].co.uk;ip=10.10.10.251;r=; from= to= proto=ESMTP helo=

    550 5.7.23 : Recipient address rejected: Message rejected due to: SPF fail – not authorized. Please see http://www.openspf.net/Why?s=helo;id=eur04-vi1-obe.outbound.protection.outlook.com;ip=10.10.10.251;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!

    • Xiao Guoan (Admin)
      3 years ago

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

      • Norbert
        3 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 10.10.10.251 is my VPN IP. I need to do like this because of the STATIC IP issue with my ISP.

        • Norbert
          3 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?

    • Xiao Guoan (Admin)
      3 years ago

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

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

    • Xiao Guoan (Admin)
      3 years ago

      Hi Norbert,

      I just published a tutorial for setting up SMTP and IMAP proxy: https://www.linuxbabe.com/mail-server/smtp-imap-proxy-with-haproxy-debian-ubuntu-centos

  • 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/opendkim.pid (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:
    https://askubuntu.com/a/1117490/992232
    Namely, editing /lib/systemd/system/opendkim.service and removing the line:

    PIDFile=/var/run/opendkim/opendkim.pid

    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/your-domain.com/default.txt 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
      2 years 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 “default._domainkey.your-domain.com 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 your-domain.com -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!
    Thanks!

    • ivan006
      2 years 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
    and
    2) If the domain is using DKIM, and the key check fails, don’t deliver the message

    Where are such policies specified?

    • Xiao Guoan (Admin)
      2 years ago

      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 mydomain.com 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 your-domain.com -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
    2 years 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 @xyz.your-domain.com?

  • Daevid Vincent
    2 years 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 'default._domainkey.my-domain.com'
    opendkim-testkey: key not secure
    opendkim-testkey: key OK
    

    Is this normal? Am I missing something?

    THANKS

    • Xiao Guoan (Admin)
      2 years ago

      Yes, the key is not secure when your domain name is not using DNSSEC. You don’t have to worry about it.

  • ivan006
    2 years 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
      2 years 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
      2 years 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 mail-tester.com)

    • Xiao Guoan (Admin)
      2 years ago

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

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

        • ivan006
          2 years 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?

    • Xiao Guoan (Admin)
      2 years ago

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

          Thanks!

        • Kevin Hanrahan
          2 years 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
    2 years 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:

    *@your-domain.com    default._domainkey.your-domain.com
    *@your-other-domain.com    default._domainkey.your-other-domain.com
    
  • 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
    2 years ago

    Hi
    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.

    Thanks,

    • Xiao Guoan (Admin)
      2 years ago

      Have you followed part 2 to enable TLS in Postfix and Dovecot? Add the following two lines in /etc/postfix/main.cf 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:
    2 years ago

    I tested with Mail-tester.com and got a score of 1.2 and a saying that my mail nevers sees a mailbox: https://www.mail-tester.com/test-r31d18hwi&reloaded=1. “SpamAssassin” scores -5.8 and identification -3. The mail still landed in Gmail’s inbox not junk folder for the first time.

  • Jerre Cope
    2 years ago

    my DMARC reports I receive all PASS the DKIM and SPF tests–except for the report from att.net
    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

    • Xiao Guoan (Admin)
      2 years ago

      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.

  • IMRON HS
    2 years ago

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

    • IMRON HS
      2 years ago
      [email protected]:/home/xen# sudo opendkim-testkey -d vanhussen.net -s default -vvv
      opendkim-testkey: using default configfile /etc/opendkim.conf
      opendkim-testkey: checking key 'default._domainkey.vanhussen.net'
      opendkim-testkey: 'default._domainkey.vanhussen.net' query timed out
      
    • Xiao Guoan (Admin)
      2 years ago

      Maybe you need to wait some time for your DKIM record to propagate to the Internet.

  • PERFECT!
    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/main.cf, line 123: overriding earlier entry: smtpd_recipient_restrictions=” in my logs until i merged the entries…

    Anyway, thanks a million!

  • 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 https://dkimcore.org/c/keycheck to verify the dkim key is updated to the current one.

    Then finally when im done and i run my phpmailer script -> https://pastebin.com/fXuaLwQH in SSH and while my first domain(pihosting.ca) works great my second domain (truebud.ca) doesnt even send email. I tested it with mail-tester and it never got it.

    What did i miss?

    • Xiao Guoan (Admin)
      2 years ago

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

  • Hi,
    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.

    • Xiao Guoan (Admin)
      2 years ago

      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.

  • Hi,

    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.

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

    Cheers!

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

    • Xiao Guoan (Admin)
      2 years ago

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

    • Xiao Guoan (Admin)
      1 year ago

      To specify the FROM address, use the following syntax.

      mail -a FROM:[email protected] [email protected]

      The mail command is used only in part 1 to show you Postfix works. The remaining parts of this tutorial series assumes you want to use a graphical email client.

  • Illia Polianskyi
    2 years ago

    Hello dear support
    as I get by dig command my dkim record, nevertheless postfix is blocked by milter

    Dec 20 09:55:18 smtp opendkim[5202]: 900617E113E: error loading key 'default._domainkey.polanski.work'
    Dec 20 09:55:18 smtp postfix/cleanup[24334]: 900617E113E: milter-reject: END-OF-MESSAGE from unknown[178.165.47.83]: 4.7.1 Service unavailable - try again later; from=<[email protected]> to=<[email protected]> proto=ESMTP helo=
    
  • Illia Polianskyi
    2 years ago

    solved, thanks

  • Michael Wallenius
    2 years ago

    Hi!

    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 mail-tester.com. 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 tester.com says “Your mail is not signed with DKIM”. SPF is just fina and passes with distinction 😉

    Any ideas?

    Kind regards
    Michael

  • Hey there,

    thanks for this great tutorial. Everything works fine until I’ve tested my configuration with mail-tester.com
    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?

  • stephen
    2 years ago

    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

  • Falital
    2 years ago

    To correctly setup dkim i needed to change the following based on the anwser to https://serverfault.com/questions/861642/opendkim-not-signing-mail
    in /etc/opendkim.conf
    from KeyTable refile:/etc/opendkim/key.table to KeyTable /etc/opendkim/key.table

    in /etc/opendkim/key.table
    from
    default._domainkey.your-domain.com your-domain.com:default:/etc/opendkim/keys/your-domain.com/default.private
    to
    default._domainkey.your-domain.com your-domain.com:default:/etc/opendkim/keys/your-domain.com/default.private

  • 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=209.85.161.41; helo=mail-oo1-f41.google.com; [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
          1 year ago

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

      • Danran
        1 year ago

        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!

    • Danran
      1 year ago

      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!

  • IMRON HS
    2 years ago

    When I try my Mail server with:

    https://www.mail-tester.com
    

    I have score 10/10, but has message:

    Your message does not contain a List-Unsubscribe header
    

    How to fix it Xiao? Thank you..

    • Xiao Guoan (Admin)
      2 years ago

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

      • IMRON HS
        2 years 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 default._domainkey.davidsherer.us 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
    1 year 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?

    • Same problem here
      “SMTP Error: [451] 4.7.1 Service unavailable – try again later”
      Any idea?

  • Smitty
    1 year ago

    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?

    • Xiao Guoan (Admin)
      1 year ago

      Maybe you need to wait for the DKIM DNS record to propagate?

    • Xiao Guoan (Admin)
      1 year ago

      Have you tried to verify your DKIM record at https://www.dmarcanalyzer.com/dkim/dkim-check/ ? Enter default as the selector and enter your domain name to check if your DKIM record is correct.

      • Smitty
        1 year ago

        So it looks like the DNS entry was parsed strangely by my hosting provider, after copying it again and ensuring all random white space was removed, DKIM tests show that it is now a valid record. However, none of my outgoing mail seems to be signed. Messages are passing properly with SPF, but DKim doesn’t appear to be invoked at all.

  • I can not get dkim to work. I did find that when I check the status of opendkim I get this error:

    example.org 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.

  • Martyn
    1 year ago

    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?

    • Still had no luck with this and research has gotten me no where.

    • Xiao Guoan (Admin)
      1 year ago

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

      TrustAnchorFile       /usr/share/dns/root.key
      • Just checked and that line is already commented out.

    • Xiao Guoan (Admin)
      1 year ago

      If you use Nameserver in the /etc/opendkim.conf file, then it should be like this:

      Nameservers    8.8.8.8,1.1.1.1

      Separate each IP address with a comma.

  • 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?

    • Xiao Guoan (Admin)
      1 year ago

      Always check your mail log (/var/log/mail.log).

  • 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 https://wiki.archlinux.org/title/OpenDKIM

    • Xiao Guoan (Admin)
      1 year ago

      Change the mode from Mode sv to Mode s in /etc/opendkim.conf file.
      s: signing
      v: verification

  • 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 your-domain.com -s default -vvv
    would report the key as OK…
    But:
    https://www.dmarcanalyzer.com/dkim/dkim-checker
    did not.
    So carefully check your work for this step!

  • Henk van der Waard
    1 year 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/main.cf, line 68: overriding earlier entry: smtpd_milters=local:opendkim/opendkim.sock"

    The Milter is configured in postfix main.cf 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,
    Henk

    • Xiao Guoan (Admin)
      1 year ago

      Use multiple milters on one line.

      smtpd_milters = local:opendkim/opendkim.sock, local:spamass/spamass.sock
      • Henk van der Waard
        1 year 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!
        Henk

  • peacecop kalmer:
    1 year 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 (google.com: 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 test.tennis24.ee. on my hosting provider is:

    v=spf1 ip4:80.235.6.91 ~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?

    • Xiao Guoan (Admin)
      1 year ago

      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:
        1 year ago

        Thanks for your quick reply! Your suggestion works:

        spf=pass (google.com: domain of [email protected] designates 80.235.6.91 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
    1 year ago

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

    .your-domain.com

    works – with asterisk I got error:
    xxx.your-domain.com not internal

    Anyway – great tutorial!
    Thanks

  • Daniel
    1 year ago

    YOU ARE THE GREATEST MAN ALIVE!!!

    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” (main.cf). 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
    1 year ago

    Ubuntu 20.04. I follow the guide but I’m getting this error in /var/log/mail.log:

    default._domainkey.something.org.au: key data is not secure: opendkim is in group 131 which has multiple users (e.g., "postfix")
    4C6A8C55A8: error loading key 'default._domainkey.something.org.au'
    

    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
      1 year 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.

    • Xiao Guoan (Admin)
      1 year ago

      change the permission, so only the opendkim user has read and write access to the private key file. It works on my server.

      sudo chmod 600 /etc/opendkim/keys/something.org.au/default.private
      • Gael Lafond
        1 year 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
    1 year 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?
    Thanks

  • Adrian
    1 year ago

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

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

    Results on dmarcanalyzer.com about my domain says “seems to be a valid DKIM record”
    Thanks!

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

  • Hello Xiao,

    Thanks for the amazing tutorials series. I realize this is a lot of work to put together and saves us a lot of time.

    I have been following the steps you discussed in the tutorials. After completing the entire Part 3 of the tutorials, I was able to receive emails in Thunderbird email [email protected] from my Gmail accounts. After completing the steps on Part 4 of the tutorial series, I was not able to send emails to “[email protected]” nor receive emails from my Gmail accounts.

    I am hosting Django websites ( www.bambamboo.com, www.essentricswithgenevieve.com, www.liondancetoronto.ca ) and the email server on a single IP address. The hostname (bamboo-webserver) is different than the email domain name (essentricswithgenevieve.com).

    Here are some of the details:

    [email protected]:~$ dig -x 139.177.199.90
    
    ; <> DiG 9.16.1-Ubuntu <> -x 139.177.199.90
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 1137
    ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
    
    ;; OPT PSEUDOSECTION:
    ; EDNS: version: 0, flags:; udp: 65494
    ;; QUESTION SECTION:
    ;90.199.177.139.in-addr.arpa.   IN      PTR
    
    ;; ANSWER SECTION:
    90.199.177.139.in-addr.arpa. 0  IN      PTR     bamboo-webserver.
    
    ;; Query time: 0 msec
    ;; SERVER: 127.0.0.53#53(127.0.0.53)
    ;; WHEN: Thu Dec 02 19:51:06 UTC 2021
    ;; MSG SIZE  rcvd: 86
    

    Here is the messages from the log file:

    sudo nano /var/log/mail.log 
    Nov 30 21:45:29 bamboo-webserver postfix/submission/smtpd[3240]: connect from unknown[38.23.191.98]
    Nov 30 21:45:29 bamboo-webserver postfix/submission/smtpd[3240]: Anonymous TLS connection established from unknown[38.23.191.98]: TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature RSA>
    Nov 30 21:45:29 bamboo-webserver dovecot: auth: Debug: auth client connected (pid=0)
    Nov 30 21:45:29 bamboo-webserver dovecot: auth: Debug: client in: AUTH#0111#011PLAIN#011service=smtp#011nologin#011lip=139.177.199.90#011rip=38.23.191.98#011secured#011resp=AGtzemVAZXNzZW50cmljc3dpdGhnZW5ldmlldmUuY29tAGtzemUxMjM>
    Nov 30 21:45:29 bamboo-webserver dovecot: auth: Debug: sql([email protected],38.23.191.98): Performing passdb lookup
    Nov 30 21:45:29 bamboo-webserver dovecot: auth: Debug: sql([email protected],38.23.191.98): query: SELECT username AS user,password FROM mailbox WHERE username = '[email protected]' AND active='1'   
    Nov 30 21:45:29 bamboo-webserver dovecot: auth: Debug: sql([email protected],38.23.191.98): Finished passdb lookup
    Nov 30 21:45:29 bamboo-webserver dovecot: auth: Debug: auth([email protected],38.23.191.98): Auth request finished
    Nov 30 21:45:29 bamboo-webserver dovecot: auth: Debug: client passdb out: OK#0111#[email protected]#011
    Nov 30 21:45:29 bamboo-webserver postfix/proxymap[3241]: warning: pgsql query failed: fatal error from host localhost: ERROR:  operator does not exist: boolean = integer?LINE 1: ...'@', alias_domain.target_domain) AND alias.active = 1 AND al...?                                                             ^?HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.?>
    Nov 30 21:45:29 bamboo-webserver postfix/submission/smtpd[3240]: warning: proxy:pgsql:/etc/postfix/sql/pgsql_virtual_alias_domain_maps.cf lookup error for "[email protected]" 
    Nov 30 21:45:29 bamboo-webserver postfix/submission/smtpd[3240]: NOQUEUE: reject: RCPT from unknown[38.23.191.98]: 451 4.3.0 : Temporary lookup failure; from= to= proto=ESMTP helo=
    Nov 30 21:45:31 bamboo-webserver postfix/submission/smtpd[3240]: lost connection after RCPT from unknown[38.23.191.98]
    Nov 30 21:45:31 bamboo-webserver postfix/submission/smtpd[3240]: disconnect from unknown[38.23.191.98] ehlo=2 starttls=1 auth=1 mail=1 rcpt=0/1 commands=5/6
    Nov 30 21:45:31 bamboo-webserver postfix/submission/smtpd[3240]: lost connection after RCPT from unknown[38.23.191.98]
    Nov 30 21:45:31 bamboo-webserver postfix/submission/smtpd[3240]: disconnect from unknown[38.23.191.98] ehlo=2 starttls=1 auth=1 mail=1 rcpt=0/1 commands=5/6
    Nov 30 21:46:11 bamboo-webserver dovecot: auth: Debug: auth client connected (pid=3254)
    Nov 30 21:46:11 bamboo-webserver dovecot: auth: Debug: client in: AUTH#0111#011PLAIN#011service=imap#011secured=tls#011session=KARWfAjSovYmF79i#011lip=139.177.199.90#011rip=38.23.191.98#011lport=143#011rport=63138#011local_name=>Nov 30 21:46:11 bamboo-webserver dovecot: auth: Debug: client passdb out: CONT#0111#011
    Nov 30 21:46:11 bamboo-webserver dovecot: auth: Debug: client in: CONT#0111#011AGtzemVAZXNzZW50cmljc3dpdGhnZW5ldmlldmUuY29tAGtzemUxMjM= (previous base64 data may contain sensitive data)
    Nov 30 21:46:11 bamboo-webserver dovecot: auth: Debug: sql([email protected],38.23.191.98,): Performing passdb lookup
    Nov 30 21:46:11 bamboo-webserver dovecot: auth: Debug: sql([email protected],38.23.191.98,): query: SELECT username AS user,password FROM mailbox WHERE username = '[email protected]>Nov 30 21:46:11 bamboo-webserver dovecot: auth: Debug: sql([email protected],38.23.191.98,): Finished passdb lookup
    Nov 30 21:46:11 bamboo-webserver dovecot: auth: Debug: auth([email protected],38.23.191.98,): Auth request finished
    Nov 30 21:46:11 bamboo-webserver dovecot: auth: Debug: client passdb out: OK#0111#[email protected]#011
    Nov 30 21:46:11 bamboo-webserver dovecot: auth: Debug: master in: REQUEST#0112496659457#0113254#0111#011783451c6ef272712a5225c55ac9910f5#011session_pid=3265#011request_auth_token
    Nov 30 21:46:11 bamboo-webserver dovecot: auth: Debug: sql([email protected],38.23.191.98,): Performing userdb lookup
    Nov 30 21:46:11 bamboo-webserver dovecot: auth: Debug: sql([email protected],38.23.191.98,): SELECT maildir, 2000 AS uid, 2000 AS gid FROM mailbox WHERE username = '[email protected]>Nov 30 21:46:11 bamboo-webserver dovecot: auth: Debug: sql([email protected],38.23.191.98,): Finished userdb lookup
    Nov 30 21:46:11 bamboo-webserver dovecot: auth: Debug: master userdb out: USER#0112496659457#[email protected]#011maildir=essentricswithgenevieve.com/ksze/#011uid=2000#011gid=2000#011auth_token=e9b71f369b60c220>Nov 30 21:46:11 bamboo-webserver dovecot: imap-login: Login: user=, method=PLAIN, rip=38.23.191.98, lip=139.177.199.90, mpid=3265, TLS, session=
    Nov 30 21:48:51 bamboo-webserver postfix/anvil[3242]: statistics: max connection rate 1/60s for (submission:38.23.191.98) at Nov 30 21:45:29
    Nov 30 21:48:51 bamboo-webserver postfix/anvil[3242]: statistics: max connection count 1 for (submission:38.23.191.98) at Nov 30 21:45:29
    Nov 30 21:48:51 bamboo-webserver postfix/anvil[3242]: statistics: max cache size 1 at Nov 30 21:45:29
    Nov 30 21:50:20 bamboo-webserver postfix/smtpd[3296]: connect from unknown[43.131.94.145]
    Nov 30 21:50:22 bamboo-webserver postfix/smtpd[3296]: lost connection after CONNECT from unknown[43.131.94.145]
    Nov 30 21:50:22 bamboo-webserver postfix/smtpd[3296]: disconnect from unknown[43.131.94.145] commands=0/0
    
    

    Any ideas?

    Thanks,

    Kin

    • I resolved the issue. It turns out that the acceptable PostgreSQL is true/false. MySQL acceptable Boolean values are 1 or 0.

      For PostgreSQL:

      user = postfixadmin
      password = xxxx
      hosts = localhost
      dbname = postfixadmin
      query = SELECT maildir FROM mailbox WHERE username='%s' AND active = true
      

      For MySQL:

      user = postfixadmin
      password = xxxx
      hosts = localhost
      dbname = postfixadmin
      query = SELECT maildir FROM mailbox WHERE username='%s' AND active = 1
      
  • Phil Freihofner
    9 months ago

    I was fine until my first attempts to run the opendkim service. The readout:

    ● opendkim.service - OpenDKIM DomainKeys Identified Mail (DKIM) Milter
        Loaded: loaded (/lib/systemd/system/opendkim.service; enabled; vendor preset: enabled)
        Active: failed (Result: exit-code) since Sun 2022-01-02 00:36:07 PST; 32s ago
          Docs: man:opendkim(8)
                man:opendkim.conf(5)
                man:opendkim-genkey(8)
                man:opendkim-genzone(8)
                man:opendkim-testadsp(8)
                man:opendkim-testkey
                http://www.opendkim.org/docs.html
       Process: 145257 ExecStart=/usr/sbin/opendkim -x /etc/opendkim.conf (code=exited, status=78)
    
    Jan 02 00:36:07 ladonax systemd[1]: opendkim.service: Control process exited, code=exited, status=78/CONFIG
    Jan 02 00:36:07 ladonax systemd[1]: opendkim.service: Failed with result 'exit-code'.
    Jan 02 00:36:07 ladonax systemd[1]: Failed to start OpenDKIM DomainKeys Identified Mail (DKIM) Milter.
    Jan 02 00:36:07 ladonax systemd[1]: opendkim.service: Scheduled restart job, restart counter is at 5.
    Jan 02 00:36:07 ladonax systemd[1]: Stopped OpenDKIM DomainKeys Identified Mail (DKIM) Milter.
    Jan 02 00:36:07 ladonax systemd[1]: opendkim.service: Start request repeated too quickly.
    Jan 02 00:36:07 ladonax systemd[1]: opendkim.service: Failed with result 'exit-code'.
    Jan 02 00:36:07 ladonax systemd[1]: Failed to start OpenDKIM DomainKeys Identified Mail (DKIM) Milter.
    

    I include the error in case others have gotten this and are searching this thread for any of its contents. I noticed that this error message has come up a number of times on other forum sites, often including references to following this tutorial.

    In my case, the error turned out to be a typo. While using nano to edit */etc/opendkim.conf* I inadvertently deleted the very first char of the file (a “#”). I discovered that this was the source of the error when going back and running the following test anew.

    sudo opendkim-testkey -d adonax.com -s default -vvv

    This test had passed initially. But on the retry when I was going back, trying to locate my problem, it indicated the point of failure as the first line of *opendkim.conf*, which allowed me to find the typo.

    Now that this is fixed, the service runs successfully and all tests involving SPF and DKIM are passing.

    To recap, if the opendkim service fails to run, I recommend diving into the log for diagnostics and keeping an eye out for things like typos or mismatched permissions.

    It’s a tribute to the careful work that went into creating this tutorial that three years after its creation, it is still sound.

  • Inder Kochar
    9 months ago

    Hi Xiao,

    I would like to Thank you for the the step by step notes to setup email server. Guess what I finish setup email server in one day, yeah and I am new to Linux have no experience with that. I am now following your tutorial for all mail server and how to secure.
    As I said I have fully functional email server with Postfix/Dovecot/mariaDB/Nginx/SPF/Dmarc/Dkim/SSL/Roundcube.
    All working I can send/receive emails.
    I am using Ubuntu 20.04 on Virtual Machine. I did follow all steps you mentioned Step 1 to Step 4. Thank you.

    Today, I was setting up identities on roundcube webmail. and start getting error “Server Error!”Error No. [600].
    I did search on google but not getting much answer to fix this issue. Hope you can guide me.
    One more thing i am missing is the tutorial about how to change RoundCube default logo skin ?

    Once again Thank you.

    Yesterday, I was try to buy you a beer when I was successfully send and received email. Please specify paypal account on your page where one can send money. Other than bit-coin things.

  • Jabukiro
    8 months ago

    5 years later and this guide still works like a charm. Thank you for keeping it updated. Absolutely brilliant!

  • Took me couple of days to work it out but it did work. Got 9.5 score.

    Took me hours to realize that the SPF data for postfix goes in master.cf not main.cf. That bug gave me serious heartaches

  • Hello!

    First, thank you for this series. I have been following everything and had no issues until now. I ended with the postfixadmin steps and then went on to this part. In the previous part, I set up Thunderbird with my email and everything worked perfect. I continued with this and went through all the checks and all seemed to be okay. I validated all the records and I’m able to send email using sendmail to yahoo and google and it does not end up in spam.

    Now for the issue: Thunderbird will connect when linking my account however, it will not send an email. It keeps asking me to retry or update my password. However, it does receive emails… I’m confused as to what this issue could be. I reviewed the log and the only thing that looks like it could be an issue is the following:

    postfix/smtpd “disconnect from unknown[my home ip]”
    dovecot imap-login user method……
    dovecot imap(me) connection closed

    There were so many configuration files we went through so I’m just not sure where to even begin.

    On another note, what would I do in order to setup a subdomain email. In the previous tutorials we were using mail.your-website.com and now we use your-website.com. I have a case where I will want subdomains as hosts as well as my-domain. Is it as simple as replacing every instance of your-website.com with sub.youwebsite.com ?

    THANK YOU!!

    • Looks like it had nothing to do with my server configuration. The issue was with Thunderbirds configuration.

      In part 2, we were using local users unix sockets so my username was i.e., adam. This is how I tested originally with Thunderbird and everything worked fine.

      In part3, we created virtual mailboxes for users where username is defined by the email address or in my case i.e., [email protected]

      Simply changing my Thunderbird Outbound settings from adam to [email protected] fixed the issue. God I love this stuff( I really do).

      Hopefully this helps if someone else is facing a similar issue.

  • Stuart Clouston
    7 months ago

    Great tutorial! Works very well.
    The only issue I now have is that after implementing this solution, postfix is no longer logging to the /var/log/mail/* folder. All my SMTP logging is now appearing in /var/log/syslog.

    I’m running Ubuntu 20.04.3 LTS with postfix & rsyslog. Is this something I need to fix on the postfix side or the syslog side?

  • Stuart Clouston
    7 months ago

    Please disregard my earlier message.

    I had to upgrade my server in order to install openDKIM and the upgrade installed a new rsyslog config file which replaced my customised config file. All good now.

  • For the section “Publish Your Public Key in DNS Records”, where it says, “The string after the p parameter is the public key,” please mention that in the photo this string is broken up into two parts. Or, better yet, highlight the string you are referring to in the photo example itself. I initially had trouble with that part of the tutorial, because I thought where the closing quotation mark was was the end of the string you mentioned.

  • I have problem with the DKIM,
    When I send email to a gmail account I can’t see that the DKIM is with status pass. Checking the header message there is no DKIM at all.

    When I check locally with “sudo opendkim-testkey -d domain.net -s default -vvv” or mail-tester. dot com /spf-dkim-check I get all good or with mxtoolbox dot com . I created the records 2 days ago so they should be up to date.

    using Debian 10 & Cloudflare

  • Rolandow
    6 months ago

    For others that are using SPF, greylisting and a backup MX server: don’t forget to whitelist the IP of the backup MX server. You can do this by adding Whitelist = /32 to the config file that is located in /etc/postfix-policyd-spf-python.

    If you don’t do this, first the email could get bounced by the greylist. Then it goes to the next backup MX server. That backup MX server will retry to deliver the email to your server, but of course, from it’s own IP address. The SPF will FAIL because the IP of the backup MX server isn’t in the SPF config of that mail (which makes sense).

    I guess the Domain_Whitelist_PTR could also be used to specify the hostname.

    • Xiao Guoan (Admin)
      5 months ago

      I would not whitelist the IP address of the back MX server. If the sending domain deployed DMARC reject policy, an imposter could bypass DMARC reject policy because the email will always pass the SPF test.

      If you have a backup MX server, I recommend creating 3 MX records:

      Record Type    Name      Mail Server            Priority
      
      MX             @         mail.yourdomain.com     0
      MX             @         mail2.yourdomain.com    5
      MX             @         mail3.yourdomain.com    10
      

      Point mail.yourdomain.com and mail2.yourdomain.com to the same IP address. Point mail3.yourdomain.com to the IP address of the backup MX server.

      I also recommend setting up Postscreen.

      • Rolandow
        5 months ago

        I thought that if I add it to the postfix-policyd-spf-python config, it would only be whitelisted for SPF? But indeed, one could bypass the SPF check this way. I’m not sure what the best strategy is then. Would Postscreen be a solution for backup MX servers?

        In my case it seemed that my ISP is ending the support of backup MX, so it doesn’t work anyways. I will trust that any decent mail server will indeed resend the message as it’s supposed to.

    • Xiao Guoan (Admin)
      5 months ago

      “my ISP is ending the support of backup MX”? What does that mean? Are they going to block TCP port 25?

      The best strategy for a backup MX with greylisting is to create 3 MX records as I have already explained.
      You can enable and configure Postscreen on the primary mail server. It’s nice to have, but not a must.

      • Rolandow
        5 months ago

        I’m sorry that my message wasn’t clear. Normally I could use the mailserver from my VPS provider as a backup MX server; I’d give it a lower priority. When it receives mail for my domains, it would catch it, and try to delivery it to my own server a little while later. I contacted support to give me the IP addresses of their mail cluster, because the mail was rejected by my server because the SPF check failed. I thought I had fixed this by whitelisting their IP.

        Their reply was that they will stop support for this backup MX feature. Spammers could abuse this by directly delivering the spam to the backup MX server, and then their server would send it to my server. Basically exact what you were telling me, but then for DMARC.

        So eventually I had to remove their mail servers from my DNS entries. I now only have my own mail server, with no backup server that catches my mail in case my mailserver is down. But, if I understood correctly, the latest RFC’s for mailservers say that a mailserver should retry to deliver mails that bounced in the first attempt. This is important because I also installed the greylisting feature you described here. So I guess the backup MX technique is old nowadays, but I didn’t know this.

    • Xiao Guoan (Admin)
      5 months ago

      Yes, The SMTP protocol (RFC 2821) recommends that sending SMTP server should retry soft-bounced emails for at least 4-5 days. If you run a mail server on a cloud VPS, which typically has high uptime, you don’t have to run a backup MX.

  • Mo.Khateeb
    6 months ago

    So Based on your blog I cant use Cloudflare to set up my SMTP server that’s meaning I will lose DNS Propagation and it’s not good
    So, have a solution to set up an SMTP server without avoiding DNS Propagation?

    • Xiao Guoan (Admin)
      6 months ago

      I’m not saying you can’t use Cloudflare. I mean you should not enable the proxy feature in Cloudflare for your mail server hostname (mail.example.com).

      What is DNS propagation? It means your DNS records have been recognized by the whole Internet. Whether you use Cloudflare or not, your DNS records can always be recognized by the Internet.

  • richardev
    6 months ago

    Based on this tutorial – I created quick bash script for creating/signing key, adding domain to trusted hosts and testig DKIM. Here is the gist: https://gist.github.com/richardevcom/a79e8ca313c2b6f34f9ea8c02959165c

  • Thank you SO MUCH for the guide! Really helped me out.

  • Hi,

    I am having an issue with not finding the public key. I am using a local DNS (BIND), so there isn’t a problem with propagating. I just copypasted the output of default.txt into my DNS Zone

    [email protected]:~$ sudo opendkim-testkey -d domain.com -s default -vvv
    opendkim-testkey: using default configfile /etc/opendkim.conf
    opendkim-testkey: checking key 'default._domainkey.domain.com'
    opendkim-testkey: 'default._domainkey.domain.com' record not found

    When I use dig, I can find the TXT record:

    [email protected]:~$ dig TXT default._domainkey.domain.com
    
    ;; ANSWER SECTION:
    default._domainkey.domain.com. 604800 IN TXT "v=DKIM1; h=sha256; k=rsa; " "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7CxWakZ+6jE5xpwlwV1ifu++ogiKUdo+6ByIVpmsZul4KM+TN7XfD8GeqXsQYWAwfXlaO+DWwTzASfSxcl3FqE8rXt2hfDTjz/9lGAvz3qJdSXSE3GarPzBxSmuEp8kjh9JAxgRP9CCdWhsTpfakOUbh3fzlIskAUeNtrv1gUMFrS8TQnjADvkd7sRkv5gwH0HmKNRtAX/PSJg" "QGgULTLraVB9zPc1dPzxt7RieW+bg/6Mnf0DN6E6VYUZPNGktNB2cjLSKCNQW2FU2z+TU3MRFu09u7PFbm28HA38mBaMZfC9+3l/trKtr4NkF17mKBmPoW9wfWLm1gk+4mh1L4oQIDAQAB"
    

    Any suggestions what went wrong?

  • Hey Xiao,

    Thank you 4 your tutorial. I have some troubles with DKIM. When i run opendkim-testkey i get error in syntax.

    opendkim-testkey -d mailmymail.de -s default -vvv
    
    opendkim-testkey: using default configfile /etc/opendkim.conf
    opendkim-testkey: checking key 'default._domainkey.mailmymail.de'
    opendkim-testkey: syntax error in key data (ASCII 0x76 at offset 4)
    

    my default.txt looks like

    default._domainkey      IN      TXT     ( "v=DKIM1; h=sha256; k=rsa; "
              "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6XQuJM/168oGqokzxMQWe0n2ROm9sDebeobDnzp2156UV/ZZhJipmCrEh8xiiaTR+wfh2ndgT3/AR46+juA+PNBydmgPvL6NL9AwdW9Ho9YNK/4d2zQ17yyUg2ktwkpZKXUnq56MvNd2JFQ6D4z8R/gZ+ACr5HtukXKxrOM42WpMX14I+GGOI0dFRJlE2CCZwWJzJme80LXt+u"
              "81zsKgGK7ASNaLzw8fTB8QqhXZmaPqDEI7ksH80i1IXGXqQIDR9GjOWIyt6gW3osKTCs4OX8r9L014kFztqTqziOTz0fxMNaHCarRWHuXWgHmIIOI6gYUXpNaH47e47hWfIGWibQIDAQAB" )  ; ----- DKIM key default for mailmymail.de 

    I can not find any solution 4 this

    • Xiao Guoan (Admin)
      5 months ago
      dig TXT default._domainkey.mailmymail.de +short

      Output:

      "TXT v=DKIM1; h=sha256; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6XQuJM/168oGqokzxMQWe0n2ROm9sDebeobDnzp2156UV/ZZhJipmCrEh8xiiaTR+wfh2ndgT3/AR46+juA+PNBydmgPvL6NL9AwdW9Ho9YNK/4d2zQ17yyUg2ktwkpZKXUnq56MvNd2JFQ6D4z8R/gZ+ACr5HtukXKxrOM42WpMX14I+GG" "OI0dFRJlE2CCZwWJzJme80LXt+u81zsKgGK7ASNaLzw8fTB8QqhXZmaPqDEI7ksH80i1IXGXqQIDR9GjOWIyt6gW3osKTCs4OX8r9L014kFztqTqziOTz0fxMNaHCarRWHuXWgHmIIOI6gYUXpNaH47e47hWfIGWibQIDAQAB"
      

      Please remove the TXT at the beginning, so it will look like this:

      "v=DKIM1; h=sha256; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6XQuJM/168oGqokzxMQWe0n2ROm9sDebeobDnzp2156UV/ZZhJipmCrEh8xiiaTR+wfh2ndgT3/AR46+juA+PNBydmgPvL6NL9AwdW9Ho9YNK/4d2zQ17yyUg2ktwkpZKXUnq56MvNd2JFQ6D4z8R/gZ+ACr5HtukXKxrOM42WpMX14I+GG" "OI0dFRJlE2CCZwWJzJme80LXt+u81zsKgGK7ASNaLzw8fTB8QqhXZmaPqDEI7ksH80i1IXGXqQIDR9GjOWIyt6gW3osKTCs4OX8r9L014kFztqTqziOTz0fxMNaHCarRWHuXWgHmIIOI6gYUXpNaH47e47hWfIGWibQIDAQAB"
      
  • Another Perfect Tutorial!!!

    A+

    Best Instructions on the Internet!!!!

    Thank you LinuxBabe!!!

  • A DKIM lesson learned: It took a while trying to find why my dkim line stated: dkim=neutral (invalid public key). It was only after doing ‘sudo dig TXT default._domainkey.your-domain.com’ that I spotted the problem. My domain registrar txt field was restricted to 255 (or less) chars. The dig results showed that the back end of the public key was fractured and not continuous and include an additional set of quotation marks (e.g. …xmESOQLy4CAOAvI86WRzKrsOKsy5vLng/a3atpx/QXhhqAZ+” “iuF4pkACzn5CnIzbCpju”) .
    I read about someone else with a similar problem and the fix was to reduce the bits from -2048 too -1024 during key generation. After doing so, the dig output was one continuous line which results in a successful dkim dkim=pass [email protected] result.
    Thank you for you excellent series of documentation.
    server – Ubuntu 22.04
    Very Best Regards

  • There’s a problem in this doc in that the KeyFile parameter in opendkim.conf needs to be changed to the path of the *private* key file, e.g. /etc/opendkim/keys//default.private. If this doesn’t happen, the opendkim-testkey test will fail; I had it pointing to the public key file instead and I was getting

    opendkim-testkey: using default configfile /etc/opendkim/opendkim.conf
    opendkim-testkey: key loaded from /etc/opendkim/keys//default.txt
    opendkim-testkey: checking key 'default._domainkey.'
    opendkim-testkey: PEM_read_bio_PrivateKey() failed
    error:0909006C:PEM routines:get_name:no start line
    
    • Xiao Guoan (Admin)
      4 months ago

      This is because you have followed some stupid tutorial on another website before.

      Locate the following lines.

      # 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
      

      By default, they are commented out. Please don’t uncomment them.

  • RainCaster
    3 months ago

    I have followed the whole series (up to this point) to get my replacement mail server running. When it came to dkim, I used the old sign/key pair from the machine I will be replacing. The old machine was a Kolab16/Ubuntu18.04 running OpenSSL 1.1.1

    The new machine uses Ubuntu 22.04 and OpenSSL 3.0.2. The testkey runs fine- as expected. However, mail is never sent, and it looks like opendkim is failing the sign for some reason. The mail log shows the following:

    Jun 17 13:25:08 slim1 dovecot: auth: Debug: sql([email protected],192.168.0.237): Finished passdb lookup
    Jun 17 13:25:08 slim1 dovecot: auth: Debug: auth([email protected],192.168.0.237): Auth request finished
    Jun 17 13:25:08 slim1 dovecot: auth: Debug: client passdb out: OK#0112#[email protected]#011
    Jun 17 13:25:08 slim1 postfix/submission/smtpd[11115]: C4FB022124E: client=user-desktop.domain.com[192.168.0.237], sasl_method=PLAIN, [email protected]
    Jun 17 13:25:08 slim1 postfix/cleanup[11126]: C4FB022124E: message-id=
    Jun 17 13:25:08 slim1 opendkim[9074]: C4FB022124E: SSL error:1E08010C:DECODER routines::unsupported
    Jun 17 13:25:08 slim1 opendkim[9074]: C4FB022124E: dkim_eom(): resource unavailable: PEM_read_bio_PrivateKey() failed
    Jun 17 13:25:08 slim1 postfix/cleanup[11126]: C4FB022124E: milter-reject: END-OF-MESSAGE from user-desktop.domain.com[192.168.0.foo]: 4.7.0 resource unavailable; from= to= proto=ESMTP helo=
    Jun 17 13:25:08 slim1 postfix/submission/smtpd[11115]: disconnect from user-desktop.domain.com[192.168.0.237] ehlo=2 starttls=1 auth=1 mail=1 rcpt=1 data=0/1 rset=1 commands=7/8
    

    For now, I would like to simply keep the key pair I have, since the Kolab server must remain in place for a while yet. It looks like OpenSSL is complaining about using a legacy resolver. How can I force that to happen in this case? I still want to keep all the rest of OpenSSL 3.x

    • Xiao Guoan (Admin)
      3 months ago

      You might need to change the ownership of the DKIM private key like this:

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

      Don’t forget to add postfix to the opendkim group.

      sudo gpasswd -a postfix opendkim

      By the way, a domain name can have multiple DKIM records. Each mail server can have its own DKIM key. Just use a different DKIM selector. I use the default DKIM selector in this tutorial, but you can have the following DKIM selectors.

      Kolab mail server:   default 
      PostfixAdmin mail server:  20220618
      
      • RainCaster
        3 months ago

        Changing the selector solved the problem for me- thanks!

  • This worked surprisingly well for something that has so many steps. Google stopped postfix from sending emails via smtp on 1/June. Then they started blocking my emails cause they weren’t DKIM signed.
    DKIM’s DNS setting is very unforgiving, you can’t even have a space after the “;”

  • Thanks for this awesome tutorial! Everyone works except for DKIM. I’ve tried appmaildev DKIM tester and mail-tester.com to check for errors and DKIM always fails to get through. I’ve also checked my /var/log/mail.log but it seems that there’s not error related to DKIM. I’ve tried several variations like reducing the RSA encryption to 1024 bits to meet Namecheap’s requirement. I’ve been trying for days and I’m still stuck. Could you give me any pointers?

    • Xiao Guoan (Admin)
      3 months ago

      First, go to https://www.dmarcanalyzer.com/dkim/dkim-check/ to check if your DKIM is valid.

      Then you can configure OpenDKIM to use TCP/IP socket instead of Unix domain socket. (Unix domain socket is usually faster than TCP/IP socket. If it doesn’t work on your server, then you should use TCP/IP socket.)

      sudo nano /etc/opendkim.conf

      Find the following line:

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

      Replace it with

      Socket     inet:[email protected]

      So OpenDKIM will be listening on the 127.0.0.1:8892 TCP/IP socket. Save and close the file. Then edit Postfix main config file.

      sudo nano /etc/postfix/main.cf

      Find the following line:

      smtpd_milters = local:opendkim/opendkim.sock

      Replace it with:

      smtpd_milters = inet:127.0.0.1:8892

      So Postfix will connect to OpenDKIM via the TCP/IP socket. Restart OpenDKIM and Postfix.

      sudo systemctl restart opendkim postfix
      • Hi Xiao,

        Thanks a lot for your prompt reply. I’ve checked the validity of DKIM for several times and gone through the entire tutorial for several runs to check if I miss anything.

        I’ve also tried the instructions you replied which is also given as part as a fallback plan in the tutorial.

        Sadly, DKIM is still not attached in my mails. I’m using Namecheap, is there anything that I might not be aware of and is not shown in the tutorial? I’ve gone through the tutorial and comments for several runs so it’s unlikely that I’ll miss those out.

  • Louis Lebrun
    2 months ago

    Hi Xiao,
    Thank’s a lot for all that.
    I’ve just set up a basic postfix + spf + dkim
    I got a score 10/10 with https://www.mail-tester.com BUT when I send a message [email protected], I got this :
    SPF : PASS avec IP 82.66.154.209 En savoir plus
    DKIM : ‘FAIL’ avec le domaine famille-en-or.net En savoir plus
    DMARC : ‘PASS’ En savoir plus
    Thank’s very much in advance for any suggestion.

    • Louis Lebrun
      2 months ago

      Hi,
      I don’t know why, but now everything PASS.
      Thank’s

  • When I go to dmarcanalyzer.com to check DKIM, I get “Error : We detected that your key in the DKIM record is invalid.” This is after making sure I’ve removed double quotes, spaces, and made sure it’s a single, one-line string before pasting it into the TXT record. What could I have missed? Everything else is working so far.

    • Okay, so, if anyone else misses this like I did, you need to copy the second quoted string as well, so that your key ends with “QAB”. The key doesn’t stop at the end of the first quoted string.

  • Hi Xiao
    Wonderful howto (I follow Part1 to n…)
    The roundcube/dovecot/postfix server work fine except the DKIM.
    The mail are not sign befor to be send.
    Il the mail log file I get

    opendkim[25905]: 0787A180209: xxx.mydomain.net [192.168.zz.yy] not internal
    opendkim[25905]: 0787A180209: not authenticated
    opendkim[25905]: 0787A180209: no signature data
    

    In my “/etc/opendkim/trusted.hosts” I have

        127.0.0.1
        localhost
        192.168.0.1/24
    
        *.mydomain.net
    

    I look like the opendkim is not looking at the “trusted.hosts” ?
    Any idee to find where I mis configure?

    Many thanks

    • Xiao Guoan (Admin)
      2 months ago

      Maybe you need to remove the asterisk.

      127.0.0.1
      localhost
      192.168.0.1/24
      
      .mydomain.net
      

      Then restart opendkim.

  • Hello Xiao
    It is solved
    I was performing submission with port 25. When passing to 587 (and adding certificate path where needed, the DKIM strat to works…
    Maybe strange ?
    But solved
    Thanks again for this tuto

    • Xiao Guoan (Admin)
      1 month ago

      Port 25 isn’t for submission. You should use port 587 or 465 for submission.

  • Hi
    the email is signed when I send an email from Webmin. Mail sent with Thunderbird is unsigned. No errors in /var/log/mail.log / journalctl -eu opendkim
    DKIM Record Check = Ok
    Why ?

    • Thunderbird > SMTP connection from “no encryption” to STARTTLS / SSL solved the problem.
      Thank you for the great tutorial.

Leave a Comment

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

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