How to configure DKIM & SPF & DMARC on Sendmail for multiple domains on CentOS 7
DKIM
DKIM is DomainKeys Identified Mail and is used in mail servers, such as Postfix or Sendmail to sign e-mails and thus authenticating the sender so that a forgery can be detected. It also reduces the possibility of an e-mail being flagged as spam, but it’s not a definite prevention. DKIM includes a cryptographic hash in the e-mail header which is calculated with the private key (on the server) and verified with the public key (in the DNS record).
- Install OpenDKIM
# yum install opendkim # yum install opendkim-tools
- Edit the configuration file of opendkim in /etc/opendkim.conf
## BASIC OPENDKIM CONFIGURATION FILE ## See opendkim.conf(5) or /usr/share/doc/opendkim/opendkim.conf.sample for more ## BEFORE running OpenDKIM you must: ## - make your MTA (Postfix, Sendmail, etc.) aware of OpenDKIM ## - generate keys for your domain (if signing) ## - edit your DNS records to publish your public keys (if signing) ## See /usr/share/doc/opendkim/INSTALL for detailed instructions. ## DEPRECATED CONFIGURATION OPTIONS ## ## The following configuration options are no longer valid. They should be ## removed from your existing configuration file to prevent potential issues. ## Failure to do so may result in opendkim being unable to start. ## ## Removed in 2.10.0: ## AddAllSignatureResults ## ADSPAction ## ADSPNoSuchDomain ## BogusPolicy ## DisableADSP ## LDAPSoftStart ## LocalADSP ## NoDiscardableMailTo ## On-PolicyError ## SendADSPReports ## UnprotectedPolicy ## CONFIGURATION OPTIONS AutoRestart Yes AutoRestartRate 10/1h TemporaryDirectory /var/tmp SignatureAlgorithm rsa-sha256 ## Specifies the path to the process ID file. PidFile /var/run/opendkim/opendkim.pid ## Selects operating modes. Valid modes are s (sign) and v (verify). Default is v. ## Must be changed to s (sign only) or sv (sign and verify) in order to sign outgoing ## messages. Mode sv ## Log activity to the system log. Syslog yes ## Log additional entries indicating successful signing or verification of messages. SyslogSuccess yes ## If logging is enabled, include detailed logging about why or why not a message was ## signed or verified. This causes an increase in the amount of log data generated ## for each message, so set this to No (or comment it out) if it gets too noisy. LogWhy yes ## Attempt to become the specified user before starting operations. UserID opendkim:opendkim ## Create a socket through which your MTA can communicate. Socket inet:8891@localhost ## Required to use local socket with MTAs that access the socket as a non- ## privileged user (e.g. Postfix) Umask 002 ## This specifies a text file in which to store DKIM transaction statistics. ## OpenDKIM must be manually compiled with --enable-stats to enable this feature. # Statistics /var/spool/opendkim/stats.dat ## Specifies whether or not the filter should generate report mail back ## to senders when verification fails and an address for such a purpose ## is provided. See opendkim.conf(5) for details. SendReports yes ## Specifies the sending address to be used on From: headers of outgoing ## failure reports. By default, the e-mail address of the user executing ## the filter is used (executing_user@hostname). # ReportAddress "Example.com Postmaster" <postmaster@example.com> ## Add a DKIM-Filter header field to messages passing through this filter ## to identify messages it has processed. SoftwareHeader yes ## SIGNING OPTIONS ## Selects the canonicalization method(s) to be used when signing messages. #Canonicalization relaxed/relaxed Canonicalization relaxed/simple ## Domain(s) whose mail should be signed by this filter. Mail from other domains will ## be verified rather than being signed. Uncomment and use your domain name. ## This parameter is not required if a SigningTable is in use. # Domain example.com ## Defines the name of the selector to be used when signing messages. Selector default ## Specifies the minimum number of key bits for acceptable keys and signatures. MinimumKeyBits 1024 ## Gives the location of a private key to be used for signing ALL messages. This ## directive is ignored if KeyTable is enabled. #KeyFile /etc/opendkim/keys/default.private ## Gives the location of a file mapping key names to signing keys. In simple terms, ## this tells OpenDKIM where to find your keys. If present, overrides any KeyFile ## directive in the configuration file. Requires SigningTable be enabled. KeyTable /etc/opendkim/KeyTable ## Defines a table used to select one or more signatures to apply to a message based ## on the address found in the From: header field. In simple terms, this tells ## OpenDKIM how to use your keys. Requires KeyTable be enabled. SigningTable refile:/etc/opendkim/SigningTable ## Identifies a set of "external" hosts that may send mail through the server as one ## of the signing domains without credentials as such. ExternalIgnoreList refile:/etc/opendkim/TrustedHosts ## Identifies a set "internal" hosts whose mail should be signed rather than verified. InternalHosts refile:/etc/opendkim/TrustedHosts ## Contains a list of IP addresses, CIDR blocks, hostnames or domain names ## whose mail should be neither signed nor verified by this filter. See man ## page for file format. # PeerList X.X.X.X ## 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 Fedora package ## because it is often the identity key used by reputation systems and thus ## somewhat security sensitive. OversignHeaders From ## Instructs the DKIM library to maintain its own local cache of keys and ## policies retrieved from DNS, rather than relying on the nameserver for ## caching service. Useful if the nameserver being used by the filter is ## not local. # QueryCache yes
As you can see, there are three more files to be added, TrustedHosts (whitelisted IPs that can sign e-mails), KeyTable (multiple domain configuration for public and private keys) and SigningTable (whitelisted users that can sign e-mail).
- /etc/opendkim/TrustedHosts:
# OPENDKIM TRUSTED HOSTS # To use this file, uncomment the #ExternalIgnoreList and/or the #InternalHosts # option in /etc/opendkim.conf then restart OpenDKIM. Additional hosts # may be added on separate lines (IP addresses, hostnames, or CIDR ranges). # The localhost IP (127.0.0.1) should always be the first entry in this file. 127.0.0.1 ::1 #host.example.com #192.168.1.0/24
- /etc/opendkim/SigningTable:
# OPENDKIM SIGNING TABLE # This table controls how to apply one or more signatures to outgoing messages based # on the address found in the From: header field. In simple terms, this tells # OpenDKIM "how" to apply your keys. # To use this file, uncomment the SigningTable option in /etc/opendkim.conf, # then uncomment one of the usage examples below and replace example.com with your # domain name, then restart OpenDKIM. # WILDCARD EXAMPLE # Enables signing for any address on the listed domain(s), but will work only if # "refile:/etc/opendkim/SigningTable" is included in /etc/opendkim.conf. # Create additional lines for additional domains. #*@example.com default._domainkey.example.com # NON-WILDCARD EXAMPLE # If "file:" (instead of "refile:") is specified in /etc/opendkim.conf, then # wildcards will not work. Instead, full user@host is checked first, then simply host, # then user@.domain (with all superdomains checked in sequence, so "foo.example.com" # would first check "user@foo.example.com", then "user@.example.com", then "user@.com"), # then .domain, then user@*, and finally *. See the opendkim.conf(5) man page under # "SigningTable" for more details. #example.com default._domainkey.example.com *@thuinformatik.ch default._domainkey.thuinformatik.ch
All users from @thuinformatik.ch can sign. You can specifiy usernames and domains, instead of the wildcard, for additional security.
- /etc/opendkim/KeyTable:
# OPENDKIM KEY TABLE # To use this file, uncomment the #KeyTable option in /etc/opendkim.conf, # then uncomment the following line and replace example.com with your domain # name, then restart OpenDKIM. Additional keys may be added on separate lines. #default._domainkey.example.com example.com:default:/etc/opendkim/keys/default.private default._domainkey.thuinformatik.ch thuinformatik.ch:default:/etc/opendkim/keys/thuinformatik.ch/default.private
Location of the private key and name of the DNS record for each domain. The “default” before _domainkey.example.com and :default: is a selector. This can be changed to something else.
- Generate the public and private key for each domain.
Shouldn’t be too difficult. If some folders don’t exist, just create them.
# cd /etc/opendkim/keys # mkdir thuinformatik.ch # opendkim-genkey -D /etc/opendkim/keys/thuinformatik.ch -d thuinformatik.ch -s default
Again -s flag is for the selector. If you changed it, you need to enter it here. The command generates a private key (default) and public key (default.txt). You will probably rename them, to match the configuration. An important note here is that the files are owned by user opendkim, or you will get permission denied errors in /var/log/mail.err. Default permissions on those files are -rw——. Move the private key to where you specified it should be in the KeyTable.
- Create opendkim user, set a password and add the user to the opendkim group.
# adduser opendkim # passwd opendkim # usermod -a -G opendkim opendkim
- Allow opendkim user to read files.
# chown root:opendkim default.*
- Start and enable the service
# systemctl start opendkim # systemctl enable opendkim
- Edit cat /etc/mail/sendmail.mc
Next up, telling sendmail to talk to opendkim. Edit /etc/mail/sendmail.mc and add this line at the end. DO NOT EDIT sendmail.cf.
INPUT_MAIL_FILTER(`opendkim', `S=inet:8891@localhost')
- Rebuild sendmail configuration and restart sendmail
# m4 /etc/mail/sendmail.mc > /etc/mail/sendmail.cf # systemctl restart sendmail
- Add the content of default.txt to your DNS zone
# cat /etc/opendkim/keys/thuinformatik.ch/default.txt default._domainkey IN TXT ( "v=DKIM1; k=rsa; " "p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+KQWYQZwNOGSuabgbIYt2haP7aK9K1QHB88jUN2ohZ66PLMu5A4d3jDwB+68joz8V4qy5XX/ik3LRJId+5YyNh+ThozwCvZtuyHi2L7Dcmg8p4J3m8h/vuZG2VmCP9IA9pcSFwJ0yMDoXJZQFCeexJ/YEB1lbua4oEcni9C03FwIDAQAB" ) ; ----- DKIM key default for thuinformatik.ch
- Verify the DKIM record is working.
Goto: https://www.dmarcanalyzer.com/de/dkim-de/dkim-record-check/ and make sure you get a valid response.
- Verify the DKIM header is correctly visible in a message you’ve sent to an external host
DKIM-Filter: OpenDKIM Filter v2.11.0 mail.netcult.ch x9LJUSpQ032185 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=thuinformatik.ch; s=default; t=1571686228; bh=c2L59hl+JxuFMU9VusJ0U8Vz9byJhrRqcRtfE1FcgD4=; h=From:To:Subject:Date:From; b=XzmeSO1AcAEHDJHbuazzMNXtG8WlKa3HMccBZHxouurHCZIklrfheU+VwKj6HYBQJ 7EKzXdwMyohrGlLjpZR/6T3mKK7W/5IXuKSpzTtbSCBaaMVuFvUiyehdTQWXmNuQ5V qpjgegvdsCrHLQHEqjfWcXDyQAuZ6a1P5yVoiUio=
Download my two management scripts to add and delete keys in a multi domain environment, the output of the add-script is the public key that has to be added to the DNS zone: dkim.zip
' To add domains # mail.add.dkim.sh domain.com ' To remove domains # mail.del.dkim.sh domain.com
SPF
SPF does not need a specific configuration. Whitelisted servers are listed in a DNS record, TXT or SPF.
An example record to validate mails for domain for the IP 46.140.84.236 is listed below:
@ IN TXT ( “v=spf1 a mx ip4:46.140.84.236 -all” )
An example record to validate mails for domain for the IP 46.140.84.236 including an additional host vm234.fc-server.de is listed below:
@ IN TXT ( “v=spf1 a mx ip4:46.140.84.236 include:vm234.fc-server.de -all” )
DMARC
DMARC does not need a specific configuration. Whitelisted servers are listed in a DNS record, TXT or SPF.
_dmarc IN TXT ( “v=DMARC1;p=none;sp=none;rua=mailto:support@thuinformatik.ch” )
8 thoughts on “How to configure DKIM & SPF & DMARC on Sendmail for multiple domains on CentOS 7”
following few time this procedure but…
We could not detect a DKIM record with the specified selector on this domain.
No idea where you have issues, what you try or where you stuck. The procedure is validated and works.
Much appreciated and excellent article – it helped me finally quickly implement DKIM along with SPF and DMARC in our sendmail SMTP setup.
However, DKIM fails for internally (same domain) forwarded emails. Is there a way to skip DKIM signing for situations like this?
My (hopefully temporary) workaround is:
1 – Set DMARC policy to “quarantine”
2 – Use Dovecot Sieve filter on incoming messages with this rule:
rule:[SPF]
if allof (header :contains “authentication-results” “dmarc=fail”, header :contains “authentication-results” “spf=fail”, not header :contains “received” “authenticated bits=0”)
{
fileinto “Junk”;
stop;
}
Notice the section:
header :contains “received” “authenticated bits=0”
This is part of the initial SMTP handshake and only present for internal domain (same server) forwarded messages.
Obviously, the same rule set could be implemented with Procmail…
Hi Lars,
What do you mean by saying “fails”? Do you have a header of such an email?
In general, internally sent mails will be equiped with a DKIM record in the mailheader, same as externally sent mails are.
I ask myself, why is this a problem? I don’t see a problem with that. Can you explain?
DKIM “breaks” when forwarding an email to another internal user in the same domain as your sending domain. However, you can successfully forward it to an external user and DMARC
Here’s an example of the relevant mail header section when forwarding an email to myself (or another user in the same domain/on the same server) where we observe “fail” for both DKIM and SPF:
Return-Path: lars@nulogic.net
Received: from [192.168.11.40] (ool-44c32950.dyn.optonline.net [68.195.41.80])
(authenticated bits=0)
by mail4.nulogic.net (8.14.7/8.14.7) with ESMTP id 24KDuNwB024326
(version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NO)
for lars@nulogic.net; Fri, 20 May 2022 09:56:24 -0400
DMARC-Filter: OpenDMARC Filter v1.4.1 mail4.nulogic.net 24KDuNwB024326
Authentication-Results: mail4.nulogic.net; dmarc=fail (p=quarantine dis=none) header.from=nulogic.net
Authentication-Results: mail4.nulogic.net; spf=fail smtp.mailfrom=nulogic.net
DKIM-Filter: OpenDKIM Filter v2.11.0 mail4.nulogic.net 24KDuNwB024326
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nulogic.net;
s=default; t=1653054988;
bh=rlit18aQXe806iK1Ea5TJO2b6X+OuOn5Ue1T0fbXR0w=;
h=Date:Subject:References:To:From:In-Reply-To:From;
b=jBKlSJGaMXmnL1enAE27FTld2eu3KUiONnNFAU5+1oysHTGhuNOCikIAoaY49vwHb
lZiBeDwdZikYe5sIqVbHRb32H5rl5ZleyWummkgP0c0BEuPD2pIBVJV0AagC1mz7ji
P9dzpKwJffgWbVVhk8kpLLJs26hWdeOylZR7oQJs=
Do you agree that the reason for the fail is a problem with the spf record in your dns zone and not a problem with the dkim signature?
Hello Tom,
Here’s an update:
The DNS TXT SPF record is correct. However, as part of the OpenDKIM setup, I also setup OpenDMARC and OpenArc and it turns out that my OpenDMARC config was the culprit, NOT OpenDKIM.
Specifically, error is caused by OpenDMARC verifying/signing the email client submission unless you specifically add this line (/etc/opendmarc.conf):
IgnoreAuthenticatedClients true
In other words, the DNS SPF error had nothing to do with the mail server/domain/IP, but the local email client (in my case Thunderbird) submission incorrectly being verified/signed. The above line will as the config key name clearly indicates.
Hope this will help someone else and save a couple of hours of troubleshooting.
Thanks again for a great article, Tom !!
Got ot 👍🏻 Thank you for the details.