Gentoo Wiki


This article is part of the HOWTO series.
Installation Kernel & Hardware Networks Portage Software System X Server Gaming Non-x86 Emulators Misc



This article is designed to create an Exim based mail server for almost any use, home to business.

Note: Work in progress...

Software Used






Initial Modifications

If you are planning to use DKIM you will need to modify the Exim ebuild, as well as download a beta libdkim-exim ebuild.

Please see:

Exim Setup

Exim has a large amount of USE flags and optional items, so here we are going to run through them. This USE line is from the modified Exim ebuild ( See bug 205814 )

USE="exiscan-acl ipv6 lmtp mysql pam perl sqlite ssl tcpd -X -dkim% -dnsdb -domainkeys -dovecot-sasl -exiscan -gnutls -ldap -mailwrapper -mbox -mbx -nis -postgres -radius -sasl -spf -srs -syslog"

A break down of the various parts:


Sender Police Framework (and SRS):

While it sounds good in theory, there are a lot of potential issues. See:

So we will be using DKIM with a fall back to DomainKeys. The possibility of using RPR ( Reverse-Path-Rewriting) will be shown as well.

A possibility might be to check for SPF, and accept the email anyway. Then add a header / edit subject to reflect the SPF status.

Base Preperations

Note: To install libdkim for exim, you will need to install the ebuild into your portage overlay
echo 'mail-mta/exim ssl dovecot-sasl exiscan-acl ldap gnutls dkim domainkeys syslog perl mysql spf srs'>>/etc/portage/package.use
emerge exim

Base configuration will be from the exiscan-acl patch:

cp /etc/exim/exim.conf.exiscan-acl /etc/exim/exim.conf

We will now work on configuring the individual parts

Exim Configuration

Exim's configuration file is broken down (internally) into 4 parts, making it easy to follow. Here we will break down the parts, and show some basic configurations. This all belongs in /etc/exim/exim.conf.

However, Debian splits up the configuration files, but if you create a /etc/exim/exim.conf it will use that and ignore the split up files.

Main Configuration Settings

This section allows you to define your specific setup. Items like domain names, and relaying hosts fit here. There are three types of configuration here:

Anything starting with acl_ is for defining the policy control for that specific section. ie: acl_smtp_mailauth - set ACL for AUTH on MAIL command

Base set up we will be using:

File: /etc/exim/exim.conf
# define our local domains, allowed relaying hosts and our qualified domain
domainlist local_domains = @ : lsearch;/usr/exim/local_domains
domainlist relay_to_domains =
hostlist   relay_from_hosts =
qualify_domain =

# define that we wish to check /etc/hosts before DNS
host_lookup_order = byaddr:bydns

# define that we do wish to ident check, and set timeout to 5 seconds
rfc1413_hosts = *
rfc1413_query_timeout = 5s

# Mandatory to use  "verify = helo"
helo_try_verify_hosts = !+relay_from_hosts

# define which ACL's we wish to use
# acl_check are subroutines defined in the ACL section
acl_smtp_rcpt = acl_check_rcpt 
acl_smtp_mail = acl_check_sender
acl_smtp_connect = acl_check_host
acl_smtp_data = acl_check_data
acl_smtp_helo = acl_check_helo

# set a max message size
message_size_limit = 10M

# What antivirus engine we using ?
av_scanner = clamd:/var/run/clamav/clamd.sock

# for F-Prot
# av_scanner = cmdline:/usr/local/bin/f-prot -archive -packed %s ; echo -e "\nfprot_retval $?":fprot_retval 3:Infection:: (.*)

# define our TLS
tls_certificate = /etc/exim/rsa.cert
tls_privatekey = /etc/exim/rsa.key
tls_dhparam = /etc/exim/dh.key

domainlist local_domains = @ : lsearch;/usr/exim/local_domains

This section, defines that exim is to search in the text file /usr/exim/local_domains for a list of domains. It is possible to use LDAP lookup here:

domainlist local_domains = ${tr {${lookup ldapm{ \
ldap://LDAP_HOST/ou=domains,LDAP_BASE?dc?one}}} {\n}{:}}

ACL Configuration

Thanks to exiscan-acl we can do a LOT of checking now at SMTP time, rather than in the work queue.




File: Check Hosts


  # Check the incoming IP, if it's on our Relay list allow it
  accept hosts = +relay_from_hosts
       log_message = match host_reject.list
       hosts = /etc/exim/lists/host_reject.list

  # Check IP address in DNS based blacklists
  deny hosts    = !+rbl_white_hosts
       message  = Host is listed in $dnslist_domain.
       dnslists = \ : \ : \ : \ : \ : \


File: Check Recipient

  # Add missing Date and Message-ID header for relayed messages
      hosts = +relay_from_hosts
      control = submission/sender_retain

  # Remove emails source routing + dangerous character
  deny    domains       = +local_domains
          local_parts   = ^[.] : ^.*[@%!/|]
          message       = Restricted characters in address.

  # Allow our local senders a little less restricted rules
  deny    domains       = !+local_domains
          local_parts   = ^[./|] : ^.*[@%!] : ^.*/\\.\\./
          message       = Restricted characters in address.

  # The default configuration allows anything to send to postmaster
  # This is optional, and in a lot of cases it's recommended NOT to whitelist anything
  accept  local_parts   = postmaster


File: Check Helo

# check the helo domain is not pretending to be us
# replace HOSTNAME and IP with your details
  accept  hosts = +relay_from_hosts

  # If the HELO pretend to be this host
  deny    condition = ${if or { \
                       {eq {${lc:$sender_helo_name}}{HOSTNAME}} \
                       {eq {${lc:$sender_helo_name}}{IP}} \
                       } {true}{false} }

   # Helo should be FQDN
   deny hosts   = !+relay_from_hosts
   message = HELO should be Fully Qualified Domain Name  Host.Domain.Tld  See RFC821
   condition = ${if !match\

   # by default we accept


File: Check Content
  # DKIM check, only add a header
  warn message   = X-DKIM-Results: ${lookup dkim{$sender_address_domain}} ($sender_address_domain)

  # SPF check, only add a header
  warn message = $sender_host_address is not allowed to send mail from $sender_address_domain
       spf = fail:neutral

  # as per SPF draft/RFC2822 add the spf-recieved header BEFORE the first non-recieved header
  # warn message = :spf_received:$spf_received
  # Exim doesn't seem to do this correctly... 

  warn message = $sender_host_domain does not publish SPF
       spf = none

  warn message = X-SPF-Results: $received

  # Unpack MIME containers and reject serious errors.
  deny  message = This message contains a MIME error ($demime_reason)
        demime = *
        condition = ${if >{$demime_errorlevel}{2}{1}{0}}

  # Reject typically wormish file extensions. There is almost no
  # sense in sending such files by email.
  deny  message = This message contains an unwanted file extension ($found_extension)
        demime = scr:vbs:bat:lnk:pif

  # Now, spam scan what has passed our rules
  # any message under 80k is scanned, and a X-Spam-Score added
  # anything that scores above 4, gets a spam report added, and
  # above 5 is rejected
  warn message   = X-Spam-Score: $spam_score ($spam_bar).
        condition = ${if <{$message_size}{80k}{1}{0}}
        spam      = nobody:true
   warn message   = X-Spam-Report: $spam_report
        condition = ${if <{$message_size}{80k}{1}{0}}
        spam      = nobody:true
        condition = ${if >{$spam_score_int}{40}{1}{0}}
   deny message   = This message scored $spam_score spam points.
        condition = ${if <{$message_size}{80k}{1}{0}}
        spam      = nobody:true
        condition = ${if >{$spam_score_int}{50}{1}{0}}

# If anything has gotten past the previous we AntiVirus scan it
  deny  message = This message contains malware ($malware_name)
        demime = *
        malware = *

  # Add X-Scanned Header
  warn message = X-Antivirus-Scanned: Clean
current: add dspam via exiscan

Routers Configuration

This section of the configuration is for us to work out how to route an email to it's final destination. It's pretty advanced, and allows us to do lookups against almost anything. It's very very important to get the order correct here, as Exim will work through them sequentially.

I strongly recommend against enabling domain_literal, as the configuration file says, it can be exploited. Generally here you will not need to edit much, as it's set up to run in this order

1 DNS Lookup for Non-local domains - Normally for outbound, or any domains you are relaying for
2 Systems Aliases - This checks the default /etc/mail/aliases, just like sendmail
3 User Forwards - This part handles traditional .forward files. To use Exim filtering, add 'allow_filter'
4 Local User - The last rule checks if it can find an actual local user on the device.

Enabling routing to DoveCot - non-SQL Virtual Users1

  # Router to send any mail for who a dovecot user exists to the appropriate maildir box
  # Routers are evaluated in order of configuration.
  # You will want to place this after the remote router and before the
  # localuser router in the default configuration.
  # If you want to allow + addressing (ie having an address extension)
  # then uncomment the suffix stanzas 
    driver = accept
    #local_part_suffix = +*
    require_files = +/home/dovecot/users/${local_part}/
    transport = dovecot_transport

Using LDAP Alias routing

This example would look up in LDAP, and then use the homeMDB field as an alias.

File: richard.ldif
 dn: cn=richard,ou=engineering,dc=company,dc=com
 homeMDB: rgwilliam
 objectClass: top
 objectClass: person
 objectClass: organizationalPerson
 objectClass: user
 cn: Richard Gwilliam

   driver = redirect
   data = ${lookup ldap {ldap://$local_part,\
   file_transport = address_file
   pipe_transport = address_pipe

Transport Configuration

Transports are used by a Router, they define how the delivery should be carried out.

If we look at the routers, you will see normally an entry like:

 file_transport = address_file
 pipe_transport = address_pipe

This defines what transport to use for this router. The default transports can generally be left alone. However, we need to add a transport for Dovecot

File: Dovecot Non-SQL Virtual Transport
# Transport to send any mail for who a dovecot user exists to the appropriate maildir box
  driver = appendfile
  user = dovecot
  group = dovecot
  mode = 0600
  maildir_format = true
  mode_fail_narrower = false
  envelope_to_add = true
  return_path_add = true

SMTP Authentication

DKIM Configuration - Outbound

Signing examples:

  driver = smtp
  dkim_selector = whizbang-dkim
  dkim_domain = DKIM_DOMAIN
  dkim_private_key = DKIM_PRIVATE_KEY
  dkim_strict = 0
  dkim_canon = relaxed

Where the macros are defined as:

DKIM_DOMAIN = ${lc:${domain:$h_from:}}
DKIM_FILE = /etc/exim/dkim/${lc:${domain:$h_from:}}.priv

Dovecot Configuration

To let dovecot use non-SQL Virtual users, we need to define where the users are and what password file to use.

* /home/dovecot/users - where the users are stored
* /home/dovecot/passwd - the htpasswd file dovecot will use
auth default {
  userdb static {
    args = uid=500 gid=500 home=/home/dovecot/users/%u
  passdb passwd-file {
    args = /home/dovecot/passwd

OpenLDAP Configuration


sorting out what happens in local delivery

# exim -d+route -bt

Further Reading




Sources for Further Reading:

Retrieved from ""

Last modified: Thu, 04 Sep 2008 05:18:00 +0000 Hits: 3,404