Exim
Exim is a powerful and the most popular Mail Transfer Agent (MTA). It's reported to have a 57% market share[1]. Also, Exim is the default MTA for Debian / Ubuntu.
Pre-installation
As only one MTA can be installed at the same time on a system, it might be required to remove an installed MTA. The package manager will report a block when another MTA is still installed. This block can resolved by manually deselecting the old mail server. For example, preparing to remove mail-mta/ssmtp (which might have been installed as the default when a program requested a mail server to be installed) with this command:
root #
emerge --deselect mail-mta/ssmtp
Installation
USE flags
USE flags for mail-mta/exim A highly configurable, drop-in replacement for sendmail
X
|
Add support for X11 |
arc
|
Adds support for Authenticated Receive Chain (ARC) |
berkdb
|
Add support for sys-libs/db (Berkeley DB for MySQL) |
dane
|
Adds support for DNS-based Authentication of Named Entities |
dcc
|
Adds support for Distributed Checksum Clearinghouse (DCC) |
dkim
|
Adds support for DomainKeys Identified Mail (DKIM) |
dlfunc
|
Install local_scan.h header to compile separate dlfunc libraries |
dmarc
|
Adds support for DMARC |
dnsdb
|
Adds support for a DNS search for a record whose domain name is the supplied query |
doc
|
Add extra documentation (API, Javadoc, etc). It is recommended to enable per package instead of globally |
dovecot-sasl
|
Adds support for Dovecot's authentication |
dsn
|
Adds support for Delivery Status Notifications (DSN) |
exiscan-acl
|
Patch providing support for content scanning |
gdbm
|
Add support for sys-libs/gdbm (GNU database libraries) |
gnutls
|
Prefer net-libs/gnutls as SSL/TLS provider (ineffective with USE=-ssl) |
idn
|
Enable support for Internationalized Domain Names |
ipv6
|
Add support for IP version 6 |
ldap
|
Add LDAP support (Lightweight Directory Access Protocol) |
lmtp
|
Adds support for lmtp |
maildir
|
Add support for maildir (~/.maildir) style mail spools |
mbx
|
Adds support for UW's mbx format |
mysql
|
Add mySQL Database support |
nis
|
Support for NIS/YP services |
pam
|
Add support for PAM (Pluggable Authentication Modules)DANGEROUS to arbitrarily flip |
perl
|
Add optional support/bindings for the Perl language |
pkcs11
|
Require pkcs11 support in net-libs/gnutls with USE=gnutls |
postgres
|
Add support for the postgresql database |
prdr
|
Adds support for Per-Recipient Data Response |
proxy
|
Add support for being behind a proxy, such as HAProxy |
radius
|
Add support for RADIUS authentication |
redis
|
Adds support for querying dev-db/redis |
sasl
|
Add support for the Simple Authentication and Security Layer |
selinux
|
!!internal use only!! Security Enhanced Linux support, this must be set by the selinux profile or breakage will occur |
socks5
|
Add support for the socks5 proxy |
spf
|
Adds support for Sender Policy Framework |
sqlite
|
Add support for sqliteembedded sql database |
srs
|
Adds support for Sender Rewriting Scheme |
ssl
|
Add support for SSL/TLS connections (Secure Socket Layer / Transport Layer Security) |
syslog
|
Enable support for syslog |
tcpd
|
Add support for TCP wrappers |
tdb
|
Use sys-libs/tdb for internal database storage (such as hints database) |
tpda
|
Adds support for Transport Post-Delivery Actions |
For a typical install, install mail-mta/exim with the following use flags:
/etc/portage/package.use/exim
mail-mta/exim dkim exiscan-acl maildir prdr spf ssl syslog
To use dovecot as your POP/IMAP server and want to make exim use dovecot's authentication services, add a use flag for dovecot-sasl.
/etc/portage/package.use/exim
mail-mta/exim dovecot-sasl dkim exiscan-acl maildir prdr spf ssl syslog
To use a database to manage what mailboxes and what aliases exist, add a use flag for the database to use, e.g. postgres, sqlite, etc.
/etc/portage/package.use/exim
mail-mta/exim dkim exiscan-acl maildir prdr spf sqlite ssl syslog
Emerge
Finally, install exim with:
root #
emerge --ask mail-mta/exim
Complete mailserver
For a complete mailserver, you'll typically also want to install a POP/IMAP server, such as dovecot or courier-imap. These so-called MDAs tightly integrate with Exim (your MTA) and possibly your database.
Also, you might want to install a webmail server, such as Squirrelmail or Roundcube, which will also integrate with your MTA, MDA and database.
Configuration
The exim ebuild creates a small number of configuration files in /etc/exim, namelyː auth_conf.sub exim.conf exim.conf.exiscan-acl and system_filter.exim. Of these files, the main configuration file is /etc/exim/exim.conf.
This exim.conf file can include several sectionsː
- General options, setting up parameters such as hostname and domains, hooking up ACL's, SSL/TLS settings, ports and logging.
- ACL, where specific rules can be written for different phases of the SMTP protocol for incoming e-mail.
- Routers, which determine based on the addresses of the e-mail to which exim-transport the message should be routed
- Transports, for actually delivering e-mails (either remotely, or locally)
- Retry, because we might not want to give up after the first attempt
- Rewrite, in case we want to touch content of the e-mail or its headers
- Authenticators, as we only want to send e-mails out into the world if it was submitted by someone we trust
- Local_scan, in case *really* specific scanning hook-ups are needed
Modern mail security (SPF/DKIM/DMARC)
With the rise of security in computing, mail security is also improving. After a number of solutions have been tried, the mailserver community seems to have settled on the combination of SPF, DKIM and DMARC.
SPF:
- SPF focuses on Envelope-From (aka Return-Path, MAIL FROM, Bounce address)
- SPF authenticates the IP of the sending server against SPF sending server policy
- SPF does not require alignment between Header-From and Envelope-From
- SPF does not survive forwarding and indirect mail-flows
- SPF does not tell the receiving server what it should do with messages that fail SPF
DKIM:
- DKIM focuses on asymmetrical crypto and control over DNS records
- DKIM crypto-proves the d= domain signed the e-mail
- DKIM crypto-proves the integrity of headers and/or body
- DKIM does not require alignment between Header-From and d= domain
- DKIM may survive forwarding and indirect mail-flows depending on what parts were signed
- DKIM does not tell the receiving server what it should do with messages that fail DKIM
DMARC:
- DMARC requires alignment between Header-From and Envelope-From used by SPF and/or d= domain field in DKIM signature
- DMARC ignores the difference in SPF between hard fail (-all) and soft fail (~all) and treats both as fail
- DMARC allows defining a policy that receivers can follow for messages that fail SPF and/or DKIM tests
- DMARC allows reporting mailboxes to be defined
Example for SPF, DKIM with SQLite and Maildir
This configuration enables SPF and DKIM, but only adds warning headers, it doesn't quarantine or reject e-mails. Further it uses SQLite for managing what mailboxes and aliases exist, and stores mails in a special directory in Maildir format.
/etc/exim/exim.conf
# Explicitly set our HELO name primary_hostname = mailserver.example.com # Define domain lists domainlist local_domains = example.com : crossexample.net : @ hostlist relay_from_hosts = 127.0.0.1 : localhost # Connect access control lists to their hooks acl_smtp_connect = acl_check_connect acl_smtp_helo = acl_check_helo acl_smtp_mail = acl_check_mail_from acl_smtp_dkim = acl_check_dkim acl_smtp_rcpt = acl_check_rcpt acl_smtp_data = acl_check_data # Allow any client to use TLS tls_advertise_hosts = * # Specify the location of the Exim server's TLS certificate and private key tls_certificate = /etc/ssl/mailserver.example.com-signed.crt tls_privatekey = /etc/ssl/private/mailserver.example.com.key # Set modern ciphers (assuming gentoo default of exim with openssl) tls_require_ciphers = TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-256-GCM-SHA384:TLS13-AES-128-GCM-SHA256:EECDH+CHACHA20:EECDH+AESGCM:EECDH+AES tls_dhparam = /etc/ssl/private/dhparam.pem openssl_options = +no_sslv2 +no_sslv3 # Support acting as smtp.example.com server for users outside our network daemon_smtp_ports = 25 : 587 # tls_on_connect_ports = 465 (required for Microsoft clients) # Add our domain to 'unqualified addresses', instead of our server name qualify_domain = example.com # Perform rDNS lookups for incoming connections, so we can confirm their HELO host_lookup = * # Advertise PRDR to accept/reject multi-recipient mails per-user prdr_enable = true # Specify what should be logged. log_selector = +smtp_protocol_error +smtp_syntax_error \ +tls_certificate_verified # Prevent clogging the queue when mail delivery and return-to-sender both fail ignore_bounce_errors_after = 2d timeout_frozen_after = 7d # If we don't set the following option, Exim will complain mildly keep_environment = ################### # ACL CONFIGURATION ################### begin acl # Work through the SMTP protocol # Trigger on an incoming connection acl_check_connect: # Record the current timestamp, in order to delay crappy senders warn set acl_m0 = $tod_epoch # Warn if reverse DNS lookup failed. Note: later we compare rDNS with HELO warn !verify = reverse_host_lookup set acl_c1 = X-DNS-Warning: Couldn't lookup reverse DNS for ${sender_host_address} # Set up for finalisation: write to log warn condition = ${if def:acl_c1 {true}{false} } logwrite = $acl_c1 # On error: accept but stall (good actors tend to be patient) accept set acl_m0 = ${if def:acl_c1 {${eval:20 + $acl_m0 - $tod_epoch} }{0} } delay = ${if >{$acl_m0}{0}{$acl_m0}{0} }s # Trigger on the HELO/EHLO of incoming connections. acl_check_helo: # Record the current timestamp, in order to delay crappy senders warn set acl_m0 = $tod_epoch # Warn if sender did not provide a HELO/EHLO greeting warn condition = ${if !def:sender_helo_name {true}{false} } set acl_c2 = X-HELO-Warning: Remote host $sender_host_address \ did not present HELO/EHLO greeting. # Warn if sender greeted with an IP address (technically correct, but crappy) warn condition = ${if !def:acl_c2 {true}{false} } condition = ${if isip {$sender_helo_name}{true}{false} } set acl_c2 = X-HELO-Warning: Remote host $sender_host_address \ used IP address instead of hostname in HELO/EHLO # Warn if sender pretended to be us (they may think that would trick us) warn condition = ${if !def:acl_c2 {true}{false} } condition = ${if match_domain{$sender_helo_name}\ {$primary_hostname:+local_domains}{true}{false} } set acl_c2 = X-HELO-Warning: Remote host $sender_host_address \ used our name in HELO/EHLO but it is not defined in \ our +local_domains # Warn if HELO verification fails, e.g. rDNS of IP != HELO domain warn condition = ${if !def:acl_c2 {true}{false} } !verify = helo set acl_c2 = X-HELO-Warning: Remote host ${if def:sender_host_name \ {$sender_host_name ($sender_host_address) }\ {$sender_host_address } }\ incorrectly presented itself as $sender_helo_name # Set up for finalisation: write to log warn condition = ${if def:acl_c2 {true}{false} } logwrite = $acl_c2 # On error: accept but stall (good actors tend to be patient) accept set acl_m0 = ${if def:acl_c2 {${eval:20 + $acl_m0 - $tod_epoch} }{0} } delay = ${if >{$acl_m0}{0}{$acl_m0}{0} }s # Trigger on MAIL FROM: command. Here we perform SPF checks. acl_check_mail_from: # Skip SPF checks for all authenticated connections (probably MUAs) accept authenticated = * # Record the current timestamp, in order to delay crappy senders warn set acl_m0 = $tod_epoch # Query if we can find an SPF policy for the sending domain warn spf = none:temperror:permerror set acl_c3 = X-SPF-Warning: can't find SPF policy for \ $sender_address_domain # Query if the sending domain has set a useful SPF policy warn condition = ${if !def:acl_c3 {true}{false} } condition = ${if match {${lookup dnsdb{txt=$sender_address_domain}{$value} } }{\\+all} } set acl_c3 = X-SPF-Warning: $sender_address_domain allows +all in SPF policy # Query the SPF policy whether sender was authorized to deliver this message # Note: fail = '-all', softfail = '~all', neutral = '?all' warn spf = fail:softfail:neutral condition = ${if !def:acl_c3 {true}{false} } set acl_c3 = X-SPF-Warning: $sender_host_address is not allowed to \ send mail for $sender_address_domain # Add a SPF-Received: line to the message header (regardless of SPF status) warn add_header = $spf_received # Set up for finalisation: add all headers and write to log warn condition = ${if def:acl_c3 {true}{false} } logwrite = $acl_c3 add_header = $acl_c1 add_header = $acl_c2 add_header = $acl_c3 # On error: accept but stall (good actors tend to be patient) accept set acl_m0 = ${if or { {def:acl_c1}{def:acl_c2}{def:acl_c3} } {${eval:20 + $acl_m0 - $tod_epoch} }{0} } delay = ${if >{$acl_m0}{0}{$acl_m0}{0} }s # This access control list is used to process DKIM status. acl_check_dkim: # Skip DKIM checks for all authenticated connections (probably MUAs) accept authenticated = * # Record the current timestamp, in order to delay crappy senders warn set acl_m0 = $tod_epoch # Warn no DKIM warn dkim_status = none set acl_c4 = X-DKIM-Warning: No signature found # RFC 8301 requires 'permanently failed evaluation' for DKIM signatures signed with 'historic algorithms (currently, rsa-sha1)' # @SEE: https://www.exim.org/exim-html-current/doc/html/spec_html/ch-dkim_and_spf.html warn condition = ${if !def:acl_c4 {true}{false} } condition = ${if eq {$dkim_verify_status}{pass} } condition = ${if eq {${length_3:$dkim_algo} }{rsa} } condition = ${if or { {eq {$dkim_algo}{rsa-sha1} } \ {< {$dkim_key_length}{1024} } } } set acl_c4 = X-DKIM-Warning: forced DKIM failure (weak hash or short key) set dkim_verify_status = fail set dkim_verify_reason = hash too weak or key too short # RFC6376 requires that verification fail if the From: header is not included in the signature # @SEE: https://www.exim.org/exim-html-current/doc/html/spec_html/ch-dkim_and_spf.html warn condition = ${if !def:acl_c4 {true}{false} } condition = ${if !inlisti{from}{$dkim_headernames}{true}{false} } set acl_c4 = X-DKIM-Warning: From: header not included in the \ signature, this defies the purpose of DKIM # Warn invalid or failed signatures warn condition = ${if !def:acl_c4 {true}{false} } dkim_status = fail:invalid set acl_c4 = X-DKIM-Warning: verifying signature of $dkim_cur_signer \ failed for $sender_address because $dkim_verify_reason # Add a DKIM-Received: line to the message header (regardless of DKIM status) warn add_header = Received-DKIM: $dkim_verify_status ${if \ def:dkim_cur_signer {($dkim_cur_signer with \ $dkim_algo for $dkim_headernames)} } # Set up for finalisation: add header and write to log warn condition = ${if def:acl_c4 {true}{false} } add_header = $acl_c4 logwrite = $acl_c4 # On error: accept but stall (good actors tend to be patient) accept set acl_m0 = ${if def:acl_c4 {${eval:20 + $acl_m0 - $tod_epoch} }{0} } delay = ${if >{$acl_m0}{0}{$acl_m0}{0} }s # Trigger on RCPT of incoming message. acl_check_rcpt: # Test empty sending host field to accept local SMTP (i.e. not over network) accept hosts = : control = dkim_disable_verify # Strange non-alphanumeric characters may indicate a user trying to trick us; # 1/2: incoming mail address may not begin with . or contain @ % ! / or | deny message = Restricted characters in address domains = +local_domains local_parts = ^[.] : ^.*[@%!/|] # 2/2: outgoing mail address may not begin with . / or | and neither may it # contain @ % ! or the sequence /../ (this is slightly looser than 1/2) deny message = Restricted characters in address domains = !+local_domains local_parts = ^[./|] : ^.*[@%!] : ^.*/\\.\\./ # Deny unless we have a route to deliver mail back to the sender address require verify = sender # Skip other checks for all authenticated connections (probably MUAs), set # submission mode and assume MUAs send address in From: that includes @domain accept authenticated = * control = submission/sender_retain control = dkim_disable_verify add_header = X-Authenticated-Sender: ${sender_address} set acl_c_authenticated = 1 # Insist that a HELO/EHLO was accepted. require message = nice hosts say HELO first condition = ${if def:sender_helo_name} # Insist that any other recipient address is in one of our local domains require message = relay not permitted domains = +local_domains # Ensure we can deliver the message before we accept it require verify = recipient # If it got through to this point, accept it without further checks accept # Message has been received, now we can check its contents (headers, body, etc) # Note: here we can invoke external virus or spam scanners, if available acl_check_data: # Deny if the message contains an overlong line, as per the standards deny message = maximum allowed line length is 998 octets, \ got $max_received_linelength condition = ${if > {$max_received_linelength}{998} } # Deny if the headers contain badly-formed addresses. deny !verify = header_syntax message = header syntax logwrite = header syntax ($acl_verify_message) # Deny if the message contains a virus. Before enabling this check, you # must install a virus scanner and set the av_scanner option above. # deny # malware = * # message = This message contains a virus ($malware_name). # Add headers to a message if it is judged to be spam. Before enabling this, # you must install SpamAssassin. You may also need to set the spamd_address # option above. # warn # spam = nobody # add_header = X-Spam_score: $spam_score\n\ # X-Spam_score_int: $spam_score_int\n\ # X-Spam_bar: $spam_bar\n\ # X-Spam_report: $spam_report # Accept the message. accept logwrite = Received message from $sender_address_domain ######### # ROUTERS ######### begin routers # --- # Routers that handle addresses in remote domains (! +local_domains). # --- # Route addresses by doing a DNS lookup on the domain name. # Domains that resolve to 0.0.0.0 or to loopback (127.0.0.0/8) are treated as # if they have no DNS entry: lookup fails, 'no_more' intervenes and the # address is handled as unrouteable. dnslookup: driver = dnslookup driver = dnslookup domains = ! +local_domains transport = remote_smtp ignore_target_hosts = 0.0.0.0 : 127.0.0.0/8 no_more # --- # Routers that handle addresses in local domains ("domainlist local_domains"). # --- # If none of these routers picks up the message, "Unknown user" is returned to # sender. # This section is heavily dependent on your setup, especially how you wish to # manage the 'local_parts', i.e. what aliases exist, what mailboxes exist and # where mailboxes are stored. # Traditionally answers to these questions were files that have existed since # dawn of Unix tradition, but nowadays it's typical to put this in a database. # If you already administer one or more databases, you can use it here as well. # But if you don't, you can consider sqlite or flat files, so you don't need to # learn about database-upgrades, etc. This example uses an sqlite database. # If recepient is an alias, redirect it to the appropriate mailbox aliases: debug_print = "Redir: virtual_aliases for ${local_part}@${domain}" driver = redirect domains = +local_domains local_part_suffix = -* local_part_suffix_optional # Change the following two lines to reflect your database setup # condition = ${if eq{${local_part} }{${lookup sqlite {/path/to/db.sqlite SELECT alias FROM aliases WHERE domain='${quote_sqlite:$domain}' AND alias='${quote_sqlite:$local_part}'; } } # data = /path/to/mailboxes/${domain}/${lookup sqlite {/path/to/db.sqlite SELECT userid FROM aliases WHERE domain='${quote_sqlite:$domain}' AND alias='${quote_sqlite:$local_part}'; } } file_transport = redir_virtual_directory directory_transport = redir_virtual_directory # If recepient is a mailbox on its own, deliver the message. # This router treats local parts with suffixes introduced by "-" as if the # suffixes did not exist. E.g. xxxx-foo@your.domain will be treated # in the same way as xxxx@your.domain by this router. users: debug_print = "Acc: userid for ${local_part}@${domain}" driver = accept no_check_local_user domains = +local_domains local_part_suffix = -* local_part_suffix_optional # Change the following line to reflect your database setup # condition = ${if eq{${local_part} }{${lookup sqlite {/path/to/db.sqlite SELECT userid FROM users WHERE domain='${quote_sqlite:$domain}' AND userid='${quote_sqlite:$local_part}'; } } transport = accept_virtual_directory cannot_route_message = Unknown user ############ # TRANSPORTS ############ # Transports can only be called by a router picking up the message begin transports # --- # Transport for delivering over SMTP (e.g. outgoing e-mail) # --- # Refuse messages with over-long lines as per standard # Note: the use of message_size_limit is a red herring. remote_smtp: driver = smtp message_size_limit = ${if > {$max_received_linelength}{998} {1}{0} } dkim_domain = ${sender_address_domain} dkim_selector = dkim dkim_private_key = /etc/ssl/private/dkim-mailserver.example.com.key dkim_canon=relaxed # --- # Transport for delivering to local mailbox # --- # This transport is used for local delivery to user mailboxes w/ Maildir accept_virtual_directory: driver = appendfile maildir_format user = vmail group = vmail mode = 0600 directory = /path/to/mailboxes/${domain}/${local_part}/ delivery_date_add redir_virtual_directory: driver = appendfile maildir_format user = vmail group = vmail mode = 0600 ####### # RETRY ####### begin retry # Because we're not going to give up after our first attempt # Address or Domain Error Retries * * F,2h,15m; G,16h,1h,1.5; F,4d,6h ################ # AUTHENTICATION ################ begin authenticators # Authentication can be finicky to set up, but will also be needed by the # POP/IMAP server you will probably also be setting up. This example makes use # of dovecot to handle authentication for our SMTP clients. dovecot_login: driver = dovecot public_name = LOGIN server_socket = /var/run/dovecot/auth-client server_set_id = $auth1 dovecot_plain: driver = dovecot public_name = PLAIN server_socket = /var/run/dovecot/auth-client server_set_id = $auth1
Example for SpamAssasin, ClamAV with PostgreSQL and Maildir
This possibly outdated configuration uses SpamAssasin to filter spam, ClamAV to detect if e-mails contain virusses, PostgreSQL for managing what mailboxes exist, and stores mails in users' home directories in Maildir format.
/etc/exim/exim.conf
# Domain list configuration, each domain must be separated by ":" domainlist local_domains = example.com:otherdomain.com:anotherdomain.com:@ # On initial configuration we do not want to relay any other domain domainlist relay_to_domains = hostlist relay_from_hosts = 127.0.0.1 : ::::1/128 # ACL we want to be checked local_from_check = true acl_smtp_mail = acl_check_mail acl_smtp_rcpt = acl_check_rcpt acl_smtp_connect = acl_check_host acl_smtp_data = acl_check_data acl_smtp_helo = acl_check_helo # Postgresql Database connection hide pgsql_servers = localhost/db_maik/dbusername/dbpassword: # Set maximum parallel remote smtp remote_max_parallel = 24 # Define clamav configuration av_scanner = clamd:127.0.0.1 3310 # Spam configuration spamd_address = 127.0.0.1 783 # Allow use of TLS, we can have files here. tls_advertise_hosts = * # Set the key and cert to use tls_certificate = /etc/ssl/mail/mycert.pem tls_privatekey = /etc/ssl/mail/myprivate.key # Our default qualify domain qualify_domain = example.com begin acl # Force authentication for send email acl_check_mail: warn set acl_c_auth_deny = no set acl_c_deny_msg = Checking User accept sender_domains = !+local_domains: deny sender_domains = +local_domains !authenticated = * set acl_c_auth_deny = yes set acl_c_deny_msg = Authentication Needed for Send Mail message = Authentication Needed for Send Mail accept acl_check_rcpt: deny condition = $acl_c_auth_deny message = $acl_c_deny_msg deny hosts = : deny message = Restricted characters in address domains = +local_domains local_parts = ^[.] : ^.*[@%!/\|] deny message = Restricted characters in address domains = !+local_domains local_parts = ^[./|] : ^.*[@%!] : ^.*/\\.\\./ accept local_parts = postmaster domains = +local_domains require verify = sender accept authenticated = * control = submission/sender_retain require message = relay not permitted domains = +local_domains : +relay_to_domains require verify = recipient accept # Verify the host against black lists acl_check_host: deny hosts = !+relay_from_hosts message = Host is listed in $dnslist_domain. dnslists = \ cbl.abuseat.org : \ virbl.dnsbl.bit.nl : \ bl.spamcop.net : \ sbl.spamhaus.org : \ xbl.spamhaus.org accept # Check that the hello does not pretend to come from our servers acl_check_helo: accept hosts = +relay_from_hosts deny condition = ${if or { \ {eq {${lc:$sender_helo_name} }{example.com} } \ {eq {${lc:$sender_helo_name} }{10.100.0.100} } \ {eq {${lc:$sender_helo_name} }{127.0.0.1} } \ {eq {${lc:$sender_helo_name} }{localhost} } \ } {true}{false} } accept # ACL fot data acl_check_data: deny condition = ${if > {$max_received_linelength}{998} } deny malware = * message = This message contains a virus ($malware_name). warn spam = nobody add_header = X-Spam_score: $spam_score\n\ X-Spam_score_int: $spam_score_int\n\ X-Spam_bar: $spam_bar\n\ X-Spam_report: $spam_report deny message = Mensaje clasificado como SPAM spam = nobody:true condition = ${if >{$spam_score_int}{60}{1}{0} } begin routers dnslookup: driver = dnslookup domains = ! +local_domains transport = remote_smtp ignore_target_hosts = 0.0.0.0 : 127.0.0.0/8 : ::::1/128 no_more # Virtual aliases virtual_aliases: driver = redirect allow_fail allow_defer data = ${lookup{$local_part}lsearch{/etc/mail/valiases/$domain} } file_transport = address_file pipe_transport = address_pipe system_aliases: driver = redirect allow_fail allow_defer data = ${lookup{$local_part}lsearch{/etc/mail/aliases} } # user = exim file_transport = address_file pipe_transport = address_pipe userforward: driver = redirect check_local_user # local_part_suffix = +* : -* # local_part_suffix_optional file = $home/.forward # allow_filter no_verify no_expn check_ancestor file_transport = address_file pipe_transport = address_pipe reply_transport = address_reply localuser: driver = accept check_local_user # local_part_suffix = +* : -* # local_part_suffix_optional # Without dovecot #transport = local_delivery # With dovecot transport = dovecot_virtual_delivery cannot_route_message = Unknown user user_vacation: driver = accept check_local_user # do not reply to errors or lists condition = "${if or { {match {$h_precedence:} {(?i)junk|julk|list} } {eq {$sender_address} {} } } {no} {yes} }" no_expn require_files = ${lookup pgsql{select concat(user_home,'/.vacation.msg') from mail_users where user_uid = '${local_part}' or user_uid = '${local_part}@${domain}'}{$value}fail} # do not reply to errors and bounces or lists senders = " ! ^.*-request@.*:\ ! ^owner-.*@.*:\ ! ^postmaster@.*:\ ! ^listmaster@.*:\ ! ^mailer-daemon@.*\ ! ^root@.*" transport = vacation_reply unseen user = ${local_part} no_verify begin transports remote_smtp: driver = smtp delivery_date_add dkim_domain = $sender_address_domain dkim_selector = thisis dkim_private_key = /etc/ssl/exim/dkim.private.key dkim_canon = relaxed local_delivery: driver = appendfile directory = ${lookup pgsql{select concat(user_home,'/.maildir') from mail_users where user_uid = '${local_part}' or user_uid = '${local_part}@${domain}'}{$value}fail} maildir_format delivery_date_add envelope_to_add return_path_add dovecot_virtual_delivery: driver = pipe command = /usr/libexec/dovecot/dovecot-lda -d $local_part@$domain -f $sender_address # v1.1+: command = /usr/local/libexec/dovecot/dovecot-lda -d $local_part@$domain -f $sender_address -a $original_local_part@$original_domain message_prefix = message_suffix = delivery_date_add envelope_to_add return_path_add log_output temp_errors = 64 : 69 : 70: 71 : 72 : 73 : 74 : 75 : 78 address_pipe: driver = pipe return_output address_file: driver = appendfile delivery_date_add envelope_to_add return_path_add address_reply: driver = autoreply vacation_reply: driver = autoreply begin retry # Address or Domain Error Retries # ----------------- ----- ------- * * F,2h,15m; G,16h,1h,1.5; F,4d,6h begin rewrite # This rule allow to have more than one user with same email *@* "${lookup pgsql{select user_alias||'@'||user_qualify_domain from mail_alias where user_uid = '$1@$2'}{$value}fail}" Ffrw begin authenticators AUTH_CRAM_MD5=yes AUTH_SPA=yes CRAM: driver = cram_md5 server_set_id = $auth1 public_name = CRAM-MD5 server_secret = ${lookup pgsql{select user_pass from mail_users where user_uid = '$auth1' or user_uid = '$auth1$auth3'}{$value}fail} #server_secret = ${if eq{$auth1}{ph10}{secret1}fail} SPA: driver = spa server_set_id = $auth1 public_name = NTLM server_password = ${lookup pgsql{select user_pass from mail_users where user_uid = '$auth1' or user_uid = '$auth1$auth3'}{$value}fail}
Testing Exim
Once the configuration file is ready we can test the the file with the following command:
root #
exim -bV
If everything goes right we can now start exim
root #
/etc/init.d/exim start
Now we must be able to test how exim will route some addresses
root #
exim -bt someuser
root #
exim -bt bunnyfoofoo@gmail.com
root #
exim -bt someuser@example.com
Finally we can do the bunny test
root #
echo "test" | sendmail bunnyfoofoo@gmail.com
References
- ↑ Mail (MX) Server Survey, as stated in part of the Internet Research Reports by Canadian consulting firm E-Soft Inc., retrieved March 22, 2019