# vim:noet:ts=8:sw=2 # Updated 050702, notes {at} notes.for.sabi.co.UK # This file is divided into several parts, all but the last of which are # terminated by a line containing the word "end". The parts must appear # in the correct order, and all must be present (even if some of them are # in fact empty). Blank lines, and lines starting with # are ignored. # Defined macros. For the rather peculiar semantics read carefully: # http://www.exim.org/exim-html-4.30/doc/html/spec_6.html#IX551 QUEUEING =x BOGOFILTERING =x # These two not yet finished/tested. #HAS_PAM =x #HAS_TLS =x FILE_PASS =/etc/shadow FILE_CRAM_MD5 =/etc/exim4/cram_md5 #FILE_DENY_F =/etc/alias/f2deny #FILE_ACCEPT_AF =/etc/alias/af2accept #FILE_DENY_A =/etc/alias/a2deny FILE_ALIAS_A2A =/etc/alias/a2a FILE_ALIAS_D2A =/etc/alias/d2a FILE_ALIAS_D2D =/etc/alias/d2d FILE_ALIAS_D2HOST =/etc/alias/d2host # MAIN CONFIGURATION SETTINGS # Specify your host's canonical name here. If this option is not set, # the uname() function is called to obtain the name. The name is used # in the SMTP banner (HELO/EHLO), so should match your sender's domain # (some idiotic sites do check that HELO and MAIL FROM: headers match). primary_hostname =sabi.co.UK # Specify the domain you want to be added to all unqualified addresses # here. If this option is not set, the primary_hostname value is used. #qualify_domain = #sender_unqualified_hosts = # If you want unqualified recipient addresses to be qualified with a different # domain to unqualified sender addresses, specify the recipient domain here. # If this option is not set, the qualify_domain value is used. #qualify_recipient = #recipient_unqualified_hosts = # Specify your local domains as a colon-separated list here. If this option # is not set, the qualify_recipient value is used as the only local domain. # If you do not want to do any local deliveries, uncomment the following line, # but do not supply any data for it. domainlist local_domains =@:@[]:localhost\ :sabi.co.UK:*.sabi.co.UK domainlist relay_to_domains = hostlist relay_from_hosts =@:@[]:localhost:sabi.co.UK .ifdef HAS_TLS tls_certificate =/etc/exim4/site_Certificate.pem tls_privatekey =/etc/exim4/site_Private_key.pem tls_advertise_hosts =${if exists {${tls_certificate}}\ {*} {127.0.0.1/8}} .endif received_header_text ="Received: \ from ${if def:sender_rcvhost\ {from ${sender_rcvhost}}\ {${if def:sender_ident {${sender_ident}}}\ ${if def:sender_helo_name {(helo=${sender_helo_name})}}}}\n\ \tby ${primary_hostname} \ ${if def:received_protocol {with ${received_protocol}}}\ ${if def:tls_cipher {(Cipher ${tls_cipher})}}\ ${if def:tls_peerdn {(PeerDN ${tls_peerdn})}}\ (Exim ${version_number} #${compile_number})\n\ \tid ${message_id}\ ${if def:authenticated_id {by authid <${authenticated_id}>}}\ ${if def:sender_host_authenticated {with ${sender_host_authenticated}}}\ ${if def:received_for {\n\tfor <${received_for}>}}" # The default for 'acl_smtp_etrn', 'acl_smtp_expn', 'acl_smtp_vrfy', # and 'acl_smtp_rcpt' is 'deny'. #acl_not_smtp = #acl_smtp_connect = #acl_smtp_starttls = #acl_smtp_auth = #acl_smtp_etrn = acl_smtp_expn =acl_local acl_smtp_vrfy =accept #acl_smtp_helo = acl_smtp_mail =acl_check_mail acl_smtp_rcpt =acl_check_rcpt #acl_smtp_data = allow_domain_literals =true percent_hack_domains = host_lookup =!* #helo_verify_hosts = #helo_try_verify_hosts = #helo_accept_junk_hosts = #host_reject_connection = rfc1413_hosts =!* rfc1413_query_timeout =30s # This option unfreezes frozen bounce messages after two days, tries # once more to deliver them, and ignores any delivery failures. ignore_bounce_errors_after =2d # This option cancels (removes) frozen messages that are older than a week. timeout_frozen_after =7d #queue_only =false #queue_only_file =/var/run/ppp-down .ifdef QUEUEING queue_domains =!+local_domains queue_smtp_domains =!+local_domains .endif ##smtp_verify =true smtp_accept_max =10 smtp_accept_max_per_host =3 smtp_accept_queue =8 smtp_accept_queue_per_connection=80 smtp_accept_reserve =3 smtp_reserve_hosts =+local_domains # No local deliveries will ever be run under the uids of these users. #never_users =root # If you are running Exim under its own uid (recommended), then you should # set up that uid as a trusted user by de-commenting the following and # changing the name if necessary. exim_user =Debian-exim exim_group =Debian-exim trusted_users =pcg trusted_groups =pcg log_file_path =syslog #log_file_path =/var/log/exim/%s.log ######################################################################## begin acl # Some bits inspired by: # Lots of ACL examples here: acl_local: accept authenticated =* accept hosts =: accept hosts =+relay_from_hosts acl_check_auth: accept encrypted =* accept condition =${if eq \ {${uc:${smtp_command_argument}}}{CRAM-MD5} \ {yes}{no}} deny message =TLS encryption or CRAM-MD5 required acl_check_mail: .ifdef FILE_DENY_F # Check the sender. deny message =No more space senders =lsearch*@;FILE_DENY_F .endif deny message =Only ASCII can be used in envelope sender\n\ (see RFC 2821, section 4.1.2) senders =\N[\x80-\xFF]\N accept acl_check_rcpt: .ifdef FILE_ACCEPT_AF # Accept specific recipient address/sender address combinations. accept senders =${lookup{${local_part}@${domain}} \ lsearch*@{FILE_ACCEPT_AF}} .endif .ifdef FILE_DENY_A # Deny specific recipient addresses. deny message =Connection fault recipients =lsearch*@;FILE_DENY_A .endif deny message =Cannot have "@%!/|" in local part local_parts =[@%!/|] warn message =X-Blacklisted-At: ${dnslist_domain} dnslists =blackholes.mail-abuse.org\ :dialup.mail-abuse.org # defer # message =Try again later # Check who has connected. accept authenticated =* accept hosts =: accept hosts =+relay_from_hosts # Check the destination. accept local_parts =postmaster accept domains =+relay_to_domains endpass message =Unrouteable address accept domains =+local_domains endpass message =Unknown address verify =recipient deny message =Relay not permitted acl_check_data: deny message =Only ASCII allowed in 'Subject:' header.\n\ (see RFC 2822, sections 3.6.5, 2.2.1) condition =${if match {${h_Subject:}}{\N[\x80-\xFF]\N}\ {yes}{no}} deny message =Only ASCII allowed in 'From:' header.\n\ (see RFC 2822, sections 3.4, 3.2.4, 3.2.5) condition =${if match {${h_From:}}{\N[\x80-\xFF]\N}\ {yes}{no}} accept ######################################################################## begin routers # ROUTERS CONFIGURATION # ORDER MATTERS GREATLY HERE # Possible routers: # allow_accept Always accepts an address. It has no private options. # dnslookup Routes by DNS lookup (descended from lookuphost). # ipliteral Routes IP literal addresses (unchanged). # iplookup Special-purpose lookup router (unchanged). # manualroute Routes domains from explicit data (descended from domainlist). # queryprogram Routes addresses by running a program (detail changed). # redirect Redirects addresses; handles all the functions previously # supported by aliasfile, forwardfile, and smartuser without # a transport. # Possible router conditions in the order in which they are tested: # 1) verify status, expn status, domains, local_parts, check_local_user # 2) debug_print # 3) senders, require_files, condition # First we alias addresses which include domains, as this may change # the delivery domain, from example from remote to local or viceversa. # The aliasing routers are in order of most specific to most generic. # Now we know the real delivery domain, and first we route to remote domains. .ifdef FILE_ALIAS_A2A # Alias a single address to another single address. alias_address_to_address: debug_print ="R: ${local_part}@${domain}: address to address" driver =redirect require_files =FILE_ALIAS_A2A data =${lookup {${local_part}@${domain}}\ lsearch{FILE_ALIAS_A2A}} repeat_use =false local_part_suffix =_* local_part_suffix_optional =true qualify_preserve_domain =false check_local_user =false allow_fail =true allow_defer =true file_transport =address_file pipe_transport =address_pipe .endif .ifdef FILE_ALIAS_D2A # Alias a whole domain to a single address. alias_domain_to_address: debug_print ="R: ${local_part}@${domain}: domain to address" driver =redirect require_files =FILE_ALIAS_D2A data =${lookup {${domain}} \ partial-lsearch{FILE_ALIAS_D2A}} repeat_use =false qualify_preserve_domain =false check_local_user =false allow_fail =true allow_defer =true file_transport =address_file pipe_transport =address_pipe .endif .ifdef FILE_ALIAS_D2D # Alias a whole domain to another whole domain, with the same local part. alias_domain_to_domain: debug_print ="R: ${local_part}@${domain}: domain to domain" driver =redirect require_files =FILE_ALIAS_D2D data =${lookup {${domain}}\ partial-lsearch{FILE_ALIAS_D2D}\ {${local_part}@${value}} {}} repeat_use =false qualify_preserve_domain =false check_local_user =false allow_fail =true allow_defer =true forbid_file =true forbid_pipe =true .endif # Now we know the real delivery domain, and first we route to remote domains. # This router handled IP literal addresses @[a.b.c.d], which is # required by the relevant RFCs and is still useful. domain_literal: debug_print ="R: ${local_part}@${domain}: domain literal" driver =ipliteral domains =!+local_domains transport =remote_smtp .ifdef FILE_ALIAS_D2HOST # We want to route some domains to a ''smart'' (gw) host. domain_smarthost: debug_print ="R: ${local_part}@${domain}: smarthost" driver =manualroute require_files =FILE_ALIAS_D2HOST route_data =${lookup {${domain}}\ partial-lsearch{FILE_ALIAS_D2HOST}} host_find_failed =defer same_domain_copy_routing =true verify =false transport =remote_smtp .endif # This router routes to remote hosts over SMTP using a DNS lookup # with default options. dnslookup_relay: debug_print ="R: ${local_part}@${domain}: DNS MX relay" driver =dnslookup domains =+relay_to_domains same_domain_copy_routing =yes transport =remote_smtp more =false dnslookup: debug_print ="R: ${local_part}@${domain}: DNS MX non relay" driver =dnslookup domains =!+local_domains ignore_target_hosts =0.0.0.0/32:127.0.0.0/8 transport =remote_smtp more =false # OK, the domain now is guaranteed to be local, because the preceding # routers handled all possible cases of non local domains. # From this point onwards we only really care about local parts, # as we assume that all local domains share the same list of users. # Classic mailing lists: alias a local part to a list of addresses in a file. alias_user_to_list: debug_print ="R: alias to '/etc/list/${local_part}'" driver =redirect file =/etc/list/${local_part} include_directory =/etc/list local_part_prefix =list- check_local_user =false allow_fail =true allow_defer =true forbid_file =true forbid_pipe =true one_time =true # Classic aliases: alias a local part to a single address. alias_user_to_address: debug_print ="R: alias ${local_part} in '/etc/aliases'" driver =redirect data =${lookup {${local_part}} lsearch{/etc/aliases}} local_part_suffix =_* local_part_suffix_optional =true check_local_user =false user =Debian-exim group =Debian-exim allow_fail =true allow_defer =true file_transport =address_file pipe_transport =address_pipe # Now the local part must be the address of some user... userforward: debug_print ="R: alias in '~${home}/.forward'" driver =redirect file =${home}/.forward check_ancestor =true check_local_user =true verify =false expn =false #filter =true file_transport =address_file pipe_transport =address_pipe reply_transport =address_reply # The domain is local and neither the domain nor the local part are aliased... # If it is root, we deliver the mail without further ado toroot: debug_print ="R: deliver to 'root'" driver =accept local_parts =root transport =local_delivery # It's a normal user mailbox... .ifdef BOGOFILTERING # So first check whether is has been filtered for spam, if it has not, # then do so. bogofilter: debug_print ="R: pass to 'bogofiltering' transport'" driver =accept condition =${if or \ {{def:h_X-SpamFiltered:}\ {def:h_X-BogoFiltered:}\ {def:h_X-UWA-UCE-Check:}\ {def:h_X-Spam:}} {no}{yes}} check_local_user verify =false expn =false transport =bogofiltering .endif # If the user is on vacation, send an automatic reply now, # and continue as if it had not matched here. onvacation: debug_print ="R: check for '${home}/.vacation'" driver =accept condition =${if eq {${h_X-Spam}}{Yes} {no} {yes}} require_files ="${home}/.vacation" unseen =true transport =vacationing # If the user has a procmailrc file we pass the mail to # procmail doprocmail: debug_print ="R: check for '${home}/.procmailrc'" driver =accept require_files ="${home}/.procmailrc" transport =procmail more =false # else we append it directly to the user's mailbox localuser: debug_print ="R: local delivery for '${local_part}'" driver =accept caseful_local_part =true local_part_suffix =_* local_part_suffix_optional =true check_local_user =true transport =local_delivery more =false # It's not an alias, a mailing list, root, or a user; is it # Superman? No, it's a bad address #dosink: # driver =smartuser # verify =false # transport =unknown ######################################################################## begin transports # TRANPORTS CONFIGURATION # Here are some pretty standard transports remote_smtp: debug_print ="T: connect to remote SMTP" driver =smtp connection_max_messages =500 #rcpt_max =100 local_delivery: debug_print ="T: append to '/var/mail/${local_part}'" driver =appendfile file =/var/mail/${local_part} notify_comsat =true envelope_to_add =true return_path_add =true delivery_date_add =true group =mail mode =0660 procmail: debug_print ="T: run 'procmail -d ${local_part}'" driver =pipe command ="/usr/bin/procmail -d ${local_part}" flexfax: debug_print ="T: run '| mailfax'" driver =pipe command ="/usr/bin/mailfax" unknown: debug_print ="T: run '| exiunknown'" driver =pipe command ="/usr/sbin/exiunknown" ignore_status =true return_output =true user =Debian-exim group =Debian-exim bogofiltering: debug_print ="T: pipe via 'bogofilter -e -p -l'" driver =pipe command =/usr/sbin/exim4 -oMr BogoFiltered -bS ignore_status =false log_output =true return_output =false return_fail_output =true return_path_add =false envelope_to_add =false use_shell =false use_bsmtp =true batch_max =8 transport_filter =/usr/bin/bogofilter -e -p -l headers_add =X-BogoFiltered: Yes user =Debian-exim group =Debian-exim home_directory ="/tmp" current_directory ="/tmp" vacationing: debug_print ="T: send contents of '${home}/.vacation'" driver =autoreply file ="${home}/.vacation" to ="${return_path}" from ="${local_part}@${domain}" subject ="Re: ${header_subject}" text ="[User '${local_part}' vacation message]\n\n" once ="${home}/.vacation_sent" log ="${home}/.vacation_log" # The transports address_pipe, address_file, address_directory and # address_reply are used by exim internally, and their names are # conventional (well-known to exim). # address_pipe is used for handling pipe addresses generated by alias # or .forward files. # address_file is used for handling file addresses generated by alias # or .forward files. # address_directory is used for handling file addresses generated by alias # or .forward files if the path ends in "/". # address_reply is used for handling autoreplies generated by the filtering # option of the forwardfile director. address_pipe: debug_print ="T: internal: 'address_pipe'" driver =pipe return_output =true ignore_status =true address_file: debug_print ="T: internal: 'address_file'" driver =appendfile # notify_comsat =true delivery_date_add =true envelope_to_add =true return_path_add =true address_directory: debug_print ="T: internal: 'address_directory'" driver =appendfile message_prefix ="" address_reply: debug_print ="T: internal: 'address_reply'" driver =autoreply ######################################################################## begin retry # RETRY CONFIGURATION # This single retry rule applies to all domains and all errors. It specifies # retries every 15 minutes for 2 hours, then increasing retry intervals, # starting at 2 hours and increasing each time by a factor of 1.5, up to 16 # hours, then retries every 8 hours until 4 days have passed since the first # failed delivery. # Domain Error Retries # ------ ----- ------- * * F,2h,15m; G,16h,2h,1.5; F,4d,8h ######################################################################## begin rewrite # REWRITE CONFIGURATION ######################################################################## begin authenticators plain: driver =plaintext public_name =PLAIN server_advertise_condition =${if eq{${tls_cipher}}{} {no}{yes}} server_prompts =: .ifdef HAS_PAM server_condition =${if pam{$2:${sg{$3}{:}{::}}} {yes}{no}} .else .ifdef FILE_PASS server_condition =${lookup {$2} lsearch{FILE_PASS}\ {${if crypteq{$3}\ {${extract{1}{:}{${value}}}}\ {yes}{no}}}\ {no}} .else server_condition =no .endif .endif server_set_id =$2 login: driver =plaintext public_name =LOGIN server_advertise_condition =${if eq{${tls_cipher}}{} {no}{yes}} server_prompts =Username:: : Password:: .ifdef HAS_PAM server_condition =${if pam{$1:${sg{$2}{:}{::}}} {yes}{no}} .else .ifdef FILE_PASS server_condition =${lookup {$1} lsearch{FILE_PASS}\ {${if crypteq{$2}\ {${extract{1}{:}{${value}}}}\ {yes}{no}}}\ {no}} .else server_condition =no .endif .endif server_set_id =$1 cram: driver =cram_md5 public_name =CRAM-MD5 server_secret =${if exists{FILE_CRAM_MD5}\ {${lookup {$1} lsearch{FILE_CRAM_MD5}}}\ fail} server_set_id =$1