EximConfig
Contents
-
EximConfig
- installation
- virus scanning with clamav
- spam-tagging w/ spamassassin
- Multiple Domain Alias Files
- increasing logging
- no rewrite on /etc/email-addresses
- enabling TLS
- authentication
- disabling IDENT
- relaying
- Dovecot as LDA
- Adding Authentication-Results Headers
- check SPF
- hubbed smarthosts
- DKIM
- other nice stuff
installation
just
aptitude install exim4 exim4-daemon-heavy clamav clamav-daemon spamassassin spamc
the usage of maildir should be answered in
dpkg-reconfigure exim4-config
with yes. also select the multiple file configuration layout. anyhow, a more detailed listing which answers you should give.
- internet site
system mail name: <FQHN>
- listen on: empty
other destinations: <FQHN>
- relay for: empty
- minimal dns-queries: no
- Maildir
- split configuration: yes
virus scanning with clamav
enable clamd.
systemctl enable clamav-daemon
add following to your /etc/exim4/conf.d/main/00_local-config_macros.
# enable clamav for scanning mails av_scanner = clamd:/var/run/clamav/clamd.ctl # local ACLs for virus scanning (not only) CHECK_DATA_LOCAL_ACL_FILE=/etc/exim4/local_acl_data
add following to your /etc/exim4/local_acl_data.
# Reject messages containing malware. deny message = This message was detected as possible malware ($malware_name). malware = *
before restarting clamav, we need to be sure that all of the access rights are in place so that the scans actually happen. the best way to handle this is to add the clamav user to the Debian-exim group. Either manually edit /etc/group, or simple run:
adduser clamav Debian-exim
a restart of clamav is necessary for the changes to take effect:
service clamav-daemon restart
for testing just
aptitude install clamav-testfiles swaks
the testfiles can be found in /usr/share/clamav-testfiles. test it by sending a mail with attachment to local user. don't use mutt for testing.
swaks --from root@<FQHN> --to tux@<FQHN> --server localhost --attach /usr/share/clamav-testfiles/clam.7z [...] <** 550 This message contains a virus (Clamav.Test.File-6) and has been rejected
you will find following output in /var/log/exim4/mainlog
2018-02-09 15:06:54 1ek9KI-00014U-NX H=localhost (arverner.smtp.at) [::1] F=<root@arverner.smtp.at> rejected after DATA: This message contains a virus (Clamav.Test.File-6) and has been rejected
spam-tagging w/ spamassassin
we'll do it like on Adding SpamAssassin and ExiscanExamples - Exim Wiki.
Exiscan-ACL's "spam" condition passes the message through SpamAssassin, and triggers if these indicate that the message is junk. By default, it connects to a SpamAssassin daemon (spamd) running on localhost. The host address and port can be changed by adding a spamd_address setting in /etc/exim4/conf.d/main/00_local-config_macros.
# enable spamassassin spamd_address = 127.0.0.1 783
enable spamd.
systemctl enable spamassassin
In our implementation, we are going to reject messages classified as spam. However, we would like to keep a copy of such messages in a separate mail folder, at least for the time being. This is so that the user can periodically scan for False Positives.
Exim offers controls that can be applied to a message that is accepted, such as freeze. The Exiscan-ACL patch adds one more of these controls, namely fakereject. This causes the following SMTP response:
550-FAKEREJECT id=message-id 550-Your message has been rejected but is being kept for evaluation. 550 If it was a legit message, it may still be delivered to the target recipient(s).
the headers we'd like to have look like following (standard spamassassin headers):
X-Spam-Flag: YES X-Spam-Checker-Version: SpamAssassin 3.2.5 (2008-06-10) on bogdan.kmp.or.at X-Spam-Level: ****** X-Spam-Status: Yes, score=6.5 required=5.0 tests=BAYES_99,HTML_MESSAGE, MIME_HTML_ONLY autolearn=no version=3.2.5
We can incorporate this feature into our implementation, by inserting the following snippet in /etc/exim4/local_acl_data.
# Reject messages that are spam. # Invoke SpamAssassin to obtain $spam_score and $spam_report. # Depending on the classification, $acl_m9 is set to "ham" or "spam". # If the message is classified as spam, pretend to reject it. warn condition = ${if <{$message_size}{4096k}{1}{0}} set acl_m9 = ham spam = mail/defer_ok set acl_m9 = spam control = fakereject logwrite = Rejected spam: $spam_report add_header = X-ieBoh2ah-Spam-Flag: YES # Add an appropriate X-Spam-Status: header to the message. warn condition = ${if <{$message_size}{4096k}{1}{0}} add_header = X-ieBoh2ah-Spam-Level: $spam_bar\n\ X-ieBoh2ah-Spam-Status: ${if eq {$acl_m9}{spam}{Yes}{No}}, $spam_report # Add an appropriate X-Spam-Scanned: header if message is too big. warn condition = ${if >={$message_size}{4096k}{1}{0}} add_header = X-ieBoh2ah-Spam-Scanned: No, Message bigger than 4096 KiB
In this example, $acl_m9 is initially set to "ham". Then SpamAssassin is invoked as the user mail. If the message is classified as spam, then $acl_m9 is set to "spam", and the FAKEREJECT response above is issued. Finally, some X-Spam-*: headers are added to the message. The idea is that the Mail Delivery Agent or the recipient's Mail User Agent can use this header to filter junk mail into a separate folder.
to ensure our X-Spam headers are unique add following snippet to /etc/exim4/system.filter.
if first_delivery then if $h_X-ieBoh2ah-Spam-Status is not "" or $h_X-ieBoh2ah-Spam-Scanned is not "" then headers remove X-Spam-Flag:X-Spam-Level:X-Spam-Status:X-Spam-Scanned endif if $h_X-ieBoh2ah-Spam-Flag is not "" then headers add "X-Spam-Flag: $h_X-ieBoh2ah-Spam-Flag" endif if $h_X-ieBoh2ah-Spam-Level is not "" then headers add "X-Spam-Level: $h_X-ieBoh2ah-Spam-Level" endif if $h_X-ieBoh2ah-Spam-Status is not "" then headers add "X-Spam-Status: $h_X-ieBoh2ah-Spam-Status" endif if $h_X-ieBoh2ah-Spam-Scanned is not "" then headers add "X-Spam-Scanned: $h_X-ieBoh2ah-Spam-Scanned" endif headers remove X-ieBoh2ah-Spam-Flag:X-ieBoh2ah-Spam-Level:X-ieBoh2ah-Spam-Status:X-ieBoh2ah-Spam-Scanned endif
enable this system-filter by setting in /etc/exim/conf.d/main/00_local-config_macros
# The name of the file that contains the system filter must be specified # by setting system_filter. If you want the filter to run under a uid # and gid other than root, you must also set system_filter_user and # system_filter_group as appropriate. system_filter = /etc/exim4/system.filter
By default, SpamAssassin presents its report in a verbose, table-like format, mainly suitable for inclusion in or attachment to the message body. In our case, we want a terse report, suitable for the X-Spam-Status: header in the example above. To do this, we add the following snippet in its site specific configuration file /etc/spamassassin/local.cf.
# report template clear_report_template report score=_SCORE_ required=_REQD_ tests=_TESTS_ autolearn=_AUTOLEARN_ version=_VERSION_ hostname=<FQHN>
For these changes to take effect, you have to restart the SpamAssassin daemon.
service spamassassin restart
for testing spamassassin just have a look on SpamAssassin: The GTUBE.
echo "XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X" | swaks --from root@<FQHN> --to tux@<FQHN> --server localhost --body -
later, when we switch to dovecots LDA we also can sort into Spam folder based on these X-Spam headers.
Multiple Domain Alias Files
The steps below are used to enable support for having multiple virtual domains each with its own alias file.
Exim will need to have the alias files for each domain.
Create the /etc/exim4/virtual-domains.d directory.
For each virtual domain, create a file that contains the aliases to be used named as the domain.
For example, if example.com was one of my domains, I'd do the following:
Create the /etc/exim4/virtual-domains.d/example.com file.
If my system users were sys1, sys2, and sys3, and their email addresses were to be joe, john, jason, I'd put the following into the domain alias file:
joe: sys1@localhost john: sys2@localhost jason: sys3@localhost
If john was also to get all mail addressed to info@example.com, you would add this entry:
info: sys2@localhost
If you wanted all mail to user1@example.com to go to another email account outside of this domain, you would enter:
user1: a.user@some.domain
If you wanted all mail directed at any address other than what is defined in the alias file to go to joe, you'd enter:
*: sys1@localhost
In the above examples, the "@localhost" suffix to the user names forces the delivery to a system user. I found that if you do not include this in the alias files and your machine's host name is within one of the domains handled by exim, every system user would need an entry in the machine's domain in order to be delivered corectly. For instance, if your host name was mail.example1.com and example1.com was handled by this server this would be needed. This would allow delivery to all the system user names at example1.com. The reason is simple, and I will try to illustrate it for you here:
exim receives a message delivered to joe.blow@example3.com
- The alias file for this domain has joe.blow: jblow in it.
- This would translate to jblow@domain-of-the-system
- The process would be repeated using jblow@domain-of-the-system
- If there was no entry in the domain-of-the-system alias file for jblow, the message would be undeliverable (or non-routable)
You could even have special redirects like the following:
script: "| /path/to/some/script" prev: :fail: $local_part left! kill: :blackhole:
or you even can have regular expressions:
^klaus[-.](m|maria)\.pfei[f]{1,2}er$ klaus ^(kmp|klaus)[+-.][a-zA-Z0-9+-.]*$ klaus ^(kmp|klaus)$ klaus
Edit /etc/exim4/conf.d/main/00_local-config_macros by adding the following lines:
# List of domains considered local for exim. Domains not listed here # need to be deliverable remotely. MAIN_LOCAL_DOMAINS = @:localhost:dsearch;/etc/exim4/virtual-domains.d
Create /etc/exim4/conf.d/router/370_local-config_virtual_domains_aliases with the following content:
virtual_domain_aliases: debug_print = "R: virtual_domain_aliases for $domain" driver = redirect allow_defer allow_fail domains = dsearch;/etc/exim4/virtual-domains.d data = ${lookup{$local_part}nwildlsearch{/etc/exim4/virtual-domains.d/$domain}} retry_use_local_part pipe_transport = address_pipe file_transport = address_file
Now, regenerate your exim4 config:
update-exim4.conf
If there were no errors, restart exim4:
service exim4 restart
increasing logging
just add to your /etc/exim4/conf.d/main/00_local-macros:
# always log all MAIN_LOG_SELECTOR = +all -pid
no rewrite on /etc/email-addresses
just imagine, you've two distinguishable users with folowing adresses:
john@example1.com john@example2.com
first john has login john, second john has login millerj on your machine. so, your /etc/email-addresses looks like:
john: john@example1.com millerj: john@example2.com
due to a rewriteing in /etc/exim4/conf.d/rewrite/31_exim4-config_rewriting all emails from john@example2.com will appear as from john@example1.com.
just disabling this by adding the follwoing to your /etc/exim4/conf.d/main/00_local-macros:
# don't rewrite from on base of /etc/email-addresses NO_EAA_REWRITE_REWRITE=1
enabling TLS
do it like as described in 2.2.2. Enabling TLS support for Exim as server in /usr/share/doc/exim4-base/README.Debian.gz. also have a look at Exim Notes - Waikato Linux Users Group.
you need only two steps to go with TLS. first generate your self signed certificates:
/usr/share/doc/exim4-base/examples/exim-gencert
second add follwoing to your /etc/exim4/conf.d/main/00_local-macros:
# enable TLS MAIN_TLS_ENABLE=1
if you'd like to or have to enable smtps/ssmtp, just add the follwoing to your /etc/exim4/conf.d/main/00_local-config_macros:
# listen on 25 (smtp), 465 (smtps/ssmtp), 587 (submission) daemon_smtp_port = 25:465:587 tls_on_connect_ports = 465
enable submission ... /etc/exim4/conf.d/main/00_local-config_macros
# hook in my own RCPT ACLs CHECK_RCPT_LOCAL_ACL_FILE=/etc/exim4/local_acl_rcpt
/etc/exim4/local_acl_rcpt
# submission on port 587 only authenticated # rejected non authenticated on port 587 accept condition = ${if eq{$interface_port}{587}{1}{0}} endpass message = SMTP AUTH required for submission on port 587 authenticated = *
disable SSLv3 in /etc/exim4/conf.d/main/00_local-config_macros and add same snippet at end of /etc/exim4/conf.d/transport/30_exim4-config_remote_smtp and 30_exim4-config_remote_smtp_smarthost
# disable SSLv3 on incoming connections according to # https://lists.exim.org/lurker/message/20141017.093614.e5c38176.en.html #tls_require_ciphers = NORMAL:!VERS-SSL3.0 tls_require_ciphers = NORMAL:!ARCFOUR-128:!VERS-SSL3.0
letsencrypt
install deb pkg dehydrated and dehydrated-apache2.
run dehydrated as unprivileged user.
adduser --system --home /var/lib/dehydrated --no-create-home --group --disabled-login letsencrypt
/etc/dehydrated/conf.d/local-config.sh
# Which user should dehydrated run as? This will be implictly enforced when running as root DEHYDRATED_USER=letsencrypt # Which group should dehydrated run as? This will be implictly enforced when running as root DEHYDRATED_GROUP=letsencrypt # E-mail to use during the registration (default: <unset>) CONTACT_EMAIL=certmaster@<FQDN> # Program or function called in certain situations # # After generating the challenge-response, or after failed challenge (in this case altname is empty) # Given arguments: clean_challenge|deploy_challenge altname token-filename token-content # # After successfully signing certificate # Given arguments: deploy_cert domain path/to/privkey.pem path/to/cert.pem path/to/fullchain.pem # # BASEDIR and WELLKNOWN variables are exported and can be used in an external program # default: <unset> HOOK=/usr/local/bin/dehydrated-hook.sh
change umask that group letsencryp is able to read certs and keys. dehydrated is a way too paranoid.
/etc/dehydrated/conf.d/umask.sh
umask 027
chmod -R g=rwX /var/lib/dehydrated/ chgrp -R letsencrypt /var/lib/dehydrated/
cp /usr/share/doc/dehydrated/examples/hook.sh /usr/local/bin/dehydrated-hook.sh
/usr/local/bin/dehydrated-hook.sh
deploy_cert() { local DOMAIN="${1}" KEYFILE="${2}" CERTFILE="${3}" FULLCHAINFILE="${4}" CHAINFILE="${5}" TIMESTAMP="${6}" chmod g+r $KEYFILE $CERTFILE $FULLCHAINFILE $CHAINFILE if [[ "$DOMAIN" =~ ^mail\..* ]]; then sudo systemctl restart exim4.service sudo systemctl restart dovecot.service else sudo systemctl restart apache2.service fi
/etc/sudoers.d/letsencrypt
letsencrypt ALL = NOPASSWD: /bin/systemctl restart apache2.service, /bin/systemctl restart exim4.service, /bin/systemctl restart dovecot.service
/etc/dehydrated/domains.txt
<FQDN>
dehydrated --register --accept-terms
dehydrated -c
adduser Debian-exim letsencrypt
its only matter of defining certs ... in /etc/exim4/conf.d/main/00_local-config_macros
# Full paths to Certificate and Private Key. The Private Key file # must be kept 'secret' and should be owned by root.Debian-exim mode # 640 (-rw-r-----). exim-gencert takes care of these prerequisites. # Normally, exim4 looks for certificate and key in different files: # MAIN_TLS_CERTIFICATE - path to certificate file, # CONFDIR/exim.crt if unset # MAIN_TLS_PRIVATEKEY - path to private key file # CONFDIR/exim.key if unset # You can also configure exim to look for certificate and key in the # same file, set MAIN_TLS_CERTKEY to that file to enable. This takes # precedence over all other settings regarding certificate and key file. MAIN_TLS_CERTIFICATE = /var/lib/dehydrated/certs/<FQDN>/fullchain.pem MAIN_TLS_PRIVATEKEY = /var/lib/dehydrated/certs/<FQDN>/privkey.pem
authentication
against system passwords
If you want to authenticate against system passwords (e.g. /etc/shadow) the easiest way is to use saslauthd in the Debian package sasl2-bin. You have to add the exim-user (currently Debian-exim) to the sasl group, to give exim permission to use the saslauthd service.
aptitude install sasl2-bin adduser Debian-exim sasl
create /etc/exim4/conf.d/auth/20_local-config_sasl_auth
# Authenticate against local passwords using sasl2-bin # Requires exim_uid to be a member of sasl group, see README.Debian.gz plain_saslauthd_server: driver = plaintext public_name = PLAIN server_condition = ${if saslauthd{{$auth2}{$auth3}}{1}{0}} server_set_id = $auth2 server_prompts = : .ifndef AUTH_SERVER_ALLOW_NOTLS_PASSWORDS server_advertise_condition = ${if eq{$tls_in_cipher}{}{}{*}} .endif login_saslauthd_server: driver = plaintext public_name = LOGIN server_condition = ${if saslauthd{{$auth1}{$auth2}}{1}{0}} server_set_id = $auth1 server_prompts = "Username:: : Password::" .ifndef AUTH_SERVER_ALLOW_NOTLS_PASSWORDS server_advertise_condition = ${if eq{$tls_in_cipher}{}{}{*}} .endif
edit /etc/default/saslauthd and set START=yes.
then restart saslauthd.
service saslauthd restart
disabling IDENT
just add in your /etc/exim4/conf.d/main/00_local-config_macros:
# disable IDENT rfc1413_hosts = * rfc1413_query_timeout = 0s
relaying
/etc/exim4/conf.d/main/00_local-config_macros
# List of sender networks (IP addresses) to _unconditionally_ relay # _for_. If you intend to be SMTP AUTH server, you do not need to enter # anything here. MAIN_RELAY_NETS = 192.168.1.0/24 : 127.0.0.1 : ::::1 # List of recipient domains to relay _to_. Use this list if you're - # for example - fallback MX or mail gateway for domains. MAIN_RELAY_TO_DOMAINS = some.other.host.com
Dovecot as LDA
add some more headers in pipe delivery. /etc/exim4/conf.d/transport/30_exim4-config_address_pipe
delivery_date_add envelope_to_add return_path_add
we do it just via .forward and not that elegant as in https://wiki2.dovecot.org/LDA/Exim.
| "/usr/lib/dovecot/dovecot-lda"
install dovecot
aptitude install dovecot-imapd dovecot-managesieved
/etc/dovecot/conf.d/10-auth.conf
# Disable LOGIN command and all other plaintext authentications unless # SSL/TLS is used (LOGINDISABLED capability). Note that if the remote IP # matches the local IP (ie. you're connecting from the same computer), the # connection is considered secure and plaintext authentication is allowed. # See also ssl=required setting. disable_plaintext_auth = yes
/etc/dovecot/conf.d/10-logging.conf
# Log file to use for error messages. "syslog" logs to syslog, # /dev/stderr logs to stderr. log_path = /var/log/dovecot/error.log # Log file to use for informational messages. Defaults to log_path. info_log_path = /var/log/dovecot/info.log # Log file to use for debug messages. Defaults to info_log_path. debug_log_path = /var/log/dovecot/debug.log # Log unsuccessful authentication attempts and the reasons why they failed. auth_verbose = yes
/etc/dovecot/conf.d/10-mail.conf
#mail_location = mbox:~/mail:INBOX=/var/mail/%u mail_location = maildir:~/Maildir
execute
/usr/share/dovecot/mkcert.sh
to create temporary SSL certs.
/etc/dovecot/conf.d/10-ssl.conf
# SSL/TLS support: yes, no, required. <doc/wiki/SSL.txt> #ssl = no ssl = yes # PEM encoded X.509 SSL/TLS certificate and private key. They're opened before # dropping root privileges, so keep the key file unreadable by anyone but # root. Included doc/mkcert.sh can be used to easily generate self-signed # certificate, just make sure to update the domains in dovecot-openssl.cnf ssl_cert = </etc/dovecot/dovecot.pem ssl_key = </etc/dovecot/private/dovecot.pem # SSL protocols to use #ssl_protocols = !SSLv3 ssl_protocols = !SSLv3
or with letsencrypt /etc/dovecot/conf.d/10-ssl.conf
# PEM encoded X.509 SSL/TLS certificate and private key. They're opened before # dropping root privileges, so keep the key file unreadable by anyone but # root. Included doc/mkcert.sh can be used to easily generate self-signed # certificate, just make sure to update the domains in dovecot-openssl.cnf ssl_cert = </var/lib/dehydrated/certs/<FQDN>/fullchain.pem ssl_key = </var/lib/dehydrated/certs/<FQDN>/privkey.pem
dont forget following command that dovecot can read its certs.
adduser dovecot letsencrypt
/etc/dovecot/conf.d/15-lda.conf
# Address to use when sending rejection mails. # Default is postmaster@<your domain>. %d expands to recipient domain. postmaster_address = postmaster@<FQDN> # Hostname to use in various parts of sent mails (e.g. in Message-Id) and # in LMTP replies. Default is the system's real hostname@domain. hostname = <FQHN> # Header where the original recipient address (SMTP's RCPT TO: address) is taken # from if not available elsewhere. With dovecot-lda -a parameter overrides this. # A commonly used header for this is X-Original-To. lda_original_recipient_header = Envelope-to # Should saving a mail to a nonexistent mailbox automatically create it? lda_mailbox_autocreate = yes # Should automatically created mailboxes be also automatically subscribed? lda_mailbox_autosubscribe = yes protocol lda { # Space separated list of plugins to load (default is global mail_plugins). mail_plugins = $mail_plugins sieve # seperate logfile for lda log_path = /var/log/dovecot/lda-error.log info_log_path = /var/log/dovecot/lda-info.log debug_log_path = /var/log/dovecot/lda-debug.log }
in /etc/dovecot/conf.d/20-managesieve.conf enable protocols, managesieve-login and managesieve.
/etc/dovecot/conf.d/90-sieve.conf
# Multiple script locations can be specified by appending an increasing number # to the setting name. The Sieve scripts found from these locations are added # to the script execution sequence in the specified order. Reading the # numbered sieve_before settings stops at the first missing setting, so no # numbers may be skipped. sieve_before = /etc/dovecot/sieve/before/ # Specifies what envelope sender address is used for redirected messages. # The following values are supported for this setting: sieve_redirect_envelope_from = orig_recipient
/etc/dovecot/sieve/before/10-spam.sieve
require ["regex","fileinto"]; # rule:[Spam] if allof (header :regex "X-Spam-Status" "^Yes") { fileinto "Spam"; }
/etc/dovecot/sieve/before/20-Mailer-Daemon.sieve
require ["fileinto"]; # rule:[Mailer-Daemon] if allof (address "From" "Mailer-Daemon@<FQHN>") { fileinto "INBOX"; }
Adding Authentication-Results Headers
http://www.debian-administration.org/users/lee/weblog/46
/etc/exim4/conf.d/main/00_local-config_macros
# Adding Authentication-Results headers with Exim # http://www.debian-administration.org/users/lee/weblog/46 AUTHSERV_ID = primary_hostname # Defines the access control list that is run when an # DKIM signature is verified .ifndef MAIN_ACL_CHECK_DKIM MAIN_ACL_CHECK_DKIM = acl_check_dkim .endif acl_smtp_dkim = MAIN_ACL_CHECK_DKIM
/etc/exim4/local_acl_rcpt
# Adding Authentication-Results headers # http://www.debian-administration.org/users/lee/weblog/46 # iprev policy which merely checks if the reverse DNS of the sending server has been properly configured warn #hosts = !condition = ${lookup dnsdb{ptr=$sender_host_address}{true}{}} !condition = ${lookup dnsdb{ptr=$sender_host_address}{true}{}} set acl_c_iprev = permerror set acl_m_authresults = $acl_m_authresults;\n iprev=permerror (no ptr) policy.iprev=$sender_host_address warn verify = reverse_host_lookup set acl_m_authresults = $acl_m_authresults;\n iprev=pass policy.iprev=$sender_host_address ($sender_host_name) warn !condition = ${if eq{$acl_c_iprev}{permerror}{true}} condition = ${if and{{def:sender_host_address}{!def:sender_host_name}} {yes}{no}} set acl_m_authresults = $acl_m_authresults;\n iprev=${if eq{$host_lookup_failed}{1}{fail}{temperror}} policy.iprev=$sender_host_address # spf warn condition = ${run{/usr/bin/spfquery.mail-spf-perl --ip \ ${quote:$sender_host_address} --identity \ ${if def:sender_address_domain \ {--scope mfrom --identity ${quote:$sender_address}}\ {--scope helo --identity ${quote:$sender_helo_name}} }}\ {yes}{yes}} set acl_c_spf = ${if eq {$runrc}{0}{pass}\ {${if eq {$runrc}{1}{fail}\ {${if eq {$runrc}{2}{softfail}\ {${if eq {$runrc}{3}{neutral}\ {${if eq {$runrc}{4}{permerror}\ {${if eq {$runrc}{5}{temperror}\ {${if eq {$runrc}{6}{none}{error}} }} }} }} }} }} }} add_header = :at_start:Received-SPF: $acl_c_spf \ client-ip=$sender_host_address; \ ${if def:sender_address_domain \ {envelope-from=${sender_address}; }{}}\ helo=$sender_helo_name # logwrite = SPF: client-ip=$sender_host_address \ # ${if def:sender_address_domain \ # {envelope-from=${sender_address} }{}}\ # helo=$sender_helo_name [$acl_c_spf] set acl_m_authresults = $acl_m_authresults;\n spf=$acl_c_spf \ ${if def:sender_address_domain \ {smtp.mailfrom=${sender_address} }{}}\ smtp.helo=$sender_helo_name # warn # condition = ${if def:authenticated_id} # set acl_m_authresults = $acl_m_authresults;\n auth=pass smtp.auth=$authenticated_id
/etc/exim4/local_acl_data
# Adding Authentication-Results headers # http://www.debian-administration.org/users/lee/weblog/46 # adding SPF log entry only if its not spam and we have authresults warn #condition = ${if def:acl_m_authresults {true}} condition = ${if and { {!eq {$acl_m9}{spam}} {def:acl_m_authresults}} } logwrite = SPF: client-ip=$sender_host_address \ ${if def:sender_address_domain \ {envelope-from=${sender_address} }{}}\ # ${if def:received_for {received-for=${received_for} }{}}\ helo=$sender_helo_name [$acl_c_spf] # auth for mails via submission warn condition = ${if def:authenticated_id} set acl_m_authresults = $acl_m_authresults;\n auth=pass smtp.auth=$authenticated_id # adding the header warn !condition = ${if def:acl_m_authresults {true}} set acl_m_authresults = ; none warn add_header = :at_start:Authentication-Results: ${AUTHSERV_ID}${acl_m_authresults}
/etc/exim4/conf.d/acl/35_local-config_check_dkim
acl_check_dkim: # Adding Authentication-Results headers # http://www.debian-administration.org/users/lee/weblog/46 warn dkim_status = fail set acl_m_authresults = $acl_m_authresults;\n dkim=fail ($dkim_verify_reason) \ header.${if eq{$dkim_identity}{}{d}{i}}=$dkim_cur_signer warn dkim_status = invalid set acl_m_authresults = $acl_m_authresults;\n dkim=neutral ($dkim_verify_reason) \ header.${if eq{$dkim_identity}{}{d}{i}}=$dkim_cur_signer warn dkim_status = pass set acl_m_authresults = $acl_m_authresults;\n dkim=pass ${if eq{$dkim_key_testing}{1}{(test mode) }}\ header.${if eq{$dkim_identity}{}{d}{i}}=$dkim_cur_signer accept
check SPF
aptitude install spf-tools-perl
/etc/exim4/conf.d/main/00_local-config_macros
# Use spfquery to perform a pair of SPF checks (for details, see # http://www.openspf.org/) #CHECK_RCPT_SPF = 1 CHECK_RCPT_SPF_DOMAIN = 1
/etc/exim4/local_acl_rcpt
# Use spfquery to perform a pair of SPF checks (for details, see # http://www.openspf.org/) # # This is quite costly in terms of DNS lookups (~6 lookups per mail). Do not # enable if that's an issue. Also note that if you enable this, you must # install "spf-tools-perl" which provides the spfquery command. # Missing spf-tools-perl will trigger the "Unexpected error in # SPF check" warning. .ifdef CHECK_RCPT_SPF_DOMAIN deny message = [SPF] $sender_host_address is not allowed to send mail from \ ${if def:sender_address_domain {$sender_address_domain}{$sender_helo_name}}. \ Please see \ http://www.openspf.org/Why?scope=${if def:sender_address_domain \ {mfrom}{helo}};identity=${if def:sender_address_domain \ {$sender_address}{$sender_helo_name}};ip=$sender_host_address log_message = SPF check failed. !acl = acl_local_deny_exceptions condition = ${run{/usr/bin/spfquery.mail-spf-perl --ip \ ${quote:$sender_host_address} --identity \ ${if def:sender_address_domain \ {--scope mfrom --identity ${quote:$sender_address}}\ {--scope helo --identity ${quote:$sender_helo_name}} }}\ {no}{${if eq {$runrc}{1}{yes}{no}} }} domains = partial-lsearch;CONFDIR/check_rcpt_spf defer message = Temporary DNS error while checking SPF record. Try again later. !acl = acl_local_deny_exceptions condition = ${if eq {$runrc}{5}{yes}{no}} domains = partial-lsearch;CONFDIR/check_rcpt_spf # warn # condition = ${if <={$runrc}{6}{yes}{no}} # add_header = Received-SPF: ${if eq {$runrc}{0}{pass}\ # {${if eq {$runrc}{2}{softfail}\ # {${if eq {$runrc}{3}{neutral}\ # {${if eq {$runrc}{4}{permerror}\ # {${if eq {$runrc}{6}{none}{error}} }} }} }} }\ # } client-ip=$sender_host_address; \ # ${if def:sender_address_domain \ # {envelope-from=${sender_address}; }{}}\ # helo=$sender_helo_name warn log_message = Unexpected error in SPF check. condition = ${if >{$runrc}{6}{yes}{no}} domains = partial-lsearch;CONFDIR/check_rcpt_spf .endif
add all the receiving domains you'd like to check and reject based on SPF into /etc/exim4/check_rcpt_spf
hubbed smarthosts
/etc/exim4/conf.d/router/160_local-config_hubbed_smarthosts
# router/160_local-config_hubbed_smarthosts ################################# # route specific domains manually via smarthost hubbed_smarthosts: debug_print = "R: hubbed_smarthosts for $domain" driver = manualroute domains = "${if exists{CONFDIR/hubbed_smarthosts}\ {partial-lsearch;CONFDIR/hubbed_smarthosts}\ fail}" #senders = *@somedomain.org : *@otherlocaldomain.org same_domain_copy_routing = yes route_data = ${lookup{$domain}partial-lsearch{CONFDIR/hubbed_smarthosts}} transport = remote_smtp_smarthost
/etc/exim4/hubbed_smarthosts
# route specific domains manually to smarthost # domain smarthost #gmail.com: mx.fahrzurhoelle.org::587
don't forget the entry in /etc/exim4/passwd.client
DKIM
/etc/exim4/conf.d/main/00_local-config_macros
# Enable DKIM DKIM_DOMAIN = ${sender_address_domain} #DKIM_DOMAIN = ${lc:${domain:$h_from:}} DKIM_SELECTOR = ${lookup{DKIM_DOMAIN}lsearch*{CONFDIR/dkim.d/dkim_selectors}} DKIM_PRIVATE_KEY = ${if exists{CONFDIR/dkim.d/DKIM_DOMAIN.DKIM_SELECTOR.key}{CONFDIR/dkim.d/DKIM_DOMAIN.DKIM_SELECTOR.key}{0}} DKIM_CANON = relaxed # we just use the same as Heiko Schlittermann schlittermann.de DKIM_SIGN_HEADERS = In-Reply-To:Content-Type:MIME-Version:References:Message-ID:Subject:To:From:Date:Cc:Content-Description:Content-ID:Content-Transfer-Encoding:Resent-To
you also will have DKIM towards smarthost. /etc/exim4/conf.d/transport/30_exim4-config_remote_smtp_smarthost
.ifdef DKIM_DOMAIN dkim_domain = DKIM_DOMAIN .endif .ifdef DKIM_SELECTOR dkim_selector = DKIM_SELECTOR .endif .ifdef DKIM_PRIVATE_KEY dkim_private_key = DKIM_PRIVATE_KEY .endif .ifdef DKIM_CANON dkim_canon = DKIM_CANON .endif .ifdef DKIM_STRICT dkim_strict = DKIM_STRICT .endif .ifdef DKIM_SIGN_HEADERS dkim_sign_headers = DKIM_SIGN_HEADERS .endif
mkdir /etc/exim4/dkim.d
create dkim keys.
DOMAIN=$1 SELECTOR=dflt KEYSIZE=2048 DKIMDIR=dkim.d cd /etc/exim4 mkdir $DKIMDIR openssl genrsa -out $DKIMDIR/$DOMAIN.$SELECTOR.key $KEYSIZE openssl rsa -in $DKIMDIR/$DOMAIN.$SELECTOR.key -out $DKIMDIR/$DOMAIN.$SELECTOR.pub -pubout -outform PEM echo -e "$DOMAIN:\t$SELECTOR" >> $DKIMDIR/dkim_selectors chown -R root:Debian-exim $DKIMDIR chmod 640 $DKIMDIR/*.key chmod 644 $DKIMDIR/*.pub $DKIMDIR/dkim_selectors chmod 755 $DKIMDIR
other nice stuff
/etc/exim4/conf.d/main/00_local-config_macros
# hard code hostname MAIN_HARDCODE_PRIMARY_HOSTNAME = <FQHN> # This option limits the number of delivery processes that Exim starts # automatically when receiving messages via SMTP, whether via the daemon # or by the use of -bs or -bS. If the value of the option is greater # than zero, and the number of messages received in a single SMTP # session exceeds this number, subsequent messages are placed on the # queue, but no delivery processes are started. This helps to limit the # number of Exim processes when a server restarts after downtime and # there is a lot of mail waiting for it on other systems. On large # systems, the default should probably be increased, and on dial-in # client systems it should probably be set to zero (that is, disabled). # # this setting is necessary for mailman and reflects also in mailmans # config. smtp_accept_queue_per_connection = 30 # Google is way behind the times on IPv6 and tends to reject mail from # new v6 addrs: #dns_ipv4_lookup = *.gmail.com : *.google.com # If TLS cannot be # used for some reason, you can set AUTH_SERVER_ALLOW_NOTLS_PASSWORDS to # advertise unencrypted clear text password based authenticators on all # connections. As this is severely reducing security, using TLS is # preferred over allowing clear text password based authenticators on # unencrypted connections. #AUTH_SERVER_ALLOW_NOTLS_PASSWORDS = 1 # enable sender verification http://www.exim.org/exim-html-current/doc/html/spec_html/ch-access_control_lists.html#SECTaddressverification #CHECK_RCPT_VERIFY_SENDER = 1 # Critical Exim Security Vulnerability: disable chunking CVE-2017-16944 chunking_advertise_hosts = # Warn if the sender host does not have valid reverse DNS. CHECK_RCPT_REVERSE_DNS = 1