DomainKeys is an authentication framework which stores public-keys
in DNS and digitally signs emails on a domain basis.
A domain owner generates a private/public key-pairs that will be
used to sign messages originating from that domain. The public-key
is placed in DNS as a TXT record. The private-key is kept on the mail
server which sends email for the domain.
When an email is submitted by an authorized user of that domain, dk-milter
uses the private-key to digitally sign the email associated with the
sending domain. The DomainKey-Signature header and signature
is added to the email and the message is sent.
When a message is received with a DomainKey-Signature header,
dk-milter extracts the signature and the sender's domain from the email.
It does a DNS lookup on the TXT record to fetch the public-key for
the sender's domain. Using the public-key, dk-milter verifies whether
the signature of the email is valid. An Authentication-Results:
domainkeys=pass header is inserted in the email if the verification
Selectors allows a domain to have more than one public-key in DNS.
This allows you to administer and change the public-keys advertized
in DNS. If the selector is test and the domain is example.com,
the public-key will be retrieved from test._domainkey.example.com.
The name before _domainkey is the selector.
Dk-milter uses main as the default selector.
Mail servers sometimes modify email in transit. This can invalidate
the domainkeys signature. dk-milter supports two canonicalization algorithms.
The simple algorithm tolerates almost no modification. The nofws algorithm
tolerates common modifications such as white-space replacement and
header line re-wrapping.
The default canonicalization used by dk-milter is simple.
The following installation guide is based upon sendmail 8.13. The
DomainKeys feature is implemented through a milter.
The milter does not support any sendmail version prior to 8.13.
You should be able to modify the DNS records for your domain.
You should have a OpenSSL library installed.
You should have sendmail 8.13 installed.
Installing the DomainKeys milter
Download the source code for the sendmail DomainKeys milter from the sendmail.net website.
- Extract the files from the downloaded dk-milter file
- Edit the dk-filter/Makefile.m4 as follows:
APPENDDEF(`confLIBS', `-lssl -lcrypto')
dnl Enable and edit these paths as needed:
dnl APPENDDEF(`confINCDIRS', `-I/usr/local/ssl/include ')
dnl APPENDDEF(`confLIBDIRS', `-L/usr/local/ssl/lib ')
dnl To use the asynchronous resolver library provided,
enable this line:
APPENDDEF(`confINCDIRS', `-I../libdk/ ')
dnl Enable these next line if needed to specify the locations
dnl and the libmilter include files:
dnl APPENDDEF(`confINCDIRS', `-I/usr/local/sendmail/include')
dnl APPENDDEF(`confLIBDIRS', `-L/usr/local/sendmail/lib')
dnl Enable for IPv6 support:
dnl APPENDDEF(`confENVDEF', `-DNETINET6 ')
dnl APPENDDEF(`confENVDEF', `-D_FFR_EXTERNAL_IGNORE_LIST ')
dnl APPENDDEF(`confENVDEF', `-D_FFR_FLUSH_HEADERS ')
dnl APPENDDEF(`confENVDEF', `-D_FFR_MACRO_LIST ')
APPENDDEF(`confENVDEF', `-D_FFR_MULTIPLE_KEYS ')
dnl APPENDDEF(`confENVDEF', `-D_FFR_REPORTINFO ')
dnl APPENDDEF(`confENVDEF', `-D_FFR_REQUIRED_HEADERS ')
dnl APPENDDEF(`confENVDEF', `-D_FFR_SELECT_CANONICALIZATION ')
dnl If you do POP before SMTP:
dnl APPENDDEF(`confENVDEF', `-DPOPAUTH ')
dnl APPENDDEF(`confINCDIRS', `-I/usr/local/BerkeleyDB/include')
dnl APPENDDEF(`confLIBDIRS', `-L/usr/local/BerkeleyDB/lib')
dnl PREPENDDEF(`confLIBS', `-ldb ')
define(`bldSOURCES', `dk-filter.c util.c ')
PREPENDDEF(`confLIBS', `-lmilter ')
If the OpenSSL library and include files are installed in a
different location, adjust the confINCDIRS and confLIBDIRS settings
to point to the directories.
- If your OpenSSL files are installed in a different directory, edit
the the confINCDIRS setting in libdk/Makefile.m4, removing
the dnl at the beginning of the line, to point to the directory where
the OpenSSL include files are:
dnl Enable these lines to make use of the provided asynchronous
dnl APPENDDEF(`confENVDEF', `-DUSE_ARLIB ')
dnl APPENDDEF(`confINCDIRS', `-I../libar/ ')
dnl Enable and edit this as appropriate for your system:
dnl APPENDDEF(`confINCDIRS', `-I/usr/local/ssl/include ')
define(`bldSOURCES', `dk.c rfc2822.c util.c ')
- Change the current directory to directory where dk-milter was extracted.
- Enter the following command:
- If there are no errors, you may continue with the installation.
- Enter the following command:
sh Build install
Generating a public and private key
DomainKeys requires a public and private key. The private key should
be saved in a safe location on your server. The public key will used
in the DNS TXT record for DomainKeys.
DNS TXT record for DomainKeys
Create a DNS TXT record for selector._domainkey.example.com
mail._domainkey.example.com. IN TXT "k=rsa; t=y;
The string after p= is the base64 encoding of your public
If the rsa.public file which was generated contains
-----BEGIN PUBLIC KEY-----
-----END PUBLIC KEY-----
the base64 encoding is everything between the first -----
BEGIN PUBLIC KEY----- and -----END PUBLIC
KEY----- lines. You should remove
any spaces and newlines.
The t=y value pair means that the domain is using this
key in test mode.
The sending domain policy is published using a DNS TXT record as follows:
_domainkey.example.com. IN TXT "t=y; o=~"
The t=y value pair means that the example.com domain is testing DomainKeys.
The o tag denotes the outbound signing policy. ~ (tilde) means that the example.com domain may sign some emails with DomainKeys.
Starting the DomainKeys milter
The milter runs as a daemon in the background. If you are starting
the milter as root, you should create an unprivileged user for the
Configuring sendmail with DomainKeys milter
- Edit the .mc configuration file that was used to build the sendmail.cf
and add the following entry to it
Using DomainKeys milter with SpamAssassin
Our AuthResults plugin can be used with SpamAssassin to evaluate the
You can perform a DomainKeys test by sending an email to email@example.com.
The email address specified as the (envelope) sender, and not the author (From:), will receive the reply. If you do not receive a reply, it is likely that your mail server rejected the mail sent by our autoresponder.
Below is an example of a signature header:
DomainKey-Signature: a=rsa-sha1; s=mail; d=example.com; c=simple;
If the verification is successful, you should see the following header
in your email:
Authentication-Results: mail.example.net; domainkeys=pass
A DomainKeys test for canonicalization nofws can be performed by sending an email to firstname.lastname@example.org. Send an email to email@example.com to test simple canonicalization.
DomainKeys signature verification failures
DomainKeys uses the email headers and body to generate a signature.
If the subject line is rewritten or text is appended to the message
body after it has been signed, the domainkeys verification fails.
Domain-based Email Authentication Using Public-Keys Advertised in
the DNS (DomainKeys) - RFC 4870
dk-filter - DomainKeys filter for sendmail
dk-filter -p socketspec [-a peerlist] [-A] [-b modes] [-c canon] [-C
config] [-d domains] [-D] [-f] [-i ilist] [-I eilist] [-h] [-H] [-k]
[-l] [-m mtas] [-M macro[=value][,...]] [-o hdrlist] [-P pidfile] [-q]
[-R] [-s keyfile] [-S selector] [-T secs] [-u userid] [-U popdb] [-V]
dk-filter implements Yahoo!, Inc.'s DomainKeys draft standard for sign-
ing and verifying e-mail messages on a per-domain basis.
Details regarding the protocol and other issues related to the draft
standard can be found at http://antispam.yahoo.com/domainkeys.
Identifies a file of "peers" which identifies clients whose con-
nections should be accepted without processing by this filter.
The peerlist should contain on each line a hostname, domain name
(e.g. ".example.com"), IP address, an IPv6 address (including an
IPv4 mapped address), or a CIDR-style IP specification (e.g.
-A Automatically re-start on failures. Use with caution; if the
filter fails instantly after it starts, this can cause a tight
Selects operating modes. modes is a concatenation of characters
which indicate which mode(s) of operation are desired. Valid
modes are s (signer) and v (verifier). The default is sv.
Selects the canonicalization method to be used when signing mes-
sages. When verifying, the message's DomainKey-Signature:
header specifies the canonicalization method. The recognized
values are nofws and simple as defined by the DomainKeys draft.
The default is simple.
Configuration control. See the CONFIGURATION section for
-d domain [,...]
A comma-separated list of domains whose mail should be signed by
this filter. Mail from other domains will be verified rather
than being signed.
If the value of this parameter starts with a "/" character, it
is assumed to be a filename from which the domain list will be
read, one per line, with "#" characters indicating the beginning
of a comment.
In either case, the domain name(s) may contain the special char-
acter "*" which is treated as a wildcard character matching zero
or more characters in a domain name.
-D Sign subdomains of those listed by the -d option as well as the
-f Normally dk-filter forks and exits immediately, leaving the ser-
vice running in the background. This flag suppresses that be-
haviour so that it runs in the foreground.
-h Causes dk-filter to add a header indicating the presence of this
filter in the path of the message from injection to delivery.
The product's name, version, and the job ID are included in the
-H Includes on DomainKey signatures the list of headers that were
included in the signature. This makes the signature header
larger by explicitly listing the included headers, but this also
allows verifying agents to ignore headers that were added in
Identifies a file of internal hosts whose mail should be signed
rather than verified. Entries in this file follow the same form
as those of the -a option above. If not specified, the default
of "127.0.0.1" is applied.
Identifies a file of "external" hosts which may send mail
through the server as one of the signing domains without creden-
tials as such; basically suppresses the "external host (host-
name) tried to send mail as (domain)" log messages. Entries in
this file follow the same form as those of the -a option above.
-k Causes -s to be interpreted as the location of a key list, which
is a file listing rules for signing with multiple keys. The key
list should contain a set of lines of the form sender-pat-
tern:keypath where sender-pattern is a pattern to match against
message senders (with the special character "*" interpreted as
"zero or more characters"), and keypath is the path to the PEM-
formatted private key to be used for signing messages which
match the sender-pattern. The selector used in the signature
will be the filename portion of keypath.
-l Log via calls to syslog(3) any interesting activity.
-m mta [,...]
A comma-separated list of MTA names (a la the sendmail(8) Dae-
monPortOptions Name parameter) whose mail should be signed by
this filter. There is no default.
Defines a set of MTA-provided macros which should be checked to
see if the sender has been determined to be a local user and
therefore whether or not the message should be signed; if a
value is specified, the value of the macro must match the value
specified (matching is case-insensitive), otherwise the macro
must be defined but may contain any value. The list is empty by
-o header [,...]
A comma-separated list of headers which should not be signed.
Ignored when verifying.
Specifies the socket that should be established by the filter to
receive connections from sendmail(8) in order to provide ser-
vice. socketspec is in one of two forms: local:path which cre-
ates a UNIX domain socket at the specified path, or
inet:port[@host] which creates a TCP socket on the specified
port. If the host is not given as either a hostname or an IP
address, the socket will be listening on all interfaces. This
option is mandatory.
Writes the process ID of the filter, once started, to the file-
-q Requests that messages which fail verification be quarantined by
the MTA. (Requires a sufficiently recent version of the milter
-R When a signature verification fails and the signing site adver-
tises a reporting address (i.e. r=user@host in its policy
record), send a structured report to that address containing
details needed to reproduce the problem.
Gives the location of a PEM-formatted private key to be used for
Defines the name of the selector to be used when signing mes-
sages. See the DomainKeys specification for details.
Sets the DNS timeout in seconds. A value of 0 causes an infi-
nite wait. The default is 5. Ignored if not using the asyn-
chronous resolver package. See also the NOTES section below.
Attempts to be come the specified userid before starting opera-
Requests that the filter consult a POP authentication database
for IP addresses that should be allowed for signing. The filter
must be specially compiled to enable this feature, since it adds
a library dependency.
-V Print the version number and exit without doing anything else.
The value of the -C switch is a comma-separated list of settings of the
form result=action which defines what the filter should do with mes-
sages that produce certain results. Each result and each action has a
full name and an abbreviated name. Either is accepted. Below, the
abbreviated name appears in parentheses.
badsignature (bad) the signature found in the message did not
verify successfully against the message; dnserror (dns) an error
was encountered attempting to retrieve a public key from the
nameserver; internal (int) an internal error occurred; nosigna-
ture (no) no signature was present on the message; signature-
missing (miss) no signature was present on the message which
claims to sign all messages.
action accept (a) accept the message; discard (d) discard the message;
tempfail (t) temp-fail the message; reject (r) reject the mes-
In the interests of minimal initial impact, the defaults for badsigna-
ture, nosignature and signaturemissing are all accept, and the default
for the others is tempfail.
A message will be verified unless it conforms to the signing criteria,
which are: (1) the domain on the From: address or Sender: address (if
present) must be listed by the -d command line switch, and (2) the
client connecting to the MTA must (a) have authenticated, or (b) be
listed in the file referenced by the -i command line switch (or be in
the default list for that option), or (c) be connected to daemon port
named by the -m command line switch.
When signing a message, a DomainKey-Signature: header will be prepended
to the message. The signature is computed using the private key pro-
vided. You must be running a version of sendmail(8) recent enough to
be able to do header prepend operations (8.13.0 or later).
When verifying a message, an Authentication-Results: header will be
prepended to indicate the presence of a signature and whether or not it
could be validated against the body of the message using the public key
advertised by the sender's nameserver. The value of this header can be
used by mail user agents to sort or discard messages that were not
signed or could not be verified.
The following environment variable(s) can be used to adjust the behav-
iour of this filter:
The directory to use when creating temporary files. The default
When using DNS timeouts (see the -T option above), be sure not to use a
timeout that is larger than the timeout being used for interaction
between sendmail and the filter. Otherwise, the MTA could abort a mes-
sage while waiting for a reply from the filter, which in turn is still
waiting for a DNS reply.
This man page covers version 1.0.1 of dk-filter.
If you have any
comments, you can contact the author here