What is DKIM?
DKIM is short for Domain Keys Identified Mail and is an internet standard, that ensures, that an email is in fact authorized by the owner of the domain, and, that its content is authentic and has not been modified. DKIM is available for FreeBSD as the OpenDKIM package or port. OpenDKIM is a milter for Sendmail, which is the default mail server in FreeBSD.
How does DKIM work?
The mail server of the sender automatically signs the email with a private key and adds a DKIM signature header field to the email. The signature is automatically verified with a public key by the mail server of the receiver. The public key is linked to the domain, because it is stored in a TXT record in DNS for the domain.
OpenDKIM can sign outgoing email and validate incoming email. OpenDKIM can use a key to sign a domain. OpenDKIM can use the same key to sign multiple domains. OpenDKIM can use multiple keys to sign multiple domains and subdomains with the use of key and signing tables.
What is the difference between DKIM and SPF?
DKIM is installed on the mail server. SPF is installed on the DNS server. DKIM ensures, that the email message is authentic. The sender information and the message has not been forged nor modified during transmission. SPF ensures, that the email was sent by an authorized mail server. The email was not sent from a spam server nor unauthorized mail server.
Install OpenDKIM for FreeBSD.
If you want to implement DKIM on your FreeBSD mail server, then install OpenDKIM from packages or ports.
# pkg search opendkim opendkim-2.10.3_12 DKIM library and milter implementation # pkg install opendkim Message from opendkim-2.10.3_12: In order to run this port, write your opendkim.conf and: if you use sendmail, add the milter socket `socketspec' in /etc/mail/<your_configuration>.mc: INPUT_MAIL_FILTER(`dkim-filter', `S=_YOUR_SOCKET_SPEC_, F=T, T=R:2m')
Note, that the message suggests, that the milter identifier is dkim-filter. This is unfortunately not correct. The milter identifier, that Sendmail will use for OpenDKIM, is opendkim.
Generate DKIM keys on FreeBSD mail server.
The DKIM package and port comes with the DKIM filter key generation tool opendkim-genkey. The tool generates a private key for signing messages and a public key for verifying messages. The public key comes in the form of a TXT record. The format is compatible with a zone file for BIND DNS.
Create a directory for storing the DKIM keys and generate a DKIM key. The option -d is a list of domains, that OpenDKIM will sign with this key. The option -D will include subdomains of those domains. See more about options in the manual for OpenDKIM. If OpenDKIM will be using multiple keys, then organize the keys. Note, that OpenDKIM runs as a non-priviledged user and group.
# cd /usr/local/etc/mail # mkdir -m 0755 opendkim-keys && cd opendkim-keys # mkdir -m 0755 foobar.com && cd foobar.com # opendkim-genkey -b 2048 -d foobar.com -s default # chown mailnull:mailnull default.* # chmod 0440 *
Add DKIM TXT record to domain name zone in BIND DNS server.
In this example, a DKIM public domain key, that was generated and written as a TXT record, is added to the domain name zone in BIND DNS on a FreeBSD server. The serial number is updated and the final zone reviewed. A lower time-to-live (TTL) might be used in the initial phase. The zone is checked by BIND DNS before BIND is restarted.
# cat default.txt >> /usr/local/etc/namedb/master/foobar.com # nano /usr/local/etc/namedb/master/foobar.com # named-checkzone foobar.com /usr/local/etc/namedb/master/foobar.com zone foobar.com/IN: loaded serial 13371377 # service named restart
Example of BIND DNS zone file with DKIM TXT record.
# cat /usr/local/etc/namedb/master/foobar.com $TTL 13M $ORIGIN foobar.com. @ IN SOA dns.foobar.com. hostmaster.foobar.com. ( 13371337 8H 2H 4W 1D ) @ IN NS dns1.foobar.com. @ IN NS dns2.foobar.com. @ IN MX 10 mail1.foobar.com. @ IN MX 20 mail2.foobar.com. @ IN TXT "v=spf1 mx -all" default._domainkey IN TXT ( "v=DKIM1; k=rsa; " "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3xl2FNEbcSLuGC0ju8nHxE2M3Tmwq8yK77rI5lgCZNr22IWKqIy9uJg+w94SKoMLZxSx6SfUc/hry3q4x9Q85rgLsRbAZ7qXHt8v4mswZ26zz+ojtspjk1LkLH73AaO4/HUB0AqZYdolAXnnGz25rsvUBPSvoLPaYHgzOqsksDaooCGBeZMpulcQ5YuIUs8lEmGW7GdQFIJ/AK" "zlYV2jD1GxlA03nDAkqXO4m+H8roGv75YXXx9IvyXgr0DB13PKNzH5yW5iOcrDBmsVVX65MzT/+Llj2w54/vwqD2R8lsFWuRW+jmWZ+a9iyAjhnbGREoShLv/o42CO+3RhzL1JqwIDAQAB" ) ; ----- DKIM key default for foobar.com @ IN A 13.37.13.37 dns1 IN A 13.13.13.13 dns2 IN A 37.37.37.37 mail1 IN A 13.37.13.38 mail2 IN A 13.37.13.39 www IN A 13.37.13.40
Test DNS with DKIM TXT record.
Test the DNS by making a DNS query with the DNS lookup utilify dig for the new TXT record, that contains the DKIM public domain key.
Be aware, that a DNS query consist of a name and a type. The name is a domain name, that is looked up, and the type is the type of resource record (RR), that is looked up. If just the name foobar.com was looked up, then that name would be different from the name default._domainkey.foobar.com, that has the DKIM key, and would not return the DKIM key.
# dig @localhost -n default._domainkey.foobar.com -t TXT default._domainkey.foobar.com. 60 IN TXT "v=DKIM1; k=rsa; " "p=MIIBIjANBgkqhkiG9w0BAQEF1337AQ8AMIIBCgKCAQEA3xl2FNEbcSLuGC0ju8nHxE2M3Tmwq8yK77rI5lgCZNr22IWKqIy9uJg+w94SKoMLZxSx6SfUc/hry3q4x9Q85rgLsRbAZ7qXHt8v4mswZ26zz+ojtspjk1LkLH73AaO4/HUB0AqZYdolAXnnGz25rsvUBPSvoLPaYHgzOqsksDaooCGBeZMpulcQ5YuIUs8lEmGW7GdQFIJ/AK" "zlYV2jD1GxlA03nDAkqXO4m+H8roGv75YXXx9IvyXgr0DB13PKNzH5yW5iOcrDBmsVVX65MzT/+Llj2w54/vwqD2R8lsFWuRW+jmWZ+a9iyAjhnbGREoShLv/o42CO+3RhzL1JqwIDAQAB"
When the updated DNS zone has been adopted by DNS servers on the internet, then DNS and DKIM for the domain can be tested on the internet as well.
In this example, a DNS query is made from the csh shell on a FreeBSD desktop computer, different from the server. It should match the test, that was done earlier.
% dig -n default._domainkey.foobar.com -t TXT
The DNS query can also be made, so that it asks a specific DNS server.
% dig @foobar -n default._domainkey.foobar.com -t TXT
Configure OpenDKIM on FreeBSD.
Find the configuration file for OpenDKIM. We can only try to guess the filename.
# find / -type f -name 'opendkim.c*' /usr/local/etc/mail/opendkim.conf.sample
Use the sample file to create a new configuration file.
# cp /usr/local/etc/mail/opendkim.conf.sample /usr/local/etc/mail/opendkim.conf
Edit the configuration by reading the comments and editing as necessary. Many options has default values. Port 8891 seems to be widely used.
# nano /usr/local/etc/mail/opendkim.conf
Confirm effective options.
# cat /usr/local/etc/mail/opendkim.conf | grep -v '^#' | grep -v '^$' Domain foobar.com InternalHosts refile:/usr/local/etc/mail/opendkim-internalhosts KeyFile /usr/local/etc/mail/opendkim-keys/foobar.com/default.private Selector default Socket inet:8891@localhost Syslog Yes SyslogSuccess yes
Make the list of internal hosts, that should be signed. The default is 127.0.0.1.
# nano /usr/local/etc/mail/opendkim-internalhosts 127.0.0.1 13.37.13.37 # chmod 0755 /usr/local/etc/mail/opendkim-internalhosts
The use of InternalHosts is probably not necessary.
Start OpenDKIM milter on FreeBSD.
Configure the OpenDKIM milter as a service in FreeBSD for automatic start.
# nano /etc/rc.conf milteropendkim_enable="YES" milteropendkim_flags="-x /usr/local/etc/mail/opendkim.conf"
Identify the service name, that starts OpenDKIM. Note, that developers went for a discreet hyphen on this one.
# service -e | grep dkim /usr/local/etc/rc.d/milter-opendkim
Start the OpenDKIM milter.
# service milter-opendkim start Starting milteropendkim.
Check system log and mail log for errors.
# tail /var/log/messages
Confirm, that OpenDKIM is running and listening on the port.
# sockstat -4 -l mailnull opendkim 81337 3 tcp4 127.0.0.1:8891 *:*
Configure Sendmail for OpenDKIM milter.
When OpenDKIM is configured and running as a service, then it is time to implement the OpenDKIM milter in Sendmail. Read more about the Sendmail configuration format in the Makefile in /etc/mail and the M4 stream configuration format in README in /usr/share/sendmail.
# cd /etc/mail/ # nano `hostname`.mc INPUT_MAIL_FILTER(`opendkim', `S=inet:8891@localhost, F=T, T=R:2m') # make /usr/bin/m4 -D_CF_DIR_=/usr/share/sendmail/cf/ /usr/share/sendmail/cf/m4/cf.m4 foobar.com.mc > foobar.com.cf # make install install -m 444 foobar.com.cf /etc/mail/sendmail.cf install -m 444 foobar.com.submit.cf /etc/mail/submit.cf # make restart
Test OpenDKIM signing.
OpenDKIM works, when the receiving mail server is able to lookup the DKIM key in DNS and then confirm the signature in the header of the email.
Send a test email from a local mail client on the mail server (localhost) to a recipient, that can read the headers of the email. Confirm, that there are no errors in mail log. Confirm, that the received email contains a DKIM signature, and, that it passed the authentication.
# tail /var/log/maillog
Send a test mail from a remote host, that is allowed to relay mail via the mail server with OpenDKIM, to a recipient, that can read the headers of the email. Confirm, that there is a DKIM signature, and, that it passed the authentication.
GMail can be used to examine the headers and DKIM authentication of an email. This is done by opening the email and selecting to view it as original message.
Example of email header with passed DKIM authentication results and DKIM signature.
The following is an example from an email in GMail. The email header contains ARC authentication results, that show, that the email passed DKIM and SPF authentication. The email header also contains the DKIM signature.
ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@foobar.com header.s=default header.b=13371337; spf=pass (google.com: domain of designates 13.37.13.37 as permitted sender) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=foobar.com; s=default; t=1707280015; bh=ATFNXTdps/lpxZOwwqUpGoGBuiD+IO1337KfY2wcvwM=; h=Date:From:To:Subject; b=XL7nF+IGeTa521337caPAO1337NEXmtIm4uknaxCLa7/klLML3vtRzLD1337NJlKu /mANY71yXFLt7Evq3my367s0jKNhXhhNY1Sqzb3sEK9nq/DBYvLmEJn4ug7+FmU5+1 62HI7w/7Pwo9i1JCOWe92IoKPekJ813378CpeD97Yjp/MJz7iPVMP16vs3sdkVGl2t U+m7P2qEOpixzSgMLBIiBkCTDAE+ZJW+Asz80aDxX8qtDw1Top1zLoNYIU37ZwgskC 9xvywBEUhFwqP/FKJH/nBthkQbDwNC01uU7LMsi98lBtSC6Kb0RfUyqf5fagM89Z8n uFpjX1o2mrFng==
How to raise log levels of Sendmail and OpenDKIM milter.
The log levels of Sendmail and OpenDKIM milter can be raised to include more details and help identify problems. This is done by configuring the Sendmail configuration file.
define(`confLOG_LEVEL', `9') define(`confMILTER_LOG_LEVEL', `18')
More about DKIM.
- https://www.dkim.org/
- https://en.wikipedia.org/wiki/DomainKeys_Identified_Mail
- http://opendkim.org/
- https://freebsd.pkgs.org/13/freebsd-amd64/opendkim-2.10.3_16.pkg.html
- https://www.freshports.org/mail/opendkim
- https://man.freebsd.org/cgi/man.cgi?query=opendkim
- https://www.micski.dk/2024/02/09/how-to-configure-spf-policy-record-in-bind-dns/
- https://www.appmaildev.com/en/dkim
- https://www.mail-tester.com/
- https://www.isc.org/bind/
- https://www.isc.org/docs/2022-webinar-dns-wildcards.pdf
- https://groups.google.com/g/comp.protocols.dns.bind/c/TuMPtBAfRLA