# $Id: exim.conf 228 2005-07-27 17:06:36Z root $
######################################################################
#                  Runtime configuration file for Exim               #
######################################################################

disable_ipv6 = true
keep_environment =
add_environment = PATH=/usr/sbin:/usr/bin:/sbin:/bin
smtp_enforce_sync = false
bounce_message_file = /etc/exim4/bounce_message_text

smtp_accept_max = 50
smtp_accept_max_per_host = 10
smtp_accept_queue_per_connection = 50

.include /etc/exim4/exim_local.conf

tls_advertise_hosts = *
tls_certificate = ${if exists{/etc/ssl/letsencrypt/${sg{${tls_sni}}{^smtp\.}{mail.}}.pem}{/etc/ssl/letsencrypt/${sg{${tls_sni}}{^smtp\.}{mail.}}.pem}}

tls_on_connect_ports = 465
daemon_smtp_ports = 25 : 465 : 587

# This is a default configuration file which will operate correctly in
# uncomplicated installations. Please see the manual for a complete list
# of all the runtime configuration options that can be included in a
# configuration file. There are many more than are mentioned here. The
# manual is in the file doc/spec.txt in the Exim distribution as a plain
# ASCII file. Other formats (PostScript, Texinfo, HTML, PDF) are available
# from the Exim ftp sites. The manual is also online at the Exim web sites.


# This file is divided into several parts, all but the first of which are
# headed by a line starting with the word "begin". Only those parts that
# are required need to be present. Blank lines, and lines starting with #
# are ignored.


########### IMPORTANT ########## IMPORTANT ########### IMPORTANT ###########
#                                                                          #
# Whenever you change Exim's configuration file, you *must* remember to    #
# HUP the Exim daemon, because it will not pick up the new configuration   #
# until you do. However, any other Exim processes that are started, for    #
# example, a process started by an MUA in order to send a message, will    #
# see the new configuration as soon as it is in place.                     #
#                                                                          #
# You do not need to HUP the daemon for changes in auxiliary files that    #
# are referenced from this file. They are read every time they are used.   #
#                                                                          #
# It is usually a good idea to test a new configuration for syntactic      #
# correctness before installing it (for example, by running the command    #
# "exim -C /config/file.new -bV").                                         #
#                                                                          #
########### IMPORTANT ########## IMPORTANT ########### IMPORTANT ###########



######################################################################
#                    MAIN CONFIGURATION SETTINGS                     #
######################################################################

# Specify your host's canonical name here. This should normally be the fully
# qualified "official" name of your host. If this option is not set, the
# uname() function is called to obtain the name. In many cases this does
# the right thing and you need not set anything explicitly.

queue_only_load = 3
log_selector = +all

# The next three settings create two lists of domains and one list of hosts.
# These lists are referred to later in this configuration using the syntax
# +local_domains, +relay_to_domains, and +relay_from_hosts, respectively. They
# are all colon-separated lists:

domainlist local_domains = ${lookup mysql{SELECT domain FROM vm_domains WHERE domain='${quote_mysql:$domain}' AND status = '1'}}
domainlist relay_to_domains = /etc/exim4/relay_domains
hostlist   relay_from_hosts = 127.0.0.1
hostlist   skip_greylisting_hosts = /etc/exim4/skip_greylisting_hosts

# overide default sender checks
untrusted_set_sender = *
local_from_check = false
local_sender_retain = true

# trusted users, needed by spamcheck
trusted_users = mail

# local whitelist check macro:
WHITELISTED = ${lookup mysql{\
              SELECT prefid FROM sa_userpref \
              WHERE (username = '${quote_mysql:$local_part@$domain}' \
              OR username = '\$GLOBAL' \
              OR username = CONCAT('%','${quote_mysql:$domain}')) \
              AND preference = 'whitelist_from' \
              AND (value = '${quote_mysql:$sender_address}' \
              OR value = CONCAT('\*@','${quote_mysql:$sender_address_domain}')) \
              }{true}{false}}

# greylist options
# these need to be valid as xxx in mysql's DATE_ADD(..,INTERVAL xxx)
# not valid, for example, are plurals: "2 HOUR" instead of "2 HOURS"
GREYLIST_INITIAL_DELAY = 4 MINUTE
GREYLIST_INITIAL_LIFETIME = 12 HOUR
GREYLIST_WHITE_LIFETIME = 36 DAY
GREYLIST_BOUNCE_LIFETIME = 0 HOUR

# you can change the table names
GREYLIST_TABLE=vm_greylisting
GREYLIST_RESENDERS_TABLE=vm_greylisting_resenders

# database macros
GREYLIST_TEST = SELECT CASE \
   WHEN now() > block_expires THEN "accepted" \
   ELSE "deferred" \
 END AS result, id \
 FROM GREYLIST_TABLE \
 WHERE (now() < record_expires) \
   AND (sender      = '${quote_mysql:$sender_address}' \
        OR (type='MANUAL' \
            AND (    sender IS NULL \
                  OR sender = '${quote_mysql:*@$sender_address_domain}' \
                ) \
           ) \
       ) \
   AND (recipient   = '${quote_mysql:$local_part@$domain}' \
        OR (type = 'MANUAL' \
            AND (    recipient IS NULL \
                  OR recipient = '${quote_mysql:$local_part@*}' \
                  OR recipient = '${quote_mysql:*@$domain}' \
                ) \
           ) \
       ) \
    AND (relay_hostname = '${quote_mysql:$acl_m_sender}' \
      OR (type='MANUAL' \
        AND relay_hostname IS NULL) \
        ) \
 ORDER BY result DESC LIMIT 1

GREYLIST_ADD = INSERT INTO GREYLIST_TABLE \
  (relay_hostname, relay_ip, sender, recipient, block_expires, \
   record_expires, create_time, type) \
  VALUES ( '${quote_mysql:$acl_m_sender}', \
  '${quote_mysql:$sender_host_address}', \
  '${quote_mysql:$sender_address}', \
  '${quote_mysql:$local_part@$domain}', \
  DATE_ADD(now(), INTERVAL GREYLIST_INITIAL_DELAY), \
  DATE_ADD(now(), INTERVAL GREYLIST_INITIAL_LIFETIME), \
  now(), \
  'AUTO' \
)

GREYLIST_DEFER_HIT = UPDATE GREYLIST_TABLE \
                     SET blockcount=blockcount+1 \
                     WHERE id = $acl_m9

GREYLIST_OK_COUNT = UPDATE GREYLIST_TABLE \
                    SET passcount=passcount+1 \
                    WHERE id = $acl_m9

GREYLIST_OK_NEWTIME = UPDATE GREYLIST_TABLE \
                      SET record_expires = DATE_ADD(now(), INTERVAL GREYLIST_WHITE_LIFETIME) \
                      WHERE id = $acl_m9 AND type='AUTO'

GREYLIST_OK_BOUNCE = UPDATE GREYLIST_TABLE \
                     SET record_expires = DATE_ADD(now(), INTERVAL GREYLIST_BOUNCE_LIFETIME) \
                     WHERE id = $acl_m9 AND type='AUTO'

GREYLIST_RESENDERS_UPDATE = REPLACE INTO GREYLIST_RESENDERS_TABLE SET hostname = '${quote_mysql:$acl_m_sender}'

# No deliveries will ever be run under the uids of these users (a colon-
# separated list). An attempt to do so causes a panic error to be logged, and
# the delivery to be deferred. This is a paranoic safety catch. Note that the
# default setting means you cannot deliver mail addressed to root as if it
# were a normal user. This isn't usually a problem, as most sites have an alias
# for root that redirects such mail to a human administrator.

never_users = root


# The setting below causes Exim to do a reverse DNS lookup on all incoming
# IP calls, in order to get the true host name. If you feel this is too
# expensive, you can specify the networks for which a lookup is done, or
# remove the setting entirely.

host_lookup = *


# The settings below, which are actually the same as the defaults in the
# code, cause Exim to make RFC 1413 (ident) callbacks for all incoming SMTP
# calls. You can limit the hosts to which these calls are made, and/or change
# the timeout that is used. If you set the timeout to zero, all RFC 1413 calls
# are disabled. RFC 1413 calls are cheap and can provide useful information
# for tracing problem messages, but some hosts and firewalls have problems
# with them. This can result in a timeout instead of an immediate refused
# connection, leading to delays on starting up an SMTP session.

rfc1413_hosts = *
rfc1413_query_timeout = 0s

# This option unfreezes frozen bounce messages after two days, tries
# once more to deliver them, and ignores any delivery failures.

ignore_bounce_errors_after = 0s

# This option cancels (removes) frozen messages that are older than a day.

timeout_frozen_after = 1d

# Treat DNS failures (SERVFAIL) as lookup failures.
# This is so that we can later reject sender addresses
# within non-existing domains, or domains for which no
# nameserver exists.
dns_again_means_nonexist = !+local_domains

# Enable HELO verification in ACLs for all hosts
helo_try_verify_hosts = *

# Advertise ESMTP "PIPELINING" to all hosts
pipelining_advertise_hosts = *

acl_smtp_connect = acl_connect
acl_smtp_helo    = acl_helo
acl_smtp_mail    = acl_mail_from
acl_smtp_dkim    = acl_check_dkim
acl_smtp_rcpt    = acl_rcpt_to
acl_smtp_data    = acl_data

# set the av scanner to clamav
##av_scanner = clamd:/run/clamav/clamd.ctl

begin acl

# this acl returns either deny or accept
# since we use it inside a defer with acl = greylist_acl,
# accepting here makes the condition TRUE thus deferring,
# denying here makes the condition FALSE thus not deferring
#
greylist_acl:
  # For regular deliveries, check greylist.

  # check greylist tuple, returning "accepted", "deferred" or "unknown"
  # in acl_m8, and the record id in acl_m9

  warn set acl_m8 = ${lookup mysql{GREYLIST_TEST}{$value}{result=unknown}}
       # here acl_m8 = "result=x id=y"

       set acl_m9 = ${extract{id}{$acl_m8}{$value}{-1}}
       # now acl_m9 contains the record id (or -1)

       set acl_m8 = ${extract{result}{$acl_m8}{$value}{unknown}}
       # now acl_m8 contains unknown/deferred/accepted

  # check if we know a certain triple, add and defer message if not
  accept
       # if above check returned unknown (no record yet)
       condition = ${if eq{$acl_m8}{unknown}{1}}
       # then also add a record
       condition = ${lookup mysql{GREYLIST_ADD}{yes}{no}}

  # check if the triple is still blocked
  accept
       # if above check returned deferred then defer
       condition = ${if eq{$acl_m8}{deferred}{1}}
       # and note it down
       condition = ${lookup mysql{GREYLIST_DEFER_HIT}{yes}{yes}}

  # use a warn verb to count records that were hit
  warn condition = ${lookup mysql{GREYLIST_OK_COUNT}}

  # use a warn verb to set a new expire time on automatic records,
  # but only if the mail was not a bounce, otherwise set to now().
  warn !senders = : postmaster@*
       condition = ${lookup mysql{GREYLIST_OK_NEWTIME}}
  warn senders = : postmaster@*
       condition = ${lookup mysql{GREYLIST_OK_BOUNCE}}

  deny
    add_header  = :at_start_rfc:X-DNS-Greylist: mail from $sender_address to $local_part@$domain accepted by greylisting
    condition = ${lookup mysql{GREYLIST_RESENDERS_UPDATE}}

# This access control list is used at the start of an incoming
# connection.  The tests are run in order until the connection
# is either accepted or denied.
#
acl_connect:

  # In this pass, we do not perform any checks here.
  accept

# This access control list is used for the HELO or EHLO command in
# an incoming SMTP transaction.  The tests are run in order until the
# greeting is either accepted or denied.
#
acl_helo:

  # Early rejection of brute-force bots under the name 'ylmf-pc'
  deny
    condition = ${if eq{$sender_helo_name}{ylmf-pc}{yes}{no}}

  # In this pass, we do not perform any checks here.
  accept

# This access control list is used for the MAIL FROM: command in an
# incoming SMTP transaction.  The tests are run in order until the
# sender address is either accepted or denied.
#
acl_mail_from:

  # Accept the command.
  accept

# This access control list is used for every RCPT command in an
# incoming SMTP message.  The tests are run in order until the
# recipient address is either accepted or denied.
#
acl_check_dkim:

  ######################################################################
  # DomainKeys
  ######################################################################

  # DKIM fail
  accept
    dkim_status = fail
    logwrite = DKIM test failed: $dkim_verify_reason
    add_header = :at_start_rfc:X-DKIM-Status: fail: $dkim_verify_reason
    set acl_m_junk = yes

  # DKIM invalid
  accept
    dkim_status = invalid
    logwrite = DKIM test invalid: $dkim_verify_reason
    add_header = :at_start_rfc:X-DKIM-Status: invalid: $dkim_verify_reason
    set acl_m_junk = yes

  # DKIM none
  accept
    dkim_status = none
    logwrite = DKIM test none
    add_header = :at_start_rfc:X-DKIM-Status: none

  # DKIM pass
  accept
    dkim_status = pass
    logwrite = DKIM test passed
    add_header = :at_start_rfc:X-DKIM-Status: passed: (address=$sender_address domain=$dkim_cur_signer), signature is good.

  # Accept the message.
  accept

acl_rcpt_to:

  # Accept mail received over local SMTP (i.e. not over TCP/IP).
  # We do this by testing for an empty sending host field.
  # Also accept mails received from hosts for which we relay mail.
  #
  # Recipient verification is omitted here, because in many
  # cases the clients are dumb MUAs that don't cope well with
  # SMTP error responses.
  #
  accept
    hosts       = : +relay_from_hosts

  # Get rate limit for user and log current rate.
  # Hourly rate limit is extracted from db, multiplied by 10 to get daily rate limit.
  # The idea being that the hourly rate limit should be a maximum, peak rate, not a sustained rate.
  # The default ratelimit of 100000 is meant to be so high as to never be reached (no limit).
  # A second default of 10 is set for lookup failures. This shouldn't happen unless there is a misconfiguration somewhere or a database issue.
  # The primary purpose of rate limiting is fighting spam, either by an abusive user or a
  # compromised account, not to restrict legitimate users. Set your defaults & limits accordignly.
  warn
    authenticated = *
    set acl_m_ratelimit_hourly = ${lookup mysql{SELECT IFNULL(vm_mboxes.ratelimit, 100000) FROM vm_mboxes WHERE vm_mboxes.mbox="$sender_address_local_part" AND vm_mboxes.domain='$sender_address_domain'}{$value}{10}}
    set acl_m_ratelimit_daily = ${eval: (10 * $acl_m_ratelimit_hourly) }
    ratelimit = 0 / 1h / per_mail / strict / $authenticated_id
    log_message = Sender rate is $sender_rate/$sender_rate_period for $authenticated_id

  # enforce hourly rate limit
  deny
    authenticated = *
    ratelimit = $acl_m_ratelimit_hourly / 1h / per_mail / strict / $authenticated_id
    message = Rate Limit of $acl_m_ratelimit_hourly per hour exceeded. Try again later.
    log_message = $authenticated_id exceeded rate limit of $acl_m_ratelimit_hourly per hour

  # enforce daily rate limit
  deny
    authenticated = *
    ratelimit = $acl_m_ratelimit_daily / 1d / per_mail / strict / $authenticated_id
    message = Rate Limit of $acl_m_ratelimit_daily per day exceeded. Try again later.
    log_message = $authenticated_id exceeded rate limit of $acl_m_ratelimit_daily per day

  # authenticated user did not exceed rate limits, accept message now
  accept
    authenticated = *

  ######################################################################
  # Hello checks
  ######################################################################

  # If the remote host greets with an IP address, then reject the mail.
  deny
    message     = Message was delivered by ratware
    log_message = remote host used IP address in HELO/EHLO greeting
    condition   = ${if isip {$sender_helo_name}{true}{false}}

  # Likewise if the peer greets with one of our own names
  deny
    message     = Message was delivered by ratware
    log_message = remote host used our name in HELO/EHLO greeting.
    condition   = ${if match_domain{$sender_helo_name}\
                       {$primary_hostname:+local_domains}\
                       {true}{false}}

  deny
    message     = Message was delivered by ratware
    log_message = remote host did not present HELO/EHLO greeting.
    condition   = ${if def:sender_helo_name {false}{true}}

  # If HELO verification fails, we add a X-HELO-Warning: header in the message.
  warn
    !verify     = helo
    message     = X-HELO-Warning: Remote host $sender_host_address \
                  ${if def:sender_host_name {($sender_host_name) }}\
                  incorrectly presented itself as $sender_helo_name
    log_message = remote host presented unverifiable HELO/EHLO greeting.

  # if "!verify     = helo" & $send_host_name = '' reject???

  ######################################################################
  # Sender Address Checks
  ######################################################################

  # If we cannot verify the sender address, deny the message.
  #
  # You may choose to remove the "callout" option.  In particular,
  # if you are sending outgoing mail through a smarthost, it will not
  # give any useful information.
  #
  # Details regarding the failed callout verification attempt are
  # included in the 550 response; to omit these, change
  # "sender/callout" to "sender/callout,no_details".
  #
#  deny
#    message     = <$sender_address> does not appear to be a \
#                  valid sender address.
#    !verify     = sender/callout

  ######################################################################
  # Recipent Address Checks
  ######################################################################

  # SRS configs taken from: https://ente.limmat.ch/kb/exim/exim_v4_srs.html
## SRS checks are temporarily disabled. srsd is currently broken on Ubuntu 22.04.
## These could be updated to use "run{/usr/bin/srs" instead of readsocket.
##  # Ensure only valid SRS prefixed bounce message get accepted
##  deny
##    senders = :
##    domains = +local_domains
##    local_parts = ${if match {$local_part} {(?i)\N^SRS[01][=+-]\N} {$local_part}}
##    control = caseful_local_part
##    condition = ${if match{${readsocket{/run/srsd/srsd.sock}{REVERSE $local_part@$domain}{5s}{\n}}}{^ERROR: .* Invalid hash at .*}}
##    message = Invalid reverse path (SRS check failed on $local_part@$domain).
##
##  warn
##    senders = :
##    domains = +local_domains
##    local_parts = ${if match {$local_part} {\N^srs[01][=+-]\N} {$local_part}}
##    control = caseful_local_part
##    condition = ${if match{${readsocket{/run/srsd/srsd.sock}{REVERSE $local_part@$domain}{5s}{ }}}{^SRS: Case insensitive hash match detected. Someone smashed case in the local-part. .*}}
##    log_message = SRS hash smashed on the way for $local_part@$domain by case insensitive MTA.
##
##  # this is for debugging only. can be safely removed any time
##  warn
##    senders = :
##    domains = +local_domains
##    local_parts = ${if match {$local_part} {(?i)\N^SRS[01][=+-]\N} {$local_part}}
##    control = caseful_local_part
##    condition = ${if !match{${readsocket{/run/srsd/srsd.sock}{REVERSE $local_part@$domain}{5s}{\n}}}{^ERROR: .* Invalid hash at .*}}
##    log_message = Incoming SRS bounce to $local_part@$domain

  # Deny if the local part contains @ or % or / or | or !. These are
  # rarely found in genuine local parts, but are often tried by people
  # looking to circumvent relaying restrictions.
  #
  # Also deny if the local part starts with a dot. Empty components
  # aren't strictly legal in RFC 2822, but Exim allows them because
  # this is common.  However, actually starting with a dot may cause
  # trouble if the local part is used as a file name (e.g. for a
  # mailing list).
  #
  deny
    local_parts = ^.*[@%!/|] : ^\\.

  # Drop the connection if the envelope sender is empty, but there is
  # more than one recipient address.  Legitimate DSNs are never sent
  # to more than one address.
  #
  drop
    message      = Legitimate bounces are never sent to more than one recipient.
    log_message  = Legitimate bounces are never sent to more than one recipient (count: $recipients_count).
    senders      = : postmaster@*
    condition    = $recipients_count

  # Reject the recipient address if it is not in a domain for
  # which we are handling mail.
  #
  deny
    message     = relay not permitted
    !domains    = +local_domains : +relay_to_domains

  # Reject the recipient if it is not a valid mailbox.
  # If the mailbox is not on our system (e.g. if we are a
  # backup MX for the recipient domain), then perform a
  # callout verification; but if the destination server is
  # not responding, accept the recipient anyway.
  #
  deny
    message = unknown user
    domains = +local_domains
    !domains = +relay_to_domains
    !verify = recipient/callout=no_cache,10s,defer_ok

  # skip any further checks if the address is whitelisted
  accept
    condition   = WHITELISTED
    logwrite    = From: $sender_address To: $local_part@$domain is whitelisted in sa_userpref
    add_header  = :at_start_rfc:X-Whitelist-Flag: YES
    set acl_m_whitelist = yes

  ######################################################################
  # DNS checks
  ######################################################################
  #
  # The results of these checks are cached, so multiple recipients
  # does not translate into multiple DNS lookups.
  #

  # check whitelists
  # a match will:
  #     add X-DNS-Whitelist header
  #     skip the rest of the checks (DNS blacklist/greylist, SPF)

## as of Aug 2019 swl.spamhaus.org appears to be offline pending redesign
## list.dnswl.org does not work with large nameresolvers (over 100k queries / 24 hours)
##  accept
##    domains     = +local_domains
##    dnslists    = swl.spamhaus.org : list.dnswl.org&0.0.0.2
##    logwrite    = $sender_host_address is whitelisted in $dnslist_domain ${if def:dnslist_text {($dnslist_text)}}, adding X-DNS-Whitelist header
##    add_header  = :at_start_rfc:X-DNS-Whitelist: $sender_host_address is listed in $dnslist_domain ${if def:dnslist_text {($dnslist_text)}}

  # Check SPF. Failures are marked as Junk and accepted - this skips further checks (e.g. DNSBL) and filters messages to the Junk folder
  accept
    spf = fail:softfail
    set acl_m_junk = yes
    add_header = :at_start_rfc:$spf_received

  warn
    spf = pass:neutral:permerror
    add_header = :at_start_rfc:$spf_received

  # check DNSBL(s) and if found add header for filtering to Junk
  accept
    !condition = ${if eq {$header_X-Whitelist-Flag:}{YES}}
    dnslists   = zen.spamhaus.org
    logwrite   = Warning: $sender_host_address is listed in DNSBL $dnslist_domain ${if def:dnslist_text {($dnslist_text)}}
    add_header = :at_start_rfc:X-DNS-Blacklist: $sender_host_address is listed in $dnslist_domain ${if def:dnslist_text {($dnslist_text)}}
    set acl_m_junk = yes

  # greylisting
  # if $sender_host_name is set use that. run command strips of leftmost subdomain if this is a third or higher level domain
  warn
    condition = ${if def:sender_host_name}
    set acl_m_sender = ${run{/bin/bash /etc/exim4/return-resender.sh $sender_host_name}{$value}{$sender_host_name}}

  # if $sender_host_name is not set use $sender_helo_name. if sender_helo_name not set email was already rejected (deny) earlier in this acl
  warn
    condition = ${if !def:sender_host_name}
    set acl_m_sender = $sender_helo_name

  # bypass greylisting if sender listed in skip_greylisting_hosts
  accept
    hosts = +skip_greylisting_hosts
    log_message = skipping greylisting due to match in skip_greylisting_hosts

  # bypass greylisting if the sending host is a known resender
  accept
    condition = ${lookup mysql{SELECT id FROM GREYLIST_RESENDERS_TABLE WHERE hostname = '${quote_mysql:$acl_m_sender}'}{yes}{no}}
    condition = ${lookup mysql{UPDATE GREYLIST_RESENDERS_TABLE SET count=count+1, timestamp = NOW() WHERE hostname = '${quote_mysql:$acl_m_sender}'}{yes}{yes}}
    add_header  = :at_start_rfc:X-DNS-Greylist: known resender
    logwrite = skipping greylisting for $acl_m_sender due to match in GREYLIST_RESENDERS_TABLE

  # run greylisting acl
  defer
    !senders = : postmaster@*
    !hosts   = +skip_greylisting_hosts
    acl      = greylist_acl
    message  = greylisted - try again later

  # Otherwise, the recipient address is OK.
  #
  accept

# This access control list is used for message data received via
# SMTP.  The tests are run in order until the recipient address
# is either accepted or denied.
#
acl_data:

  # Add Message-ID if missing in messages received from our own hosts.
  warn
    condition   = ${if !def:h_Message-ID: {1}}
    hosts       = : +relay_from_hosts
    message     = Message-ID: <E$message_id@$primary_hostname>

  # add domain keys status header
  #
  #warn
  #  message = DomainKey-Status: $dk_status
  #  !condition = ${if eq{$dk_status}{}{1}{0}}

  # Accept mail received over local SMTP (i.e. not over TCP/IP).
  # We do this by testing for an empty sending host field.
  # Also accept mails received from hosts for which we relay mail.
  #
  accept
    hosts       = : +relay_from_hosts

  # Accept if the message arrived over an authenticated connection, from
  # any host.
  #
  accept
    authenticated = *

  # Enforce a message-size limit
  #
  #deny
  #  message     = Message size $message_size is larger than limit of \
  #                MESSAGE_SIZE_LIMIT
  #  condition   = ${if >{$message_size}{MESSAGE_SIZE_LIMIT}{true}{false}}

  # Check if the address list header is syntactically correct.
  # Note that some specialized MTAs, such as certain mailing list
  # servers, do not automatically generate a Message-ID for bounces.
  # Thus, we add the check for a non-empty sender.
  # (email feedback reports from aol fail this check)
  accept
    message     = X-RFC2822-Error: Your message does not conform to RFC2822 standard
    log_message = message header failed RFC2822 syntax check
    !hosts      = +relay_from_hosts
    !senders    = : postmaster@*
    !verify     = header_syntax
    add_header  = :at_start_rfc:X-RFC2822-Error: Your message does not conform to RFC2822 standard
    set acl_m_junk = yes

  # Warn unless there is a verifiable sender address in at least
  # one of the "Sender:", "Reply-To:", or "From:" header lines.
  warn
    !verify     = header_sender
    log_message = No valid sender in message header
    add_header  = :at_start_rfc:X-Sender-Verify-Failed: No valid sender in message header

  # Deny if the message contains a virus. Before enabling this check, you
  # must install a virus scanner and set the av_scanner option above.
  #
  #accept
  #  malware     = */defer_ok
  #  log_message = This message contains a virus ($malware_name).
  #  add_header  = :at_start_rfc:X-Virus-Warning: This message contains a virus ($malware_name).
  #  set acl_m_junk = yes

  # Accept the message.
  #
  accept


######################################################################
#                      ROUTERS CONFIGURATION                         #
#               Specifies how addresses are handled                  #
######################################################################
#     THE ORDER IN WHICH THE ROUTERS ARE DEFINED IS IMPORTANT!       #
# An address is passed to each router in turn until it is accepted.  #
######################################################################

begin routers

autowhitelist_filter:
  driver = redirect
  domains = ! +local_domains
  ignore_target_hosts = 0.0.0.0 : 127.0.0.0/8
  condition = ${lookup mysql{SELECT vm_mboxes.id FROM vm_mboxes WHERE vm_mboxes.mbox="${quote_mysql:$sender_address_local_part}" AND vm_mboxes.domain="${quote_mysql:$sender_address_domain}" }}
  check_local_user = false
  user = Debian-exim
  file = /etc/exim4/autowhitelist.filter
  no_verify
  unseen
  allow_filter = true

srs_bounce:
  senders = :
  driver = redirect
  domains = +local_domains
  allow_fail
  allow_defer
  local_part_prefix = srs0+ : srs0- : srs0= : srs1+ : srs1- : srs1=
  caseful_local_part
  address_data = ${run{/usr/bin/srs --secretfile=/etc/exim4/srsd.secret --hashlength=24 --reverse --address=$local_part_prefix$local_part@$domain}{$value}{:defer: SRS failure}}
   ## srsd is broken on ubuntu 22.04. using above "run" command instead
#  address_data = ${readsocket{/run/srsd/srsd.sock}{REVERSE $local_part_prefix$local_part@$domain}{5s}{ }{:defer: SRS daemon failure}}
  data = ${sg {$address_data} {^SRS: Case insensitive hash match detected. Someone smashed case in the local-part\. .* ([^ ]+)@([^ ]+)\$} {\N$1@$2\N} }
  headers_add = X-SRS: Decoded valid SRS return address to ${quote_local_part:${local_part:$address_data}}@${domain:$address_data} by $primary_hostname

srs_forward:
  driver = redirect
  senders = ! : ! *@+local_domains
  domains = ! +local_domains : ! +relay_to_domains
  condition = ${lookup mysql{SELECT vm_domains.id FROM vm_domains WHERE vm_domains.domain='${quote_mysql:$original_domain}' AND vm_domains.status = '1'}}
  address_data = ${run{/usr/bin/srs --secretfile=/etc/exim4/srsd.secret --hashlength=24 --forward --address=$sender_address_local_part@$sender_address_domain --alias=$original_domain}{$value}{:defer: SRS failure}}
  ## srsd is broken on ubuntu 22.04. using above "run" command instead
#  address_data = ${readsocket{/run/srsd/srsd.sock}\
#                {FORWARD $sender_address_local_part@$sender_address_domain $original_domain\n}\
#                                        {5s}{\n}{:defer: SRS daemon failure}}
  errors_to = ${quote_local_part:${local_part:$address_data}}@${domain:$address_data}
  data = ${quote_local_part:$local_part}@$domain
  headers_add = X-SRS-Forward: from $sender_address to $original_local_part@$original_domain forwarded to $local_part@$domain by $primary_hostname
  repeat_use = false
  allow_defer
  no_verify

# This router routes addresses that are not in local domains by doing a DNS
# lookup on the domain name. Any domain that resolves to 0.0.0.0 or to a
# loopback interface address (127.0.0.0/8) is treated as if it had no DNS
# entry. Note that 0.0.0.0 is the same as 0.0.0.0/32, which is commonly treated
# as the local host inside the network stack. It is not 0.0.0.0/0, the default
# route. If the DNS lookup fails, no further routers are tried because of
# the no_more setting, and consequently the address is unrouteable.

dnslookup:
  driver = dnslookup
  self = pass
  transport = remote_smtp
  ignore_target_hosts = 0.0.0.0 : 127.0.0.0/8
  no_more

# The remaining routers handle addresses in the local domain(s).

junk_filter:
  driver = accept
  domains = +local_domains
  condition = ${if eq{$acl_m_junk}{yes}}
  condition = ${if !eq{$acl_m_whitelist}{yes}}
  condition = ${if !eq {$received_protocol}{spam-scanned}}
  local_part_suffix = +*
  local_part_suffix_optional = true
  local_parts = ${lookup mysql{SELECT vm_mboxes.mbox FROM vm_mboxes WHERE vm_mboxes.mbox='${quote_mysql:$local_part}' AND vm_mboxes.domain='${quote_mysql:$domain}' AND vm_mboxes.status > '0' AND vm_mboxes.filter > '0'}}
  headers_add = X-Junk-Flag: YES
  transport = junk_delivery

spam_filter:
  driver = accept
  domains = +local_domains
  condition = ${if eq {$received_protocol}{spam-scanned}}
  condition = ${if eq {$header_X-Spam-Flag:}{YES}}
##  condition = ${if !eq {$header_X-Whitelist-Flag:}{YES}}
  local_part_suffix = +*
  local_part_suffix_optional = true
  local_parts = ${lookup mysql{SELECT vm_mboxes.mbox FROM vm_mboxes WHERE vm_mboxes.mbox='${quote_mysql:$local_part}' AND vm_mboxes.domain='${quote_mysql:$domain}' AND vm_mboxes.status > '0' AND vm_mboxes.filter = '2'}}
  transport = junk_delivery

mailman3_router:
  driver = accept
  domains = +local_domains
  condition = ${if !eq {$received_protocol}{spam-scanned}}
  require_files = /var/lib/mailman3/lists/${local_part}.${domain}
  local_part_suffix_optional
  local_part_suffix = \
     -bounces   : -bounces+* : \
     -confirm   : -confirm+* : \
     -join      : -leave     : \
     -owner     : -request   : \
     -subscribe : -unsubscribe
  transport = mailman3_transport

virtual_alias:
  driver = redirect
  domains = +local_domains
  local_part_suffix = +*
  local_part_suffix_optional = true
  condition = ${if !eq {$received_protocol}{spam-scanned}}
  data = ${lookup mysql{SELECT CONCAT(vm_aliases.mbox,'@','${quote_mysql:$domain}') FROM vm_mboxes, vm_aliases WHERE vm_mboxes.mbox=vm_aliases.mbox AND vm_mboxes.domain='${quote_mysql:$domain}' AND vm_mboxes.status > '0' AND vm_aliases.alias='${quote_mysql:$local_part}' AND vm_aliases.domain='${quote_mysql:$domain}'}}

virtual_vacation:
  driver = accept
  domains = +local_domains
  # currently configured to *not* autorespond to + aliases
  #local_part_suffix = +*
  #local_part_suffix_optional = true
  local_parts = ${lookup mysql{SELECT vm_mboxes.mbox FROM vm_mboxes, vm_autoresponders WHERE vm_mboxes.mbox='${quote_mysql:$local_part}' AND vm_mboxes.domain='${quote_mysql:$domain}' AND vm_mboxes.status > '0' AND vm_autoresponders.mbox='${quote_mysql:$local_part}' AND vm_autoresponders.domain='${quote_mysql:$domain}' AND vm_autoresponders.mode='Vacation' AND vm_autoresponders.status='1'}}
  # add options for start & end date fields to above query
  # do not reply to errors or lists or spam-scanned messages, require vacation message in db
  condition = ${if !match {$h_precedence:} {(?i)junk|bulk|list}}
  condition = ${if !eq{$acl_m_junk}{yes}}
  condition = ${if !eq {$received_protocol}{spam-scanned}}
  condition = ${if !eq {$sender_address} {}}
  no_expn
  # do not reply to errors and bounces or lists
  senders = " ! ^.*-request@.*:\
              ! ^owner-.*@.*:\
              ! ^postmaster@.*:\
              ! ^listmaster@.*:\
              ! ^mailer-daemon@.*\
              ! ^root@.*"
  transport = vacation_transport
  unseen
  no_verify

virtual_autoresponder:
  driver = accept
  domains = +local_domains
  # currently configured to *not* autorespond to + aliases
  #local_part_suffix = +*
  #local_part_suffix_optional = true
  local_parts = ${lookup mysql{SELECT vm_mboxes.mbox FROM vm_mboxes, vm_autoresponders WHERE vm_mboxes.mbox='${quote_mysql:$local_part}' AND vm_mboxes.domain='${quote_mysql:$domain}' AND vm_mboxes.status > '0' AND vm_autoresponders.mbox='${quote_mysql:$local_part}' AND vm_autoresponders.domain='${quote_mysql:$domain}' AND vm_autoresponders.mode='Autoresponder' AND vm_autoresponders.status='1'}}
  # add options for start & end date fields to above query
  # do not reply to errors or lists or spam-scanned messages, require autoresponder message in db
  condition = ${if !match {$h_precedence:} {(?i)junk|bulk|list}}
  condition = ${if !eq{$acl_m_junk}{yes}}
  condition = ${if !eq {$received_protocol}{spam-scanned}}
  condition = ${if !eq {$sender_address} {}}
  no_expn
  # do not reply to errors and bounces or lists
  senders = " ! ^.*-request@.*:\
              ! ^owner-.*@.*:\
              ! ^postmaster@.*:\
              ! ^listmaster@.*:\
              ! ^mailer-daemon@.*\
              ! ^root@.*"
  transport = autoresponder_transport
  unseen
  no_verify

virtual_forward_and_drop:
  driver = redirect
  domains = +local_domains
  condition = ${if !eq {$received_protocol}{spam-scanned}}
  local_part_suffix = +*
  local_part_suffix_optional = true
  data = ${lookup mysql{SELECT vm_forwards.forward_to FROM vm_mboxes, vm_forwards WHERE vm_mboxes.mbox='${quote_mysql:$local_part}' AND vm_mboxes.domain='${quote_mysql:$domain}' AND vm_mboxes.status > '0' AND vm_forwards.mbox='${quote_mysql:$local_part}' AND vm_forwards.domain='${quote_mysql:$domain}' AND vm_forwards.save_local='0'}}

virtual_forward_and_keep:
  driver = redirect
  domains = +local_domains
  condition = ${if !eq {$received_protocol}{spam-scanned}}
  local_part_suffix = +*
  local_part_suffix_optional = true
  data = ${lookup mysql{SELECT CONCAT('${quote_mysql:$local_part}@${quote_mysql:$domain}\n', vm_forwards.forward_to) FROM vm_mboxes, vm_forwards WHERE vm_mboxes.mbox='${quote_mysql:$local_part}' AND vm_mboxes.domain='${quote_mysql:$domain}' AND vm_mboxes.status > '0' AND vm_forwards.mbox='${quote_mysql:$local_part}' AND vm_forwards.domain='${quote_mysql:$domain}' AND vm_forwards.save_local='1'}}

spamcheck_router:
  driver = accept
  # uncomment next line to bypass spamcheck when testing address routing with "exim -bt user@example.com"
  #address_test = false
  domains = +local_domains
  condition = ${if !eq {$received_protocol}{spam-scanned}}
  condition = ${if !eq {$sender_address_domain}{$domain}}
  condition = ${if !eq{$acl_m_whitelist}{yes}}
  condition = ${if < {$message_size}{512k}}
  local_part_suffix = +*
  local_part_suffix_optional = true
  local_parts = ${lookup mysql{SELECT vm_mboxes.mbox FROM vm_mboxes WHERE vm_mboxes.mbox='${quote_mysql:$local_part}' AND vm_mboxes.domain='${quote_mysql:$domain}' AND vm_mboxes.status > '0' AND vm_mboxes.filter = '2'}}
  headers_remove = X-Spam-Checker-Version:X-Spam-Flag:X-Spam-Level:X-Spam-Status:X-Spam-Score:X-Spam-Report
  transport = spamcheck

# add mailman3 spamcheck?

user_filter:
  driver = redirect
  domains = +local_domains
  local_part_suffix = +*
  local_part_suffix_optional = true
  data = ${lookup mysql{SELECT vm_filters.filter FROM vm_mboxes, vm_filters WHERE vm_mboxes.mbox='${quote_mysql:$local_part}' AND vm_mboxes.domain='${quote_mysql:$domain}' AND vm_mboxes.status > '0' AND vm_filters.mbox='${quote_mysql:$local_part}' AND vm_filters.domain='${quote_mysql:$domain}'}}
  user = vmail
  no_verify
  no_expn
  check_ancestor
  allow_filter
  file_transport = address_file
  pipe_transport = address_pipe
  reply_transport = address_reply
  directory_transport = user_filter_maildir_delivery
  allow_fail

lmtp_localuser:
  driver = accept
  domains = +local_domains
  local_part_suffix = +*
  local_part_suffix_optional = true
  condition = ${lookup mysql{SELECT vm_mboxes.id FROM vm_mboxes WHERE vm_mboxes.mbox='${quote_mysql:$local_part}' AND vm_mboxes.domain='${quote_mysql:$domain}' AND vm_mboxes.status > '0'}}
  transport = dovecot_lmtp
  cannot_route_message = Unknown user

# Support for catchall aliases. It is *not* recommended to use this.
virtual_alias_catchall:
  driver = redirect
  domains = +local_domains
##  condition = ${if !eq {$received_protocol}{spam-scanned}}
  data = ${lookup mysql{SELECT CONCAT(vm_aliases.mbox,'@','${quote_mysql:$domain}') FROM vm_mboxes, vm_aliases WHERE vm_mboxes.mbox=vm_aliases.mbox AND vm_mboxes.domain='${quote_mysql:$domain}' AND vm_mboxes.status > '0' AND vm_aliases.alias='catchall' AND vm_aliases.domain='${quote_mysql:$domain}'}}

# This router handles aliasing using a linearly searched alias file with the
# name SYSTEM_ALIASES_FILE. When this configuration is installed automatically,
# the name gets inserted into this file from whatever is set in Exim's
# build-time configuration. The default path is the traditional /etc/aliases.
# If you install this configuration by hand, you need to specify the correct
# path in the "data" setting below.
#
##### NB  You must ensure that the alias file exists. It used to be the case
##### NB  that every Unix had that file, because it was the Sendmail default.
##### NB  These days, there are systems that don't have it. Your aliases
##### NB  file should at least contain an alias for "postmaster".
#
# If any of your aliases expand to pipes or files, you will need to set
# up a user and a group for these deliveries to run under. You can do
# this by uncommenting the "user" option below (changing the user name
# as appropriate) and adding a "group" option if necessary. Alternatively, you
# can specify "user" on the transports that are used. Note that the transports
# listed below are the same as are used for .forward files; you might want
# to set up different ones for pipe and file deliveries from aliases.

# System Aliases, and User Forwards below, are only enabled for primary_hostname & qualify_domain.
# primary_hostname is the server hostname (FQDN)
# qualify_domain can be set in exim_local.conf and defaults to the server domain name,
# which is the primary_hostname without the local part - what "hostname -d" returns.
# These routers do not get invoked for any other virtual email domains configured on the server.

system_aliases:
  driver = redirect
  domains = $primary_hostname:$qualify_domain:$qualify_recipient
  allow_fail
  allow_defer
  data = ${lookup{$local_part}lsearch{/etc/aliases}}
#  user = exim
#  file_transport = address_file
#  pipe_transport = address_pipe


# This router handles forwarding using traditional .forward files in users'
# home directories. If you want it also to allow mail filtering when a forward
# file starts with the string "# Exim filter", uncomment the "allow_filter"
# option.

# The no_verify setting means that this router is skipped when Exim is
# verifying addresses. Similarly, no_expn means that this router is skipped if
# Exim is processing an EXPN command.

# The check_ancestor option means that if the forward file generates an
# address that is an ancestor of the current one, the current one gets
# passed on instead. This covers the case where A is aliased to B and B
# has a .forward file pointing to A.

# The three transports specified at the end are those that are used when
# forwarding generates a direct delivery to a file, or to a pipe, or sets
# up an auto-reply, respectively.

userforward:
  driver = redirect
  check_local_user
  domains = $primary_hostname:$qualify_domain:$qualify_recipient
  file = $home/.forward
  no_verify
  no_expn
  check_ancestor
  allow_filter
  file_transport = address_file
  pipe_transport = address_pipe
  reply_transport = address_reply


# This router matches local user mailboxes.

#localuser:
#  driver = accept
#  check_local_user
#  transport = local_delivery



######################################################################
#                      TRANSPORTS CONFIGURATION                      #
######################################################################
#                       ORDER DOES NOT MATTER                        #
#     Only one appropriate transport is called for each delivery.    #
######################################################################

# A transport is used only when referenced from a router that successfully
# handles an address.

begin transports

# This transport is used for delivering messages over SMTP connections.

remote_smtp:
  driver = smtp
  # run{/bin/echo part is required to de-taint the domain
  dkim_domain = ${run{/bin/echo ${lc:${domain:$h_from:}}}{$value}}
  dkim_canon = relaxed
  dkim_selector = ${if exists{/etc/ssl/dkim/${dkim_domain}.selector}{${readfile{/etc/ssl/dkim/${dkim_domain}.selector}{}}}{0}}
  dkim_private_key = ${if exists{/etc/ssl/dkim/${dkim_domain}.pem}{/etc/ssl/dkim/${dkim_domain}.pem}{0}}

# This transport is used for local delivery to user mailboxes in traditional
# BSD mailbox format. By default it will be run under the uid and gid of the
# local user, and requires the sticky bit to be set on the /var/mail directory.
# Some systems use the alternative approach of running mail deliveries under a
# particular group instead of using the sticky bit. The commented options below
# show how this can be done.

#local_delivery:
#  driver = appendfile
##  file = /var/vmail/$local_part_data
#  maildir_format = true
#  directory = /home/$local_part_data/Maildir
#  create_directory = true
#  directory_mode = 770
#  delivery_date_add
#  envelope_to_add
#  return_path_add
#  user = $local_part
#  group = $local_part
# mode = 0660

dovecot_lmtp:
  driver = lmtp
  socket = /run/dovecot/lmtp
  #return_path_add
  #maximum number of deliveries per batch, default 1
  #batch_max = 200
  #allow suffixes/prefixes (default unset)
  #rcpt_include_affixes

## for vacation mail
vacation_transport:
  driver  = autoreply
  log     = /var/vmail/${domain_data}/${local_part_data}/vacation_log
  once    = /var/vmail/${domain_data}/${local_part_data}/vacation_once_db
  return_path = ${local_part}@${domain}
  to      = ${sender_address}
  from    = ${local_part}@${domain}
  subject = ${lookup mysql{SELECT vm_autoresponders.subject FROM vm_autoresponders WHERE vm_autoresponders.mbox='${quote_mysql:$local_part}' AND vm_autoresponders.domain='${quote_mysql:$domain}' AND vm_autoresponders.status='1' AND vm_autoresponders.mode='Vacation'}{$value}{"Auto Reply"}}
  text = ${lookup mysql{SELECT vm_autoresponders.body FROM vm_autoresponders WHERE vm_autoresponders.mbox='${quote_mysql:$local_part}' AND vm_autoresponders.domain='${quote_mysql:$domain}' AND vm_autoresponders.status='1' AND vm_autoresponders.mode='Vacation'}{$value}fail}
  user = vmail

##  for autoresponder
autoresponder_transport:
  driver  = autoreply
  log     = /var/vmail/${domain_data}/${local_part_data}/autoresponder_log
  return_path = ${local_part}@${domain}
  to      = ${sender_address}
  from    = ${local_part}@${domain}
  subject = ${lookup mysql{SELECT vm_autoresponders.subject FROM vm_autoresponders WHERE vm_autoresponders.mbox='${quote_mysql:$local_part}' AND vm_autoresponders.domain='${quote_mysql:$domain}' AND vm_autoresponders.status='1'  AND vm_autoresponders.mode='Autoresponder'}{$value}{"Auto Reply"}}
  text = ${lookup mysql{SELECT vm_autoresponders.body FROM vm_autoresponders WHERE vm_autoresponders.mbox='${quote_mysql:$local_part}' AND vm_autoresponders.domain='${quote_mysql:$domain}' AND vm_autoresponders.status='1' AND vm_autoresponders.mode='Autoresponder'}{$value}fail}
  user = vmail

#maildir_delivery:
#  driver = appendfile
#  maildir_format = true
#  directory = /var/vmail/${domain_data}/${local_part_data}/Maildir
#  create_directory = true
#  directory_mode = 750
# user = vmail

user_filter_maildir_delivery:
  driver = appendfile
  maildir_format = true
  user = vmail

junk_delivery:
  driver = appendfile
  maildir_format = true
  directory = /var/vmail/${domain_data}/${local_part_data}/Maildir/.Junk
  create_directory = true
  directory_mode = 750
  user = vmail

# SpamAssassin
spamcheck:
    driver = pipe
    command = /usr/sbin/exim -oMr spam-scanned -bS
    use_bsmtp = true
    transport_filter = /usr/bin/spamc -f -u $local_part_data@$domain_data
    home_directory = "/tmp"
    current_directory = "/tmp"
    # must use a privileged user to set $received_protocol on the way back in!
    user = mail
    group = mail
    log_output = true
    return_fail_output = true
    return_path_add = false
    message_prefix =
    message_suffix =

mailman3_transport:
  driver = smtp
  protocol = lmtp
  allow_localhost
  hosts = localhost
  #hosts_override
  port = 8024
  rcpt_include_affixes = true

#mailman_transport:
#  driver = pipe
#  command = MAILMAN_WRAP \
#    '${if def:local_part_suffix \
#      {${sg{$local_part_suffix}{-(\\w+)(\\+.*)?}{\$1}}} \
#      {post}}' \
#    $local_part
#  current_directory = MAILMAN_HOME
#  home_directory = MAILMAN_HOME
#  user = MAILMAN_UID
#  group = MAILMAN_GID


# clamav
#clamav_scan
#   driver = pipe
#   command = /usr/bin/clamdscan
#   user = clamav
#   user_bsmtp = true

# This transport is used for handling pipe deliveries generated by alias or
# .forward files. If the pipe generates any standard output, it is returned
# to the sender of the message as a delivery error. Set return_fail_output
# instead of return_output if you want this to happen only when the pipe fails
# to complete normally. You can set different transports for aliases and
# forwards if you want to - see the references to address_pipe in the routers
# section above.

address_pipe:
  driver = pipe
  return_output


# This transport is used for handling deliveries directly to files that are
# generated by aliasing or forwarding.

address_file:
  driver = appendfile
  delivery_date_add
  envelope_to_add
  return_path_add


# This transport is used for handling autoreplies generated by the filtering
# option of the userforward router.

address_reply:
  driver = autoreply



######################################################################
#                      RETRY CONFIGURATION                           #
######################################################################

begin retry

# This single retry rule applies to all domains and all errors. It specifies
# retries every 15 minutes for 2 hours, then every 2 hours until 1 full day
# has passed since the first delivery failed.

# Domain               Error       Retries
# ------               -----       -------

*                      *           F,2h,15m; F,1d,2h


######################################################################
#                      REWRITE CONFIGURATION                         #
######################################################################

# There are no rewriting specifications in this default configuration file.

begin rewrite


######################################################################
#                   AUTHENTICATION CONFIGURATION                     #
######################################################################

# There are no authenticator specifications in this default configuration file.

begin authenticators

dovecot_plain:
  driver = dovecot
  public_name = PLAIN
  server_socket = /run/dovecot/auth-client
  server_set_id = $auth1

dovecot_login:
  driver = dovecot
  public_name = LOGIN
  server_socket = /run/dovecot/auth-client
  server_set_id = $auth1

# End of Exim configuration file