Sendmail, the SPF, the DKIM, and the Spam

In my first post, I talked about how to configure a server with Sendmail, to make it use SMTP Authentication, and to make it use certificate to connect to your server via SSL : Secured Sendmail with SMTP Authentication

The next step is to tell everyone that mails from your domain can only be sent from your mail server. There are a few ways to do this.
And at last we also would want spams to be detected.

  1. SPF (and SenderID)
  2. DKIM (OpenDKIM)
  3. Spams (SpamAssasin and ClamAV)

1. SPF (and SenderID)

SPF is an acronym for Sender Policy Framework. ( http://en.wikipedia.org/wiki/Sender_Policy_Framework )
SenderID is another solution to the problem of message validation.

Let's consider you've already added a MX record in your DNS zone list for "host.com" :

mail 10800 IN A
@ 10800 IN MX 0 mail.host.com.

Since I don't want e-mails in my domain to be used by spammers, to tell everyone clearly emails from your domain comes from it is to add a TXT record to your zone list :

@ 10800 IN TXT v=spf1 ip4: a mx -all

What does this record do ? http://www.openspf.org/SPF_Record_Syntax
  • ip4:
    • allows this IPv4 to send mails for the domain
  • a
    • allows domain's A records to send mails for the domain
  • mx
    • allows domain's MX records to send mails for the domain
  • -all
    • prohibit all others to send mails for the domain
That's exactly what I need. And this should be it for the DNS zone records.

To check the sender id, you also can install a mail filter (milter) to sendmail, and check this page :

On FreeBSD, you can use "/usr/ports/mail/sid-milter". Once it's installed, you have to configure sendmail to use it, edit you /etc/mail/mail.host.com.mc and add :

define(`confINPUT_MAIL_FILTERS', `sid-filter')dnl

then, you add in /etc/rc.conf to tell the server to start it :

miltersid_flags="-r 0 -t -h"

To start the SenderID milter :

/usr/local/etc/rc.d/milter-sid start

And finally restart sendmail and use sid-milter :

# cd /etc/mail
# make all install restart

2. DKIM with OpenDKIM

DKIM is an acronym for Domain Keys Identified Mail.

When I first search about how to install DKIM, there were only a few message telling that dkim-filter would soon be obsolete, and so that one should use OpenDKIM instead. I can see now that there are posts about this and this one can summarize nicely how to use it even though it's about postfix :

here are the command I used mostly (/bin/csh) :

# cd /usr/ports/mail/opendkim
# make config

Check FILTER if it's not, since we want a sendmail milter

# setenv BATCH 1
# make install clean
# unsetenv BATCH
# cd /usr/local/etc/mail/
# cp opendkim.conf.sample opendkim.conf
# vi /opendkim.conf

Once you're editing your configuration file, you can use these options, they are mostly secure. Either uncomment or just replace the whole file if you don't care (anyway, you still have the sample file) :

Domain host.com
KeyFile /var/db/dkim/dkim.key.pem
Selector dkim
Canonicalization relaxed/simple
UserID mailnull
ReportAddress "DKIM Error Postmaster" <postmaster@host.com>
Socket local:/var/run/milteropendkim/dkim-filter
Syslog Yes

Then you have to create the key file to sign your mail headers :

# mkdir -p /var/db/dkim
# cd /var/db/dkim
# openssl genrsa -out rsa.private
# openssl rsa -in rsa.private -out rsa.public -pubout PEM
# mv rsa.private dkim.key.pem
# chmod 600 dkim.key.pem

Again, we want everyone to know that we are using DKIM. So we're going to add an other TXT record in the DNS zone list for host.com, and we are using the rsa.public file without the ----BEGIN PUBLIC KEY----- and the -----END PUBLIC KEY-----, and also each lines should be concatenated to one single line :

dkim._domainkey 10800 IN TXT "v=DKIM1; g=*; k=rsa; p=MIGfMA0GCSqGSIb3DQ......ndSUOxbGQhnVbYOD6X49Z9jEtmBJPn1IowIDAQAB"

._domainkey is required, it's part of the standard. "dkim" is the selector you set in the opendkim.conf.

Save your zone list, hope your DNS servers will propagate the information.
Now, we have to configure sendmail to accept the milter, edit your /etc/mail/mail.host.com.mc and add these lines :

INPUT_MAIL_FILTER(`dkim-filter', `S=local:/var/run/milteropendkim/dkim-filter, F=T, T=R:2m')
define(`confINPUT_MAIL_FILTERS', `sid-filter,dkim-filter')dnl

Then edit your /etc/rc.conf and add :


Now start the milter :

/usr/local/etc/rc.d/milter-opendkim start

Finally compile your .mc changes and restart sendmail :

# cd /etc/mail
# make all install restart

If everything is set correctly, you should now be able to send signed mail headers with DKIM, which is informing clearly other mail servers or receipts that you really sent a mail from the domain.

In GMail, this can look like :

DKIM sample

The "signed-by:" is the DKIM, and the "mailed-by:" is the SPF.

3. Spam filtering with SpamAssassin (and ClamAV)

I'm not sure exactly why but when I think about spams, I'm thinking about "nice" words ... Anyways, from the first day I've used mails and tried to find informations about mail servers, I've always heard / read about SpamAssassin.
So let's install SpamAssassin, the service :

# cd /usr/ports/mail/p5-Mail-SpamAssassin
# make config

These are the options preferably checked :
[*] AS_ROOT        Run spamd as root (recommended)
[*] SPAMC          Build spamd/spamc (not for amavisd)
[*] DKIM           DKIM/DomainKeys Identified Mail
[*] SSL            Build with SSL support for spamd/spamc
[*] GNUPG          Install GnuPG (for sa-update)
[*] RAZOR          Add Vipul's Razor support
[*] SPF_QUERY      Add SPF query support

Then (with /bin/csh) :

# setenv BATCH 1
# make install clean
# unsetenv BATCH

Once installed :

# cd /usr/local/etc/mail/spamassassin
# cp local.cf.sample local.cf

It's probably not needed, but you could edit your local.cf file to change things suiting your needs, but basically it's already nice as it is. We'll set the rest in /etc/rc.conf adding :


The optional flag "-A" tells spamd to limit connection to our public ip address.
Update SpamAssassin rules as root :

# sa-update

And finally launch the service :

# /usr/local/etc/rc.d/sa-spamd start

Now the service is installed and running ... let's installed the sendmail milter :

# cd /usr/ports/mail/spamass-milter
# make config

I'm not using IPv6 for now, so here is what's only checked :

 [*] ADDAUTH_PATCH     Bypass checks for SMTP AUTH connections

Run the install :

# setenv BATCH 1
# make install clean
# unsetenv BATCH

Once the milter is installed, edit your /etc/mail/mail.host.com.mc file, and add :

INPUT_MAIL_FILTER(`spamassassin', `S=local:/var/run/spamass-milter/spamass-milter.sock, F=, T=C:15m;S:4m;R:4m;E:10m')
define(`confINPUT_MAIL_FILTERS', `sid-filter,dkim-filter,spamassassin')dnl

define(`confMILTER_MACROS_CONNECT',`t, b, j, _, {daemon_name}, {if_name}, {if_addr}')dnl
define(`confMILTER_MACROS_HELO',`s, {tls_version}, {cipher}, {cipher_bits}, {cert_subject}, {cert_issuer}')dnl
define(`confMILTER_MACROS_ENVRCPT',`r, v, Z')dnl


FEATURE(`dnsbl', `zen.spamhaus.org', `"550 Mail from " $`'&{client_addr} " refused - see http://www.spamhaus.org/"')
FEATURE(`dnsbl', `dul.dnsbl.sorbs.net', `"550 Mail from " $`'&{client_addr} " refused - see http://www.dul.dnsbl.sorbs.net/"')
FEATURE(`dnsbl', `bl.spamcop.net', `"450 Mail from " $`'&{client_addr} " refused - see http://spamcop.net/bl.shtml"')

Save your file.
To explain : we add the milter and we define some macro for SpamAssassin to work with encryption. Then we tell sendmail to delay the e-mails checks on DNS Black Lists. Then ZEN list is a mix of the different types of lists at SpamHaus, and the two others are well know blacklists. It seems just the three of them is detecting spams nicely.

Now edit /etc/rc.conf to tell the milter to be able start :

spamass_milter_localflags="-i, -u spamd -- -u spamd"

The most important to understand here is the spamass_milter_localflags, where we tell the milter to ignore "-i" messages if the originating IP is in the parameter list, here defined to ",". You can always add IP Addresses here and restart the milter.
Let's start it :

# /usr/local/etc/rc.d/spamass-milter start

Then let's sendmail know about our changes and restart it :

# cd /etc/mail
# make all install restart

Sendmail should be running. You can check for errors inside /var/log/maillog

An option package you could install, I didn't search for advanced configuration, it's to use ClamAV to check your mails for viruses. If you think you can trust what's in your mails, you're not force to install it, but here is how I'd do (again with /bin/csh):

# cd /usr/ports/security/clamav-milter
# setenv BATCH 1
# make install clean
# unsetenv BATCH

Then edit your /etc/mail/mail.host.com.mc and add :

INPUT_MAIL_FILTER(`clmilter',`S=local:/var/run/clamav/clmilter.sock, F=, T=S:4m;R:4m')
define(`confINPUT_MAIL_FILTERS', `sid-filter,dkim-filter,spamassassin,clmilter')dnl

Then edit /etc/rc.conf to be able to start the clamav milter :

clamav_freshclam_flags="--daemon --checks=12"

The clamav_freshclam_flags tells clamav to refresh its database every 12 hours.
Let's start the services :

# /usr/local/etc/rc.d/clamav-clamd start
# /usr/local/etc/rc.d/clamav-milter start
# /usr/local/etc/rc.d/clamav-freshclam start

and then restart sendmail with changes :

# cd /etc/mail
# make all install restart

This is it for this post.
Next post will be about how to install IMAP service, and to be able to connect to IMAP service with SSL.