Nach der Einrichtung von OpenLDAP im ersten Teil, der Anpassung und Konfiguration von dovecot im zweiten Teil befasst sich der dritte Teil mit der Konfiguration von Exim. Obwohl fast alles im Blog detailliert beschrieben ist, empfehle ich, die Konfigurationsdateien für das Mailsystem herunterzuladen.
Installation von Exim
Da wir bei exim die LDAP-Unterstützung benötigen, müssen wir die entsprechende Exim-Version mit einem
sudo apt-get install exim4-daemon-heavy
installieren. Dabei wird notwendigerweise auch postfix entfernt, das von Ubuntu standardmäßig als Message Transfer Agent (MTA) eingesetzt wird.
Konfiguration von Exim
Damit exim auf die SSL-Zertifikate zur Verschlüsselung der SMTP-Verbindungen zugreifen kann, müssen wir den exim-Benutzer zur Gruppe ssl-cert hinzufügen
sudo adduser Debian-exim ssl-certZur Konfiguration von exim kann man unter Ubuntu/Debian ein spezielles Konfigurationspaket namens exim4-config verwenden. Dieses erzeugt aus einzelnen Dateien im Verzeichnis /etc/exim4/conf.d eine finale Konfigurationsdatei (nähere Informationen zu exim4-config auf der Debian-Seite). Ich empfehle, dieses Konfigurationspaket zu verwenden und die Grundkonfiguration mit
sudo dpkg-reconfigure exim4-configzu starten. Im anschließenden Konfigurationsdialog wählen wir Nur lokale Mailzustellung; keine Netzwerkverbindung. Dann geben wir den korrekten DNS-Namen des Servers an, den wir auch schon bei der Erzeugung der Schlüsselzertifikate verwendet haben (hier im Beispiel myserver). Der nächste Punkt ist eigentlich selbsterklärend, wenn der SMTP-Server über alle Interfaces erreichbar sein soll, das Feld leer lassen, ansonsten die gewünschte IP-Addresse eintragen. Der nächste Schritt fordert uns auf, mögliche weitere Domains für den lokalen Mailempfang anzugeben (im Zweifelsfall leer lassen). Der Punkt, ob DNS-Anfragen minimiert werden sollen, beantworten wir mit Nein. Als Speicherformat für lokale Mails wählen wir mbox (wird aber später modifiziert). Die Einstellungen sollen in kleine Dateien aufgeteilt werden. Nun machen wir uns an die Anpassung. Wir editieren die Datei /etc/exim4/update-exim4.conf.conf und ändern die letzte Zeile mit dem Eintrag
dc_localdelivery='mail_spool'
in
dc_localdelivery='dovecot_delivery'
ab. Im nächsten Schritt löschen wir den Inhalt des Verzeichnisses /etc/exim4/conf.d und kopieren die Dateien aus dem Konfigurationspaket dorthin mit
sudo rm -rf /etc/exim4/conf.d sudo cp -R /path/to/configfiles/exim/conf.d /etc/exim4
In der Datei /etc/exim4/conf.d/main/00_local_macros passen wir folgende Zeilen an:
ldap_default_servers = myserver MAIN_TLS_CERTIFICATE = /etc/ssl/certs/myserver.crt MAIN_TLS_PRIVATEKEY = /etc/ssl/private/myserver.key
Wir ersetzen hier myserver jeweils durch den DNS-Namen des Servers. Nun erzeugen wir die finale Konfigurationsdatei für exim und starten exim anschließend neu mit dem Befehl
sudo update-exim4.conf && sudo /etc/init.d/exim4 restart
Das Programm erzeugt so eine finale Konfigurationsdatei, die unter /var/lib/exim4/config.autogenerated abgelegt wird. Für diejenigen, die das Debiankonfigurationssystem nicht nutzen können/wollen, ist hier deren Inhalt aufgeführt:
######### # WARNING WARNING WARNING # WARNING WARNING WARNING # WARNING WARNING WARNING # WARNING WARNING WARNING # WARNING WARNING WARNING # This file is generated dynamically from the files in # the conf.d/ directory, or from exim4.conf.template respectively. # Additional information is read from update-exim4.conf.conf # This version of the file was created from the directory /etc/exim4 # Any changes you make here will be lost. # See /usr/share/doc/exim4-base/README.Debian.gz and update-exim4.conf(8) # for instructions of customization. # WARNING WARNING WARNING # WARNING WARNING WARNING # WARNING WARNING WARNING # WARNING WARNING WARNING # WARNING WARNING WARNING ######### FIRST_USER_ACCOUNT_UID = 1000 acl_not_smtp_start = acl_check_not_smtp ldap_default_servers = myserver LDAP_BASE = ou=users,o=effinger SEC_MAIL_USER=secmail IS_SENDER_SECMAIL = eq{$originator_uid}{${extract{2}{:}{${lookup{SEC_MAIL_USER}lsearch{/etc/passwd}{$value}}}}} received_header_text = ${if !IS_SENDER_SECMAIL {Received: ${if def:sender_rcvhost {from $sender_rcvhost\n\t}{${if def:sender_ident {from ${quote_local_part:$sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)\n\t}}}}by $primary_hostname ${if def:received_protocol {with $received_protocol}} ${if def:tls_cipher {($tls_cipher)\n\t}}(Exim $version_number)\n\t${if def:sender_address {(envelope-from <$sender_address>)\n\t}}id $message_exim_id${if def:received_for {\n\tfor $received_for}}}{}} LOCAL_DELIVERY_SECMAIL = dovecot_delivery_secmail MAIN_TLS_ENABLE = yes MAIN_TLS_CERTIFICATE = /etc/ssl/certs/myserver.crt MAIN_TLS_PRIVATEKEY = /etc/ssl/private/myserver.key MAIN_TLS_VERIFY_CERTIFICATES = /etc/ssl/certs/ca.crt SENDER_EXTRACT_UID = ${sg{${lc:$sender_address}} \ {\N^([a-zA-Z0-9_.-]+)@([a-zA-Z0-9_.-]+@[a-zA-Z0-9_.-]+)$\N}{\$1}} SENDER_EXTRACT_REAL_MAIL = ${sg{${lc:$sender_address}} \ {\N^([a-zA-Z0-9_.-]+)@([a-zA-Z0-9_.-]+@[a-zA-Z0-9_.-]+)$\N}{\$2}} IS_SENDER_REMOTE = ${lookup ldap \ {ldap:///uid=${quote_ldap_dn:SENDER_EXTRACT_UID},LDAP_BASE??sub?(&(dcSubMailAddress=${quote_ldap:SENDER_EXTRACT_REAL_MAIL})(dcAccountStatus=active))} \ {yes}fail} IS_LOCAL_PART_VALID = ${lookup ldap \ {ldap:///uid=${quote_ldap_dn:${lc:$local_part}},LDAP_BASE??base?(objectClass=dcMailUser)} \ {yes}{no}} GET_UID_FOR_RCPT = ${tr \ {${lookup ldapm \ {ldap:///LDAP_BASE??sub?${if match_domain{$domain}{+local_domains}{(mail=${quote_ldap:$local_part})}{(&(dcSubMailAddress=${quote_ldap:$local_part@$domain})(dcAccountStatus=active))}}} \ {${sg{${lc:$value}}{\N(?m)^.*uid="(.*?)".*$\N}{\$1}}} \ }} \ {\n}{,} \ } GET_ALIAS_FOR_RCPT = ${tr \ {${lookup ldapm \ {ldap:///LDAP_BASE?mail,dcSubMailAddress?sub?(|(dcMailAlias=${quote_ldap:$local_part${if match_domain{$domain}{+local_domains}{}{@$domain}}})(&(dcMailAlternateAddress=${quote_ldap:$local_part@$domain})(dcAccountStatus=active)))} \ {${sg{${lc:$value}}{\N(?m)^.*(mail|dcsubmailaddress)="(.*?)".*$\N}{\$2}}} \ }} \ {\n}{,} \ } GET_ALIAS_FOR_AUTH = ${tr \ {${lookup ldapm \ {ldap:///LDAP_BASE?dcMailAlias,dcMailAlternateAddress?sub?(|(mail=${quote_ldap:AUTH_SERVER_MAIL})(&(dcSubMailAddress=${quote_ldap:AUTH_SERVER_MAIL})(dcAccountStatus=active)))} \ {${sg{${lc:$value}}{\N(?m)^.*(dcmailalias|dcmailalternateaddress)="(.*?)".*$\N}{\$2}}} \ }} \ {\n}{,} \ } GET_COMPLETE_MAIL_FOR_LOCAL_PART_UID = ${lookup ldap \ {ldap:///uid=${quote_ldap_dn:${lc:$local_part}},LDAP_BASE?mail?base?(objectClass=dcMailUser)} \ {${local_part}@${value}}} GET_LOCAL_MAIL = ${if match_domain{$parent_domain}{+local_domains} \ {GET_COMPLETE_MAIL_FOR_LOCAL_PART_UID} \ {${lookup ldap \ {ldap:///uid=${quote_ldap_dn:${lc:$local_part}},LDAP_BASE?dcSubMailAddress?sub?(&(dcSubMailAddress=${quote_ldap:$parent_local_part@$parent_domain})(dcAccountStatus=active))} \ {$local_part@$parent_local_part@$parent_domain} \ {GET_COMPLETE_MAIL_FOR_LOCAL_PART_UID} \ }} \ } IS_AUTH_REMOTE = ${lookup ldap { \ user="uid=${quote_ldap_dn:AUTH_SERVER_UID},LDAP_BASE" \ pass=${quote:AUTH_SERVER_PASSWORD} \ ldap:///LDAP_BASE??sub?(&(dcSubMailAddress=${quote_ldap:AUTH_SERVER_MAIL})(dcAccountStatus=active)(dcSMTPServer=*)(dcSMTPLogin=*)(dcSMTPPassword=*))} \ {yes}fail} AUTH_REMOTE_SERVER = ${lookup ldap { \ user="uid=${quote_ldap_dn:AUTH_SERVER_UID},LDAP_BASE" \ pass=${quote:AUTH_SERVER_PASSWORD} \ ldap:///LDAP_BASE?dcSMTPServer?sub?(&(dcSubMailAddress=${quote_ldap:AUTH_SERVER_MAIL})(dcAccountStatus=active)(dcSMTPServer=*)(dcSMTPLogin=*)(dcSMTPPassword=*))} \ {$value}{}} AUTH_REMOTE_LOGIN = ${lookup ldap {\ user="uid=${quote_ldap_dn:AUTH_SERVER_UID},LDAP_BASE" \ pass=${quote:AUTH_SERVER_PASSWORD} \ ldap:///LDAP_BASE?dcSMTPLogin?sub?(&(dcSubMailAddress=${quote_ldap:AUTH_SERVER_MAIL})(dcAccountStatus=active)(dcSMTPServer=*)(dcSMTPLogin=*)(dcSMTPPassword=*))} \ {$value}{}} AUTH_REMOTE_PASSWORD = ${lookup ldap {\ user="uid=${quote_ldap_dn:AUTH_SERVER_UID},LDAP_BASE" \ pass=${quote:AUTH_SERVER_PASSWORD} \ ldap:///LDAP_BASE?dcSMTPPassword?sub?(&(dcSubMailAddress=${quote_ldap:AUTH_SERVER_MAIL})(dcAccountStatus=active)(dcSMTPServer=*)(dcSMTPLogin=*)(dcSMTPPassword=*))} \ {$value}{}} AUTH_SERVER_PLAIN_AUTH = ${if ldapauth \ {user="uid=${quote_ldap_dn:${sg{${lc:$auth2}} \ {\N^([a-zA-Z0-9_.-]+)@([a-zA-Z0-9_@.-]+)$\N}{\$1}}},LDAP_BASE" \ pass=${quote:$auth3} \ ldap:///}{yes}{no}} AUTH_SERVER_LOGIN_AUTH = ${if ldapauth \ {user="uid=${quote_ldap_dn:${sg{${lc:$auth1}} \ {\N^([a-zA-Z0-9_.-]+)@([a-zA-Z0-9_@.-]+)$\N}{\$1}}},LDAP_BASE" \ pass=${quote:$auth2} \ ldap:///}{yes}{no}} AUTH_SERVER_MAIL = ${sg{${lc:${extract{1}{\/}{$authenticated_id}}}}{\N^([a-zA-Z0-9_.-]+)@([a-zA-Z0-9_@.-]+)$\N}{\$2}} AUTH_SERVER_UID = ${sg{${lc:${extract{1}{\/}{$authenticated_id}}}}{\N^([a-zA-Z0-9_.-]+)@([a-zA-Z0-9_@.-]+)$\N}{\$1}} AUTH_SERVER_PASSWORD = ${extract{2}{\/}{$authenticated_id}} IS_SENDER_BAD = ${if match {AUTH_SERVER_MAIL}{\N^[a-zA-Z0-9_.-]+$\N} \ {${if match {${lc:AUTH_SERVER_MAIL}} {${lc:$sender_address_local_part}} {no} \ {${if match {${lc:$sender_address_local_part}} \ {${lc:${tr{GET_ALIAS_FOR_AUTH}{,}{::}}}} \ {no}{yes}}}\ }} \ {${if match_address {${lc:AUTH_SERVER_MAIL}} {${lc:$sender_address}} {no} \ {${if match_address {${lc:$sender_address}} \ {${lc:${tr{GET_ALIAS_FOR_AUTH}{,}{::}}}} \ {no}\ {${if and{ \ {match_domain{$sender_address_domain}{+local_domains}} \ {match_local_part{$sender_address_local_part}{SEC_MAIL_USER}} \ {match_ip{$sender_host_address}{@[]}} \ }\ {no}\ {yes}\ }}\ }}\ }}} exim_path = /usr/sbin/exim4 .ifndef CONFDIR CONFDIR = /etc/exim4 .endif UPEX4CmacrosUPEX4C = 1 ############################################## # the following macro definitions were created # dynamically by /usr/sbin/update-exim4.conf .ifndef MAIN_PACKAGE_VERSION MAIN_PACKAGE_VERSION=4.69-5ubuntu2 .endif .ifndef MAIN_LOCAL_DOMAINS MAIN_LOCAL_DOMAINS=@:localhost .endif .ifndef MAIN_RELAY_TO_DOMAINS MAIN_RELAY_TO_DOMAINS=empty .endif .ifndef ETC_MAILNAME ETC_MAILNAME=myserver .endif .ifndef LOCAL_DELIVERY LOCAL_DELIVERY=dovecot_delivery .endif .ifndef MAIN_RELAY_NETS MAIN_RELAY_NETS=: 127.0.0.1 : ::::1 .endif .ifndef DCreadhost DCreadhost=empty .endif .ifndef DCsmarthost DCsmarthost=empty .endif .ifndef DC_eximconfig_configtype DC_eximconfig_configtype=local .endif .ifndef DCconfig_local DCconfig_local=1 .endif ############################################## domainlist local_domains = MAIN_LOCAL_DOMAINS domainlist relay_to_domains = MAIN_RELAY_TO_DOMAINS hostlist relay_from_hosts = MAIN_RELAY_NETS .ifndef MAIN_PRIMARY_HOSTNAME_AS_QUALIFY_DOMAIN .ifndef MAIN_QUALIFY_DOMAIN qualify_domain = ETC_MAILNAME .else qualify_domain = MAIN_QUALIFY_DOMAIN .endif .endif .ifdef MAIN_LOCAL_INTERFACES local_interfaces = MAIN_LOCAL_INTERFACES .endif .ifndef LOCAL_DELIVERY LOCAL_DELIVERY=mail_spool .endif gecos_pattern = ^([^,:]*) gecos_name = $1 .ifndef CHECK_RCPT_LOCAL_LOCALPARTS CHECK_RCPT_LOCAL_LOCALPARTS = ^[.] : ^.*[@%!/|`#&?] .endif .ifndef CHECK_RCPT_REMOTE_LOCALPARTS CHECK_RCPT_REMOTE_LOCALPARTS = ^[./|] : ^.*[@%!`#&?] : ^.*/\\.\\./ .endif .ifndef MAIN_LOG_SELECTOR MAIN_LOG_SELECTOR = +tls_peerdn .endif .ifndef MAIN_ACL_CHECK_MAIL MAIN_ACL_CHECK_MAIL = acl_check_mail .endif acl_smtp_mail = MAIN_ACL_CHECK_MAIL .ifndef MAIN_ACL_CHECK_RCPT MAIN_ACL_CHECK_RCPT = acl_check_rcpt .endif acl_smtp_rcpt = MAIN_ACL_CHECK_RCPT .ifndef MAIN_ACL_CHECK_DATA MAIN_ACL_CHECK_DATA = acl_check_data .endif acl_smtp_data = MAIN_ACL_CHECK_DATA .ifdef MESSAGE_SIZE_LIMIT message_size_limit = MESSAGE_SIZE_LIMIT .endif .ifdef MAIN_ALLOW_DOMAIN_LITERALS allow_domain_literals .endif .ifndef DC_minimaldns .ifndef MAIN_HOST_LOOKUP MAIN_HOST_LOOKUP = * .endif host_lookup = MAIN_HOST_LOOKUP .endif .ifdef MAIN_HARDCODE_PRIMARY_HOSTNAME primary_hostname = MAIN_HARDCODE_PRIMARY_HOSTNAME .endif .ifdef MAIN_SMTP_ACCEPT_MAX_NOMAIL_HOSTS smtp_accept_max_nonmail_hosts = MAIN_SMTP_ACCEPT_MAX_NOMAIL_HOSTS .endif .ifndef MAIN_FORCE_SENDER local_from_check = false local_sender_retain = true untrusted_set_sender = * .endif .ifndef MAIN_IGNORE_BOUNCE_ERRORS_AFTER MAIN_IGNORE_BOUNCE_ERRORS_AFTER = 2d .endif ignore_bounce_errors_after = MAIN_IGNORE_BOUNCE_ERRORS_AFTER .ifndef MAIN_TIMEOUT_FROZEN_AFTER MAIN_TIMEOUT_FROZEN_AFTER = 7d .endif timeout_frozen_after = MAIN_TIMEOUT_FROZEN_AFTER .ifndef MAIN_FREEZE_TELL MAIN_FREEZE_TELL = postmaster .endif freeze_tell = MAIN_FREEZE_TELL .ifndef SPOOLDIR SPOOLDIR = /var/spool/exim4 .endif spool_directory = SPOOLDIR .ifndef MAIN_TRUSTED_USERS MAIN_TRUSTED_USERS = uucp .endif trusted_users = MAIN_TRUSTED_USERS .ifdef MAIN_TRUSTED_GROUPS trusted_groups = MAIN_TRUSTED_GROUPS .endif .ifdef MAIN_TLS_ENABLE .ifndef MAIN_TLS_ADVERTISE_HOSTS MAIN_TLS_ADVERTISE_HOSTS = * .endif tls_advertise_hosts = MAIN_TLS_ADVERTISE_HOSTS .ifdef MAIN_TLS_CERTKEY tls_certificate = MAIN_TLS_CERTKEY .else .ifndef MAIN_TLS_CERTIFICATE MAIN_TLS_CERTIFICATE = CONFDIR/exim.crt .endif tls_certificate = MAIN_TLS_CERTIFICATE .ifndef MAIN_TLS_PRIVATEKEY MAIN_TLS_PRIVATEKEY = CONFDIR/exim.key .endif tls_privatekey = MAIN_TLS_PRIVATEKEY .endif .ifndef MAIN_TLS_VERIFY_CERTIFICATES MAIN_TLS_VERIFY_CERTIFICATES = ${if exists{/etc/ssl/certs/ca-certificates.crt}\ {/etc/ssl/certs/ca-certificates.crt}\ {/dev/null}} .endif tls_verify_certificates = MAIN_TLS_VERIFY_CERTIFICATES .ifdef MAIN_TLS_VERIFY_HOSTS tls_verify_hosts = MAIN_TLS_VERIFY_HOSTS .endif .ifndef MAIN_TLS_TRY_VERIFY_HOSTS MAIN_TLS_TRY_VERIFY_HOSTS = * .endif tls_try_verify_hosts = MAIN_TLS_TRY_VERIFY_HOSTS .endif .ifdef MAIN_LOG_SELECTOR log_selector = MAIN_LOG_SELECTOR .endif begin acl acl_check_not_smtp: accept condition=${if IS_SENDER_SECMAIL {yes}{no}} control=suppress_local_fixups accept acl_local_deny_exceptions: accept hosts = ${if exists{CONFDIR/host_local_deny_exceptions}\ {CONFDIR/host_local_deny_exceptions}\ {}} accept senders = ${if exists{CONFDIR/sender_local_deny_exceptions}\ {CONFDIR/sender_local_deny_exceptions}\ {}} accept hosts = ${if exists{CONFDIR/local_host_whitelist}\ {CONFDIR/local_host_whitelist}\ {}} accept senders = ${if exists{CONFDIR/local_sender_whitelist}\ {CONFDIR/local_sender_whitelist}\ {}} .ifdef LOCAL_DENY_EXCEPTIONS_LOCAL_ACL_FILE .include LOCAL_DENY_EXCEPTIONS_LOCAL_ACL_FILE .endif .ifdef WHITELIST_LOCAL_DENY_LOCAL_ACL_FILE .include WHITELIST_LOCAL_DENY_LOCAL_ACL_FILE .endif acl_check_mail: .ifdef CHECK_MAIL_HELO_ISSUED deny message = no HELO given before MAIL command condition = ${if def:sender_helo_name {no}{yes}} .endif deny message = bad sender log_message = bad sender (auth_id=AUTH_SERVER_MAIL mismatches sender=$sender_address) condition = IS_SENDER_BAD accept acl_check_rcpt: .ifdef CHECK_RCPT_LOCAL_LOCALPARTS deny domains = +local_domains local_parts = CHECK_RCPT_LOCAL_LOCALPARTS message = restricted characters in address .endif .ifdef CHECK_RCPT_REMOTE_LOCALPARTS deny domains = !+local_domains local_parts = CHECK_RCPT_REMOTE_LOCALPARTS message = restricted characters in address .endif accept .ifndef CHECK_RCPT_POSTMASTER local_parts = postmaster .else local_parts = CHECK_RCPT_POSTMASTER .endif domains = +local_domains : +relay_to_domains .ifdef CHECK_RCPT_VERIFY_SENDER deny message = Sender verification failed !acl = acl_local_deny_exceptions !verify = sender .endif deny !acl = acl_local_deny_exceptions senders = ${if exists{CONFDIR/local_sender_callout}\ {CONFDIR/local_sender_callout}\ {}} !verify = sender/callout require verify = recipient accept authenticated = * condition = IS_SENDER_REMOTE require message = relay not permitted domains = +local_domains : +relay_to_domains deny !acl = acl_local_deny_exceptions recipients = ${if exists{CONFDIR/local_rcpt_callout}\ {CONFDIR/local_rcpt_callout}\ {}} !verify = recipient/callout deny message = sender envelope address $sender_address is locally blacklisted here. If you think this is wrong, get in touch with postmaster !acl = acl_local_deny_exceptions senders = ${if exists{CONFDIR/local_sender_blacklist}\ {CONFDIR/local_sender_blacklist}\ {}} deny message = sender IP address $sender_host_address is locally blacklisted here. If you think this is wrong, get in touch with postmaster !acl = acl_local_deny_exceptions hosts = ${if exists{CONFDIR/local_host_blacklist}\ {CONFDIR/local_host_blacklist}\ {}} .ifdef CHECK_RCPT_REVERSE_DNS warn message = X-Host-Lookup-Failed: Reverse DNS lookup failed for $sender_host_address (${if eq{$host_lookup_failed}{1}{failed}{deferred}}) condition = ${if and{{def:sender_host_address}{!def:sender_host_name}}\ {yes}{no}} .endif .ifdef CHECK_RCPT_SPF 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 --ip \"$sender_host_address\" --mail-from \"$sender_address\" --helo \"$sender_helo_name\"}\ {no}{${if eq {$runrc}{1}{yes}{no}}}} defer message = Temporary DNS error while checking SPF record. Try again later. condition = ${if eq {$runrc}{5}{yes}{no}} warn message = Received-SPF: ${if eq {$runrc}{0}{pass}{${if eq {$runrc}{2}{softfail}\ {${if eq {$runrc}{3}{neutral}{${if eq {$runrc}{4}{unknown}{${if eq {$runrc}{6}{none}{error}}}}}}}}}} condition = ${if <={$runrc}{6}{yes}{no}} warn log_message = Unexpected error in SPF check. condition = ${if >{$runrc}{6}{yes}{no}} warn message = X-SPF-Guess: ${run{/usr/bin/spfquery --ip \"$sender_host_address\" --mail-from \"$sender_address\" \ --helo \"$sender_helo_name\" --guess true}\ {pass}{${if eq {$runrc}{2}{softfail}{${if eq {$runrc}{3}{neutral}{${if eq {$runrc}{4}{unknown}\ {${if eq {$runrc}{6}{none}{error}}}}}}}}}} condition = ${if <={$runrc}{6}{yes}{no}} defer message = Temporary DNS error while checking SPF record. Try again later. condition = ${if eq {$runrc}{5}{yes}{no}} .endif .ifdef CHECK_RCPT_IP_DNSBLS warn message = X-Warning: $sender_host_address is listed at $dnslist_domain ($dnslist_value: $dnslist_text) log_message = $sender_host_address is listed at $dnslist_domain ($dnslist_value: $dnslist_text) dnslists = CHECK_RCPT_IP_DNSBLS .endif .ifdef CHECK_RCPT_DOMAIN_DNSBLS warn message = X-Warning: $sender_address_domain is listed at $dnslist_domain ($dnslist_value: $dnslist_text) log_message = $sender_address_domain is listed at $dnslist_domain ($dnslist_value: $dnslist_text) !senders = ${if exists{CONFDIR/local_domain_dnsbl_whitelist}\ {CONFDIR/local_domain_dnsbl_whitelist}\ {}} dnslists = CHECK_RCPT_DOMAIN_DNSBLS .endif .ifdef CHECK_RCPT_LOCAL_ACL_FILE .include CHECK_RCPT_LOCAL_ACL_FILE .endif accept domains = +relay_to_domains endpass verify = recipient accept acl_check_data: .ifdef CHECK_DATA_VERIFY_HEADER_SYNTAX deny message = Message headers fail syntax check !acl = acl_local_deny_exceptions !verify = header_syntax .endif .ifdef CHECK_DATA_VERIFY_HEADER_SENDER deny message = No verifiable sender address in message headers !acl = acl_local_deny_exceptions !verify = header_sender .endif .ifdef CHECK_DATA_LOCAL_ACL_FILE .include CHECK_DATA_LOCAL_ACL_FILE .endif accept begin routers .ifdef MAIN_ALLOW_DOMAIN_LITERALS domain_literal: debug_print = "R: domain_literal for $local_part@$domain" driver = ipliteral domains = ! +local_domains transport = remote_smtp .endif hubbed_hosts: debug_print = "R: hubbed_hosts for $domain" driver = manualroute domains = "${if exists{CONFDIR/hubbed_hosts}\ {partial-lsearch;CONFDIR/hubbed_hosts}\ fail}" same_domain_copy_routing = yes route_data = ${lookup{$domain}partial-lsearch{CONFDIR/hubbed_hosts}} transport = remote_smtp system_aliases: debug_print = "R: system_aliases for $local_part@$domain" driver = redirect domains = +local_domains allow_fail allow_defer data = ${lookup{$local_part}lsearch{/etc/aliases}} .ifdef SYSTEM_ALIASES_USER user = SYSTEM_ALIASES_USER .endif .ifdef SYSTEM_ALIASES_GROUP group = SYSTEM_ALIASES_GROUP .endif .ifdef SYSTEM_ALIASES_FILE_TRANSPORT file_transport = SYSTEM_ALIASES_FILE_TRANSPORT .endif .ifdef SYSTEM_ALIASES_PIPE_TRANSPORT pipe_transport = SYSTEM_ALIASES_PIPE_TRANSPORT .endif .ifdef SYSTEM_ALIASES_DIRECTORY_TRANSPORT directory_transport = SYSTEM_ALIASES_DIRECTORY_TRANSPORT .endif .ifndef FIRST_USER_ACCOUNT_UID FIRST_USER_ACCOUNT_UID = 0 .endif .ifndef DEFAULT_SYSTEM_ACCOUNT_ALIAS DEFAULT_SYSTEM_ACCOUNT_ALIAS = :fail: no mail to system accounts .endif COND_SYSTEM_USER_AND_REMOTE_SUBMITTER = "\ ${if and{{! match_ip{$sender_host_address}{:@[]}}\ {<{$local_user_uid}{FIRST_USER_ACCOUNT_UID}}}\ {1}{0}\ }" lowuid_aliases: debug_print = "R: lowuid_aliases for $local_part@$domain (UID $local_user_uid)" check_local_user driver = redirect allow_fail domains = +local_domains condition = COND_SYSTEM_USER_AND_REMOTE_SUBMITTER data = ${if exists{/etc/exim4/lowuid-aliases}\ {${lookup{$local_part}lsearch{/etc/exim4/lowuid-aliases}\ {$value}{DEFAULT_SYSTEM_ACCOUNT_ALIAS}}}{DEFAULT_SYSTEM_ACCOUNT_ALIAS}} local_user_secmail: debug_print = "R: local_user_secmail for $local_part@$domain" driver = accept domains = +local_domains local_parts = ! root condition = ${if IS_SENDER_SECMAIL {IS_LOCAL_PART_VALID}{no}} transport = LOCAL_DELIVERY_SECMAIL local_user: debug_print = "R: local_user for $local_part@$domain" driver = accept domains = +local_domains local_parts = ! root condition = IS_LOCAL_PART_VALID transport = LOCAL_DELIVERY cannot_route_message = Unknown user ldap_uid_aliases: debug_print = "R: ldap_uid_alias for $local_part@$domain" driver = redirect data = GET_UID_FOR_RCPT check_ancestor ldap_aliases: debug_print = "R: ldap_alias for $local_part@$domain" driver = redirect data = GET_ALIAS_FOR_RCPT check_ancestor .ifdef DCconfig_satellite hub_user: debug_print = "R: hub_user for $local_part@$domain" driver = redirect domains = +local_domains data = ${local_part}@DCreadhost check_local_user hub_user_smarthost: debug_print = "R: hub_user_smarthost for $local_part@$domain" driver = manualroute domains = DCreadhost transport = remote_smtp_smarthost route_list = * DCsmarthost byname host_find_failed = defer same_domain_copy_routing = yes check_local_user .endif smarthost_auto: condition = IS_AUTH_REMOTE driver = manualroute domains = ! +local_domains route_data = AUTH_REMOTE_SERVER transport = remote_smtp_smarthost_auto mail4root: debug_print = "R: mail4root for $local_part@$domain" driver = redirect domains = +local_domains data = /var/mail/mail file_transport = address_file local_parts = root user = mail group = mail begin transports .ifdef HIDE_MAILNAME REMOTE_SMTP_HEADERS_REWRITE=*@+local_domains $1@DCreadhost frs : *@ETC_MAILNAME $1@DCreadhost frs REMOTE_SMTP_RETURN_PATH=${if match_domain{$sender_address_domain}{+local_domains}{${sender_address_local_part}@DCreadhost}{${if match_domain{$sender_address_domain}{ETC_MAILNAME}{${sender_address_local_part}@DCreadhost}fail}}} .endif .ifdef REMOTE_SMTP_HELO_FROM_DNS REMOTE_SMTP_HELO_DATA=${lookup dnsdb {ptr=$sending_ip_address}{$value}{$primary_hostname}} .endif address_file: debug_print = "T: address_file for $local_part@$domain" driver = appendfile delivery_date_add envelope_to_add return_path_add address_pipe: debug_print = "T: address_pipe for $local_part@$domain" driver = pipe return_fail_output address_reply: debug_print = "T: autoreply for $local_part@$domain" driver = autoreply dovecot_delivery: debug_print = "T: dovecot_delivery_pipe for $local_part@$domain translates to GET_LOCAL_MAIL" driver = pipe command = /usr/lib/dovecot/deliver -d "GET_LOCAL_MAIL" message_prefix = message_suffix = delivery_date_add envelope_to_add return_path_add log_output user = secmail group = secmail dovecot_delivery_secmail: debug_print = "T: dovecot_delivery_pipe_secmail for $local_part@$domain translates to GET_LOCAL_MAIL" driver = pipe command = /usr/lib/dovecot/deliver -d "GET_LOCAL_MAIL" message_prefix = message_suffix = delivery_date_add = false envelope_to_add = false return_path_add = false log_output user = secmail group = secmail mail_spool: debug_print = "T: appendfile for $local_part@$domain" driver = appendfile file = /var/mail/$local_part delivery_date_add envelope_to_add return_path_add group = mail mode = 0660 mode_fail_narrower = false maildir_home: debug_print = "T: maildir_home for $local_part@$domain" driver = appendfile .ifdef MAILDIR_HOME_MAILDIR_LOCATION directory = MAILDIR_HOME_MAILDIR_LOCATION .else directory = $home/Maildir .endif .ifdef MAILDIR_HOME_CREATE_DIRECTORY create_directory .endif .ifdef MAILDIR_HOME_CREATE_FILE create_file = MAILDIR_HOME_CREATE_FILE .endif delivery_date_add envelope_to_add return_path_add maildir_format .ifdef MAILDIR_HOME_DIRECTORY_MODE directory_mode = MAILDIR_HOME_DIRECTORY_MODE .else directory_mode = 0700 .endif .ifdef MAILDIR_HOME_MODE mode = MAILDIR_HOME_MODE .else mode = 0600 .endif mode_fail_narrower = false maildrop_pipe: debug_print = "T: maildrop_pipe for $local_part@$domain" driver = pipe path = "/bin:/usr/bin:/usr/local/bin" command = "/usr/bin/maildrop" return_path_add delivery_date_add envelope_to_add procmail_pipe: debug_print = "T: procmail_pipe for $local_part@$domain" driver = pipe path = "/bin:/usr/bin:/usr/local/bin" command = "/usr/bin/procmail" return_path_add delivery_date_add envelope_to_add remote_smtp: debug_print = "T: remote_smtp for $local_part@$domain" driver = smtp .ifdef REMOTE_SMTP_HOSTS_AVOID_TLS hosts_avoid_tls = REMOTE_SMTP_HOSTS_AVOID_TLS .endif .ifdef REMOTE_SMTP_HEADERS_REWRITE headers_rewrite = REMOTE_SMTP_HEADERS_REWRITE .endif .ifdef REMOTE_SMTP_RETURN_PATH return_path = REMOTE_SMTP_RETURN_PATH .endif .ifdef REMOTE_SMTP_HELO_FROM_DNS helo_data=REMOTE_SMTP_HELO_DATA .endif remote_smtp_smarthost: debug_print = "T: remote_smtp_smarthost for $local_part@$domain" driver = smtp hosts_try_auth = <; ${if exists{CONFDIR/passwd.client} \ {\ ${lookup{$host}nwildlsearch{CONFDIR/passwd.client}{$host_address}}\ }\ {} \ } .ifdef REMOTE_SMTP_SMARTHOST_HOSTS_AVOID_TLS hosts_avoid_tls = REMOTE_SMTP_SMARTHOST_HOSTS_AVOID_TLS .endif .ifdef REMOTE_SMTP_HEADERS_REWRITE headers_rewrite = REMOTE_SMTP_HEADERS_REWRITE .endif .ifdef REMOTE_SMTP_RETURN_PATH return_path = REMOTE_SMTP_RETURN_PATH .endif .ifdef REMOTE_SMTP_HELO_FROM_DNS helo_data=REMOTE_SMTP_HELO_DATA .endif remote_smtp_smarthost_auto: debug_print = "T: remote_smtp_smarthost_auto for $local_part@$domain from user AUTH_SERVER_MAIL" driver = smtp hosts_require_auth = AUTH_REMOTE_SERVER address_directory: debug_print = "T: address_directory for $local_part@$domain" driver = appendfile delivery_date_add envelope_to_add return_path_add check_string = "" escape_string = "" maildir_format begin retry * * F,2h,15m; G,16h,1h,1.5; F,4d,6h begin rewrite .ifndef NO_EAA_REWRITE_REWRITE *@+local_domains "${lookup{${local_part}}lsearch{/etc/email-addresses}\ {$value}fail}" Ffrs *@ETC_MAILNAME "${lookup{${local_part}}lsearch{/etc/email-addresses}\ {$value}fail}" Ffrs .endif begin authenticators plain_ldapauth_server: driver = plaintext public_name = PLAIN .ifndef AUTH_SERVER_ALLOW_NOTLS_PASSWORDS server_advertise_condition = ${if eq{$tls_cipher}{}{}{*}} .endif server_condition = AUTH_SERVER_PLAIN_AUTH server_set_id = $auth2/$auth3 server_prompts = : login_ldapauth_server: driver = plaintext public_name = LOGIN server_prompts = Username:: : Password:: .ifndef AUTH_SERVER_ALLOW_NOTLS_PASSWORDS server_advertise_condition = ${if eq{$tls_cipher}{}{}{*}} .endif server_condition = AUTH_SERVER_LOGIN_AUTH server_set_id = $auth1/$auth2 cram_md5_client: driver = cram_md5 public_name = CRAM-MD5 client_name = AUTH_REMOTE_LOGIN client_secret = AUTH_REMOTE_PASSWORD plain_client: driver = plaintext public_name = PLAIN client_send = <|^AUTH_REMOTE_LOGIN^AUTH_REMOTE_PASSWORD login_client: driver = plaintext public_name = LOGIN client_send = <| | AUTH_REMOTE_LOGIN | AUTH_REMOTE_PASSWORD
Die Konfigurationsdatei ist auf den ersten Blick sehr umfangreich, allerdings gibt es eine exzellente Dokumentation von Exim. Dort sind insbesondere die Abschnitte zu Lookups (wegen LDAP) und String Expansions interessant. Allgemeine Konfigurationshinweise für Exim unter Debian/Ubuntu hat Justin Koivisto zusammengestellt. Den Beitrag von Wolfgang Hennerbichler zur Einrichtung der TLS-Verschlüsselung der SMTP-Verbindung zusammen mit der Dokumentation von exim4-config zu diesem Thema empfand ich ebenfalls hilfreich wie auch den Forumsthread, der die Verwendung von $authenticated_id und die Anpassung des received_header_text dokumentiert. Die Mailingliste von exim enthält einen sehr guten Beitrag, mit ausführlicher Beispielkonfiguration, wie E-Mails via Authentifizierung über externe Mailserver verschickt werden können. Wie man mehrere Smarthosts mit Exim verwendt, beschreibt auch Thorsten Gunkel.
Nun testen wir die Exim-Konfiguration, ob auch alles wie gewünscht funktioniert.
exim -bt paul@myserver
sollte folgendes ausgeben
R: system_aliases for paul@myserver R: local_user_secmail for paul@myserver R: local_user for paul@myserver paul@myserver router = local_user, transport = dovecot_delivery
analog sollte ein
exim -bt paulpanzer@gmx.de
zu folgendem Resultat führen
R: ldap_uid_alias for paulpanzer@gmx.de
R: system_aliases for paul@myserver
R: local_user_secmail for paul@myserver
R: local_user for paul@myserver
paul@myserver
<-- paulpanzer@gmx.de
router = local_user, transport = dovecot_deliveryIm nächsten Schritt können wir auch eine SMTP-Session testen. Dazu erzeugen wir mit dem Befehl
echo -ne '\0paul@paulpanzer@gmx.de\0test' | base64
eine Zeichenfolge zur Authentifizierung, wobei paul für den Benutzer steht, paulpanzer@gmx.de für die externe Mailaddresse und test für das Passwort von paul (es besteht keine Verbindung zu den Passwörtern von paulpanzer@gmx.de). Ich erhalte hier AHBhdWxAcGF1bHBhbnplckBnbXguZGUAdGVzdA==. Wir starten mit
openssl s_client -starttls smtp -crlf -connect myserver:25
eine verschlüsselte SMTP-Session und verschicken eine Testmail an paul@myserver, indem wir folgende Befehle eingeben (alle Zeilen, die nicht mit einer Zahl beginnen)
250 HELP ehlo client 250-myserver Hello myserver [127.0.1.1] 250-SIZE 52428800 250-PIPELINING 250-AUTH PLAIN LOGIN 250 HELP AUTH PLAIN AHBhdWxAcGF1bHBhbnplckBnbXguZGUAdGVzdA== 235 Authentication succeeded mail from: paulpanzer@gmx.de 250 OK rcpt to: paul@myserver 250 Accepted data 354 Enter message, ending with "." on a line by itself From: Paul Panzer <paulpanzer@gmx.de> To: Paul <paul@myserver> Subject: Testing SMTP This is a test body. . 250 OK id=1Ll9N3-0001hf-6J quit 221 myserver closing connection closed
Wer im Detail nachlesen möchte, was die einzelnen Befehle bewirken, dem sei die Anleitung zum Testen von SMTP per Telnet von John M. Simpson empfohlen. Als Resultat des Tests sollten wir im Verzeichnis /home/paul/mail/paul/maildir/INBOX/new/ eine Datei haben, die in etwa folgenden Inhalt hat
Return-path: <paulpanzer@gmx.de> Envelope-to: paul@myserver Delivery-date: Sat, 21 Mar 2009 23:18:09 +0100 Received: from myserver ([127.0.1.1] helo=la) by myserver with esmtpsa (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.69) (envelope-from <paulpanzer@gmx.de>) id 1Ll9Vy-0001jC-N8 for paul@myserver; Sat, 21 Mar 2009 23:18:09 +0100 From: Paul Panzer <paulpanzer@gmx.de> To: Paul <paul@myserver> Subject: Testing SMTP This is a test body.
Fehlerquellen in der Konfiguration finden
Falls exim nicht das gewünschte Resultat liefert oder bei der Auslieferung an eine bestimmte Addresse ein Fehler auftritt, hilft es, Exim im Debug-Modus zu starten. Beispielsweise kann man eine derartige Batch-SMTP-Session über folgenden Befehl starten
sudo exim4 -C /var/lib/exim4/config.autogenerated -v -d+all -bs
Um zu testen, wie Exim intern die Mailaddressen routet, können wir mit
sudo exim -v -d-all+lookup -bt paulpanzer@gmx.de
alle zugehörigen lookups von exim verfolgen. Durch das “-all+lookup” werden nur Informationen ausgeben, die mit lookups zu tun haben.
Umgang mit Exim
Exim besitzt eine Vielzahl an Kommandozeilenoptionen. Sich in der man-page zurechtzufinden ist daher nicht einfach, allerdings habe ich eine sehr gute Zusammenstellung einzelner Exim-Befehle gefunden. Ein Befehl fehlt dabei jedoch. Mit
sudo exim -qff
kann man das erneute Auslierfern von “frozen messages”, also als unzustellbar marktierten Mails, erzwingen.
Der vierte Teil der Konfiguration beschäftigt sich mit der Einrichtung von getmail zum Abruf externer Mails via POP3/IMAP.


Mittlerweile hat sich im Debian/Ubuntu-Paket von exim die Einstellung zum Mailhostnamen geändert. Der Hostname wird nicht mehr über den FQDN (hostname –fqdn) festgelegt sondern aus der Datei /etc/mailname ausgelesen, so dass in der automatisch erzeugten Konfigurationsdatei die Variable ETC_MAILNAME entsprechend gesetzt wird. Deshalb musste ich bei mir dir /etc/mailname anpassen.
[...] habe. In den letzten vier Blogartikeln wurde das Zusammenspiel der Grundkomponenten mit Dovecot, Exim, OpenLDAP und getmail konfiguriert. Jetzt geht es ans Feintuning – das Einrichten eines [...]