User Tools

Site Tools


exim4:config

Exim4 - Config

http://networkgeekstuff.com/networking/tutorial-email-server-for-a-small-company-including-imap-for-mobiles-spf-and-dkim/ TODO

Our mail server supports virtual accounts using the MySQL database, SMTP-authentication and secure connection TLS / SSL.

Determine the user account which will be the owner of this mail setup

On Ubuntu, there is an existing user named mail. This mail setup will run with this mail user being its owner.

NOTE: A different user could be used as the owner instead of using the mail user account, and if so simply ensure that you adjust for all subsequent instructions in this setup.

For example, you could create a different user account named exim:

useradd exim -c "Exim" -d /var/spool/mqueue -s /sbin/nologin -g mail

Get the User Id (uid) and Group Id (gid) of the mail owner

Issue the following command to determine the User Id (uid) and Group Id (gid) of the mail user.

cat /etc/passwd | grep mail:

Returns

mail:x:8:8:mail:/var/mail:/usr/sbin/nologin

In this example the User Id (uid) is the first 8. The Group Id (gid) is the second 8. The actual numbers may differ on your system.

Take a note of the uid and gid numbers as they will be needed later.

NOTE: Ubuntu usually has the mail user having:

  • a UID value of 8.
  • a GID value of 8.

Create a certificate

To use TLS / SSL create a certificate.

Create a certificate manually. Within the /etc/exim4 directory run:

mkdir -p /etc/ssl/certs
cd /etc/ssl/certs
openssl req -x509 -newkey rsa:4096 -keyout mail.pem -out mail.pem -days 9999 -nodes

Should this be

openssl req -x509 -sha256 -newkey rsa:4096 -keyout mail.pem -out mail.pem -days 9999 -nodes

ALERT: There are less than 9999 days left before the Unix / Linux 32-bit date wrap-around occurs.

This can result in the days being calculated as a negative date. It would be safer to use a more meaningful number of days.

Fill in the following fields with any data you like (as this is purely a self-signed certificate) except for the Common Name (eg, YOUR name) [] field where you need to enter the name of the server:

Shows

Generating a 4096 bit RSA private key
............................................++
.............................................................................................................................++
writing new private key to 'exim.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:UK
State or Province Name (full name) [Some-State]:Jersey
Locality Name (eg, city) []:St. Helier 
Organization Name (eg, company) [Internet Widgits Pty Ltd]:ShareWiz
Organizational Unit Name (eg, section) []:Tech
Common Name (e.g. server FQDN or YOUR name) []:mail.sharewiz.net
Email Address []:admin@sharewiz.net

Now we have a file /etc/ssl/certs/mail.pem.

Ensure this file has the right permissions and owner.

chmod 440 /etc/ssl/certs/mail.pem
chgrp mail /etc/ssl/certs/mail.pem

D-H parameters that may take a substantial amount of time to compute. It is unreasonable to re-compute them for every TLS session. Therefore, Exim keeps this data in a file.

For maximum security, the parameters that are stored in this file should be recalculated periodically, the frequency depending on your paranoia level.

The calculation of new parameters needs random numbers, and these are obtained from /dev/random. If the system is not very active, /dev/random may delay returning data until enough randomness (entropy) is available.

rm -f new-params
touch new-params
chown exim:exim new-params
chmod 0600 new-params
certtool --generate-dh-params --bits 2236 >>new-params
openssl dhparam -noout -text -in new-params | head
[ check the first line, make sure it's not more than 2236;
  if it is, then go back to the start ("rm") and repeat
  until the size generated is at most the size requested ]
chmod 0400 new-params

openssl req -newkey rsa:2048 -keyout sharewiz.net.key -out sharewiz.net.csr openssl req -new -x509 -days 3650 -nodes -out sharewiz.net.pem -keyout sharewiz.net.key openssl dhparam -out dh4096.pem 4096 openssl dhparam -rand - 4096 » dhparam.pem openssl dhparam -rand - 8192 » dh8192.pem openssl ecparam -list_curves

openssl rsa req -passin password -in 1_sharewiz.net.csr -noout -text

Exim Config File (Split)

Because the default Exim4 configuration file is large and uncomfortable to edit, it is broken down into a number of files that are included in alphabetical order:

  • 100.main.conf - basic server configuration: variables, database connection, logging, etc.
  • 110.greylist.conf - Greylisting scripts
  • 200.acl-greylist.conf - ACL for Greylisting
  • 400.acl-check-rcpt-syntax.conf - ACL- checking host-sender
  • 410.acl-check-rcpt-spam.conf - ACL for the calculation of the anti-spam score for the message header
  • 420.acl-check-rcpt-end.conf - the end of the ACL check_rcpt: delays greylisty, blacklist
  • 500.acl-check-data.conf - ACL to verify the contents of the letter: attachi, Spamassassin, antivirus
  • 600.routers.conf - routers
  • 610.routers-groups.conf - router to support user groups
  • 700.transports.conf - transports
  • 800.retry.conf - Resending messages
  • 900.authenticators.conf - Authentication
  • configure - the main configuration file that connects all the other
  • dialup_hosts - regular expressions describing the hosts that we do not like
  • system-filter - spam action: mark / delete
  • whitelist-hosts - list of hosts that do not pass a series of tests
  • whitelist-sender - a list of senders who do not pass a series of tests

At first glance, it looks a bit confusing, but I'll try to explain the logic of Exim with config. Upon receiving the email, the following occurs:

  • The sending host is checked: greeting syntax session, a domain name that matches the name and address, etc. If an obvious error is found (invalid characters, trying to pass themselves off as other hosts, etc.) - the email is not passed, otherwise the email is awarded spam scores points;
  • if the host or the sender is not included in the whitelist, a delay is triggered through Greylisting. The delay is calculated by the formula 15c + (the number dialed points / 10), Greylisting just do not know if such a host, adds it to the grey list and sends the error “temporary problem”. If the host is a normal relay, he will send a letter again and get to the white list (by the way, normal hosts are willing to wait and the previous delay, it is in a hurry to send spammers megatons of letters and wait for them once);
  • email is broken down into parts. If it has a prohibited file extensions in the attachments or viruses, it is mercilessly chopped. The same email is then sent to SpamAssassin, the number of points scored there is multiplied by 2 and added to the total;
  • Then the email is sent to the routers, that decide what to do with them: send by SMTP, put in a drawer, etc. and assign the appropriate email transport. The router with the groups - all interesting thing: the group - it is something like an alias, but as long as it is not a private, write only group members can in it;
  • Transports, of course, carry out what they want from the routers;
  • Separately, the system filter works:
  • The total spam points adjusts the rules subject line to something like SPAM [104 points] or remove it entirely, depending on the settings each individual mailbox;

configure

configure
###################################################################### 
# Runtime configuration file for Exim # 
###################################################################### 
 
# Include main settings.
include /usr/local/etc/exim/100.main.conf
 
# Include settings Greylisting.
.include /usr/local/etc/exim/110.greylist.conf
 
### ACL configuration for incoming mail.
begin acl
 
# Start ACL - "working" for the ACL Greylisting
.ifdef USE_GREYLIST
greylist_acl:
.include /usr/local/etc/exim/200.acl-greylist.conf
.endif
 
# Verify the HELO.
acl_check_helo:
  accept hosts = +relay_from_hosts
  drop condition = ${if match{$sender_helo_name}{MY_IP}{yes}{no} }
  message   = "Dropped spammer pretending to be us"
  drop condition = ${if match{$sender_helo_name}{^[0-9]\.[0-9]\.[0-9]\.[0-9]}{yes}{no} }
  message   = "Dropped IP-only or IP-starting helo"
accept
 
 
# These rules are triggered for each email.
acl_check_rcpt:
  warn set acl_c_lp = $local_part@$domain
 
  # Acl_check_rcpt - checking the syntax is correct
  .include /usr/local/etc/exim/400.acl-check-rcpt-syntax.conf
 
  # Acl_check_rcpt - anti-spam - Host and others.
  .include /usr/local/etc/exim/410.acl-check-rcpt-spam.conf
 
  # Acl_check_rcpt - black-lists, delays, etc.
  .include /usr/local/etc/exim/420.acl-check-rcpt-end.conf
 
 
# Check the message body.
acl_check_content:
 
  # Include configuration message body check
  .include /usr/local/etc/exim/500.acl-check-data.conf
 
 
# What do we do with the mail.
begin routers
 
  # Include router configuration. 
  .include /usr/local/etc/exim/600.routers.conf
 
 
# Start transports - Delivers the mail.
begin transports
 
  # Include transports.
  .include /usr/local/etc/exim/700.transports.conf
 
 
# Configuration of repetition and rewriting.
.include /usr/local/etc/exim/800.retry.conf
 
 
#begin rewrite
 
 
# Authentication section when sending emails.
begin authenticators
  # Authenticate users.
  .include /usr/local/etc/exim/900.authenticators.conf 

100.main.conf

The basic settings: IP, domains, etc .:

# Set the variables.
MY_IP = 123.123.123.123
INTERNAL_IP = 192.168.1.2

# Settings Vexim.
USE_SPF = true
USE_AV = true
USE_SPAMD = true
USE_GREYLIST = true
TLS = true

# Whitelisting.
hostlist whitelist_hosts = net-iplsearch; /usr/local/etc/exim/whitelist-hosts
addresslist whitelist_sender = wildlsearch; /usr/local/etc/exim/whitelist-sender

# In IPv6 we do not work.
disable_ipv6 = true

# User and group from which will run the entire bundle.
exim_user = exim
exim_group = mail

# There were mailings settings, do not use - no setup.
MAILMAN_HOME = /usr/local/mailman
MAILMAN_WRAP = MAILMAN_HOME/mail/mailman
MAILMAN_USER = exim
MAILMAN_GROUP = mail

# Enter the credentials to connect to the MySQL server. 
# Word `hide`, first, means that when 
# Check config command call 
# Exim -bV config_file these data will not be displayed. 
# If without it - it will be shown ... Recording format: 
# Host / dbname / user / password
hide mysql_servers = localhost::(/tmp/mysql.sock)/mail/exim/8975f9i7vioyuhg

# Interfaces to listen.
local_interfaces = MY_IP

# Host Name.  Used EHLO. 
# Listed on the other points, if they are not specified, the type qualify_domain and other .. 
# If there are not found anything (comment out the line), then used that returns the uname () function.
primary_hostname = sharewiz.net

# Request for sampling Domain Information.
VIRTUAL_DOMAINS = SELECT DISTINCT domain FROM domains WHERE type = 'local' AND enabled = '1' AND domain = '${quote_mysql:$domain}'
RELAY_DOMAINS = SELECT DISTINCT domain FROM domains WHERE type = 'relay'  AND domain = '${quote_mysql:$domain}'
ALIAS_DOMAINS = SELECT DISTINCT alias FROM domainalias WHERE alias = '${quote_mysql:$domain}'

# Make a list of local domains.  Next, the list will appear in the form of + local_domains.
# In this case, the domains are selected from the database MySQL.  Also, you can simply scroll through the colon.
domainlist local_domains = @ : ${lookup mysql{VIRTUAL_DOMAINS}} : ${lookup mysql{ALIAS_DOMAINS}}
domainlist relay_to_domains = ${lookup mysql{RELAY_DOMAINS}}

# List of trusted networks from which mail will go without a number of checks.
hostlist   relay_from_hosts = localhost : MY_IP : 192.168.100.0/20 : 192.168.80.0/24

# Enter the name acl for checking mail.
acl_smtp_rcpt = acl_check_rcpt
acl_smtp_data = acl_check_content
acl_smtp_helo = acl_check_helo

# If the setting is said to check mail for viruses - connect.
.ifdef USE_AV
av_scanner = clamd:/var/run/clamav/clamd.sock
.endif


# If the setting is said to check mail for spam - connect.
.ifdef USE_SPAMD
spamd_address = /var/run/spamd.sock
.endif


# If the setting is said to work with support for SSL - connect.
.ifdef TLS
 # SSL/TLS cert and key
 tls_certificate = /etc/ssl/certs/mail.pem
 tls_privatekey = /etc/ssl/certs/mail.pem
 # Advertise TLS to anyone
 tls_advertise_hosts = *
 tls_on_connect_ports=465
.endif


# Domain name is added to the local senders (real users of the system) that mail is sent from the root, will be from 
# root@sharewiz.net.  If this item is not specified, then the hostname of `primary_hostname` is used.
qualify_domain = sharewiz.net

# Host Name for the situation, return to the previous one - is the domain name to be added to the e-mail 
# Of system users, well and in general for the post, which came on the address type `root` etc ... 
  Eton # If the item is not specified then the value obtained from the preceding paragraph - `qualify_domain`
 qualify_recipient = sharewiz.net

 # A is just a piece of the above anachronism - about mail to 
  # As user @ [222.222.222.222] - take it or not.  By default 
  # (When the line is commented out) the value - false.  If you want to 
  # Put the true one would have to add to the list of domains 
  Combination # @ [] - it means `all local addresses`
 allow_domain_literals = false

 # Delivery prohibit work by the user under the root - for safety
 never_users = root

 # Check the line forward and reverse zones for all hosts. 
  # Toka why they need it - even don `t know ... Spam does not cut. 
  # But there may be problems - if the zone server tells the server `failed` 
  # The mail from that host you get :)
 #host_lookup = *

  # By default, Exim does all otfutbolivat `nekvalifitsirovannye` address 
  # Consisting of the current local part.  To allow such letters 
  # Certain hosts using these guidelines: 
  # Nekvalifitsirovannyh` senders to `
 #sender_unqualified_hosts = + relay_from_hosts

  # For `nekvalifitsirovannyh` recipients
 #recipient_unqualified_hosts = + relay_from_hosts

 # If the message was not delivered, it is generated sooschenie 
  # Error.  If the error message could not be delivered 
  # It is frozen for a specified period at this point, 
  # And then attempt to deliver it again.  At the next 
  # Failure - the message is deleted.
 ignore_bounce_errors_after = 1d

 # Frozen messages queued for longer 
  # Specified time are deleted and a message is generated 
  # Error (assuming it was not a undelivered 
  # Error message :))
 timeout_frozen_after = 7d

 # A list of addresses, separated by commas, which are saved into 
  # Of posts frozen messages (about frozen 
  # Notification of freezing, no messages are generated.  - I 
  # Hope this line is clear :))
 #freeze_tell = postmaster@sharewiz.net

 # How long to repeat delivery attempt 
  # Frozen posts
 auto_thaw = 1h

 # Server greeting
 smtp_banner = "$primary_hostname, ESMTP EXIM $version_number"

 # The maximum number of simultaneous connections 
  # SMTP.  Count should be based on the load on the server
 smtp_accept_max = 500

 # Maximum number of messages are accepted per connection 
  # From the remote server (or user).
 smtp_accept_max_per_connection = 25

 # Maximum number of connections from one host
 smtp_accept_max_per_host = 20

 # If the message many recipients on remote hosts, 
  # Zapuskatesya it to the number of maximum number 
  # Parallel delivery processes
 remote_max_parallel = 15

 # When generating error messages apply 
  # Not the entire message, and the piece (from the beginning) of the 
  # Size (sometimes useful and entirely - in this case 
  # Just comment out this line)
 return_size_limit = 70k

 # Allow the wrong characters in the HELO (faced 
  # With this accident - name of the company consisted of two words 
  # And some dolt domain called the my_firme_name 
  # Direct to underscore ... vindovyh customers at 
  # Connection happily reported about itself 
  # `Vasya.my_firme_name` Exim does well, and their football :))
 helo_allow_chars = _

 # Forced synchronization.  If the sender 
  # Rushing to issue commands without waiting for a reply, 
  # He sent away for a long time :) A little, 
  # Spam is cut.
 smtp_enforce_sync = true

 # Choose that we will benefit from logging 
  # + - Write in the logs, 
  # - - Do not write in the logs. 
  # + All_parents - all incoming? 
  # + Connection_reject - fragmentation compound 
  # + Incoming_interface - interface (actually - IP) 
  # + Lost_incoming_connections - lostness incoming 
  connection # 
  # + Received_sender - Poster 
  # + Received_recipients - recipient 
  # + Smtp_confirmation - confirmation SMTP? 
  # + Smtp_syntax_error - SMTP syntax error 
  # + Smtp_protocol_error - SMTP protocol error 
  # -queue_run - Work queue (frozen messagi) 
  #log_selector = \ 
  # + All \ 
  # -incoming_port \ 
  # -incoming_interface \ 
  # -arguments \ 
  # -smtp_connection \ 
  # -lost_incoming_connection \ 
  # -queue_run 
  log_selector = + subject \
                 + All_parents \
                 + Lost_incoming_connection \
                 + Received_sender \
                 + Received_recipients \
                 + Smtp_confirmation \
                 + Smtp_syntax_error \
                 + Smtp_protocol_error \
                 -queue_run

 # Filter system, then you can tag spam and generally to do with a lot of interesting letters
 system_filter = / usr / local / etc / exim / system-filter
 system_filter_pipe_transport = address_pipe
 system_filter_user = exim
 system_filter_group = mail   

110.greylist.conf

  # Greylisting Settings 

  # The initial delay after the first attempt to send a letter
 GREYLIST_INITIAL_DELAY = 10 MINUTE

 # Lifetime gray recording after the first attempt to send a letter
 GREYLIST_INITIAL_LIFETIME = 4 HOUR

 # Lifetime white write
 GREYLIST_WHITE_LIFETIME = 36 DAY

 # I can not remember what it is, but there was zero :-))
 GREYLIST_BOUNCE_LIFETIME = 0 HOUR

 # Names greylistovyh tables
 GREYLIST_TABLE = exim_greylist
 GREYLIST_LOG_TABLE = exim_greylist_log

 # Logging settings greylistov
 GREYLIST_LOG_ENABLED = no

 .ifdef USE_GREYLIST
 # Database macros
 GREYLIST_TEST = SELECT CASE \
    WHEN now ()> block_expires \
    OR relay_ip = '127.0.0.1' \
    THEN "accepted" \
    ELSE "deferred" \
  END AS result, id \
  FROM GREYLIST_TABLE \
  WHERE (now () <record_expires) \
    AND (relay_ip = '$ {quote_mysql: $ sender_host_address}' \
         OR (type = 'MANUAL' \
             AND (relay_ip IS NULL \
                   OR relay_ip = substring ( '$ {quote_mysql: $ sender_host_address}', 1, length (relay_ip)) \
                 ) \
            ) \
        ) \
  ORDER BY result DESC LIMIT 1

 GREYLIST_ADD = INSERT INTO GREYLIST_TABLE \
   (Relay_ip, block_expires, \
    record_expires, create_time, type) \
  VALUES ( '$ {quote_mysql: $ sender_host_address}', \
   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_LOG = INSERT INTO GREYLIST_LOG_TABLE \
                (Listid, timestamp, kind) \
                VALUES ($ acl_m9, now (), '$ acl_m8')

 GREYLIST_CHECK = SELECT greylist from domains where domain = '$ domain'

 .endif 

200.acl-greylist.conf

  # If the domain field value greylist = 0, no check at all
 deny condition = $ {if <{$ {lookup mysql {GREYLIST_CHECK}}} {1}}

 # Expose the internal variables for greylista
 warn set acl_m8 = $ {lookup mysql {GREYLIST_TEST} {$ value} {result = unknown}}
         set acl_m9 = $ {extract {id} {$ acl_m8} {$ value} {- 1}}
         set acl_m8 = $ {extract {result} {$ acl_m8} {$ value} {unknown}}

 # Check whether a host know if not - bring into the gray list
 accept condition = $ {if eq {$ acl_m8} {unknown} {1}}
         condition = $ {lookup mysql {GREYLIST_ADD} {yes} {no}}

 # Writing to the log
 .ifdef GREYLIST_LOG_ENABLED
 warn condition = $ {lookup mysql {GREYLIST_LOG}}
 .endif

 # Check for resubmission to the transition to the white list
accept condition = $ {if eq {$ acl_m8} {deferred} {1}}
        condition = $ {lookup mysql {GREYLIST_DEFER_HIT} {yes} {yes}}

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 

400.acl-check-rcpt-syntax.conf

 # Receive messages that came with lokalhosta, not via TCP / IP
accept hosts =:

# Forbid letters contain a local part
@ # Characters; %; !; /; |. Remember, if you had
# `Percent_hack_domains` the% must be removed.
# Checked local domains
deny message = Reject: incorrect symbol in address
        log_message = REJECT: incorrect symbol in address
        domains = + local_domains
        [.]. Local_parts = ^: ^ * [@% / |!]
        delay = 30s

# Check for invalid characters for non-local recipients:
deny message = Reject: incorrect symbol in address
        log_message = REJECT: incorrect symbol in address
        domains =! + local_domains
        local_parts = ^ [./ |]: ^ * [@%!]: ^ * / \\ \\ ./...
        delay = 30s

# Accept mail for the local domain postmaster without
# Sender (I commented out because it is -
# The main source of spam in my mailbox).
 # Accept local_parts = postmaster
# Domains = + local_domains

# Zapreschschaem if the sender can not be verified
# (Not in the list of local users)
# At home I zakomentil, for the reason that some
# Zhelezyaki (printers, & etc) and software (Kaspersky, DrWEB)
# Know how to send e-mail, in case of problems, but do not know how to put
# Desired sender. Such letters will not let this check.
# Require verify = sender

# Zapreschschaem those who have not exchanged congratulatory
# Messages (HELO / EHLO)
deny condition = $ {if eq {$ sender_helo_name} {} {yes} {no}}
        message = Reject: HELO / EHLO require by SMTP RFC
        log_message = REJECT: HELO / EHLO require by SMTP RFC
        delay = 30s

# Receives messages from those who authenticated:
 the accept authenticated by = *

# Rubaie tries, those substitutes its own IP in the HELO
deny condition = $ {if isip {$ sender_helo_name} {yes} {no}}
        hosts = + relay_from_hosts:! *
        message = Reject: We do not allow domain literals, many spam ...
        log_message = REJECT: We do not allow domain literals, many spam ...
        delay = 30s

# Ruban Helo with our name
deny condition = $ {if match_domain {$ sender_helo_name} \
                          {$ Primary_hostname: + local_domains: + relay_to_domains} \
                          {True} {false}}
        message = Reject: Message was delivered by ratware - own
        log_message = REJECT: remote host used our name in HELO / EHLO.
        delay = 30s

# Ruban invalid characters in the helo
deny condition = $ {if match {$ sender_helo_name} {\ N_ \ N} {yes} {no}}
        message = Reject: Invalid symbols in HELO
        log_message = REJECT: Invalid symbols in HELO
        hosts = 127.0.0.1:!! localhost:! + relay_from_hosts: *

# Ekscheyndzha restrictions - the user can not start / end point.
deny message = Reject: Invalid address
        log_message = REJECT: Dot-starting address
        senders = \ N ^ \ |. \ @ \ N. 

410.acl-check-rcpt-spam.conf

 # # Enter a variable acl_m0 - count will be in it,
# # How many points were numbered spam ...
 warn set acl_m0 = 0

# Check the HELO line and reverse DNS records for the North:
warn condition = $ {if! eq {$ sender_helo_name} {$ sender_host_name} {yes} {no}}
 hosts = + relay_from_hosts:! *
 set acl_m0 = $ {eval: $ acl_m0 + 20}

# Look, there was found the reverse entry for the host
warn condition = $ {if eq {$ host_lookup_failed} {1} {yes} {no}}
 hosts = + relay_from_hosts:! *
 set acl_m0 = $ {eval: $ acl_m0 + 30}

# Counting the number of dots or hyphens in the domain name. (More than 5 = 40 points)
warn condition = $ {if match {$ sender_host_name} \
 {\ N (? (> \ W + [\ |. \ -]) {5,}) \ N} {yes} {no}}
 hosts = + relay_from_hosts:! *
 set acl_m0 = $ {eval: $ acl_m0 + 40}

# Check the length of the return addresses pochtovgo - pslednee time got into the habit
# Send wild-type return address Fulbrightbackstage@absacargo.com,
# Damsel'stailpipe`s@abbeywindows.co.uk etc.
warn condition = $ {if> {$ {strlen: $ sender_address}} {25} {yes} {no}}
 hosts = + relay_from_hosts:! *
 set acl_m0 = $ {eval: $ acl_m0 + 10}

# Add the points for any dialup hosts
warn condition = $ {lookup {$ sender_host_name} \
 wildlsearch {/ usr / local / etc / exim / dialup_hosts} \
 {Yes} {no}}
 hosts = + relay_from_hosts:! *
 set acl_m0 = $ {eval: $ acl_m0 + 60}

# Check the counter recipients in the letter - normal users rarely send
# Messages with a large number of recipients, and mail services for large
# Reset all servers on the white sheet that is more
warn condition = $ {if> {$ recipients_count} {6} {yes} {no}}
 hosts = + relay_from_hosts:! *
 set acl_m0 = $ {eval: $ acl_m0 + ($ recipients_count * 20)}

# Check for the existence of zones of HELO (this rule ogrebayut points all
# Freaks with HELO type 'friends' or 'localhost.localdomain')
warn condition = $ {if! eq {$ {lookup mysql {SELECT 1 FROM \
 `List_top_level_domains` WHERE` zone` = \
 LCASE (CONCAT ( '.', SUBSTRING_INDEX (\
 '$ {Quote_mysql: $ sender_helo_name}', \
 '.', -1)))}}} {1} {yes} {no}}
 hosts = + relay_from_hosts:! *
 set acl_m0 = $ {eval: $ acl_m0 + 150}

# Add points if spf does not match
warn spf = fail
 hosts = + relay_from_hosts:! *
 set acl_m0 = $ {eval: $ acl_m0 + 60}

# Set the variable that is visible between the ACL-s 
warn set acl_c_spam = $ acl_m0

420.acl-check-rcpt-end.conf

 # Skip the letter, if the host or the sender to the whitelist
warn log_message = WHITELISTED: host
 hosts = + whitelist_hosts

warn log_message = WHITELISTED: sender
 senders = + whitelist_sender

warn set acl_m5 = $ local_part @ $ domain

accept hosts = + whitelist_hosts

accept senders = + whitelist_sender

# Delay. It cuts a lot of not-MTA - spam skriptik.
 warn
 set acl_c0 = 15s

# Compute the delay based on the count of spam score:
 warn
 condition = $ {if! eq {$ acl_m0} {0} {yes} {no}}
 condition = $ {if> {$ acl_m0} {150} {yes} {no}}
 set acl_c0 = $ {eval: $ acl_m0 / 10} s

 warn
 # Set the delay to 0 seconds, your hosts
 hosts = + relay_from_hosts
 set acl_c0 = 0s

 warn
 delay = $ acl_c0

# Ruban those in the black list. are moving a server
# From the top down, unless the host is not found on the ground, the
# Requested second, etc. If it is not found in any
# From the list - the mail is skipped.
 deny message = "you in blacklist - $ dnslist_domain -> \
 $ Dnslist_text; $ Dnslist_value "
 log_message = REJECT: Listed in $ dnslist_domain
 hosts =! + relay_from_hosts
 dnslists = cbl.abuseat.org: \
 dul.dnsbl.sorbs.net: \
 sbl-xbl.spamhaus.org
 delay = 30s

# If enabled greylisty - greylistim all mail except postmasterskoy
.ifdef USE_GREYLIST

 ! Defer senders =: postmaster @ *
 acl = greylist_acl
 message = GREYLIST: Greylisted, try later.
.endif

 # Check the members of the alias file (system)
 accept domains = + local_domains
 verify = recipient

 # Allow mail from domains listed in relay_from_hosts
 accept hosts = + relay_from_hosts

 # Prinial mail for domains ekscheyndzhevyh
 accept domains = + relay_to_domains

 # If nepodoshlo any rule - is clearly looking for a man
 # Open relay. Pshёl away. :)
 deny message = "Access deny - this not open relay!"
 log_message = REJECT: We are not an open relay
 delay = 30s 

500.acl-check-data.conf

 # Check the body of the message

# Extract MIME containers and cut serious mistakes
deny message = This message contains a MIME error ($ demime_reason)
 log_message = REJECT: Error in MIME
 demime = *
 condition = $ {if> {$ demime_errorlevel} {2} {1} {0}}

# Cut typical viral file extensions
deny message = Bad file extension ($ found_extension)
 log_message = REJECT: Bad attachment
 demime = scr: vbs: bat: lnk: pif

deny message = Possible CMD file attack ($ found_extension)
 log_message = REJECT: Bad attachment
 demime = cmd

deny message = Possible COM file attack ($ found_extension)
 log_message = REJECT: Bad attachment
 demime = com

deny message = Possible Microsoft JScript attack ($ found_extension)
 log_message = REJECT: Bad attachment
 demime = js

deny message = Possible Windows registry attack ($ found_extension)
 log_message = REJECT: Bad attachment
 demime = reg

deny message = Possible compiled Help file-base virus ($ found_extension)
 log_message = REJECT: Bad attachment
 demime = chm

deny message = Possible SpeedDial attack ($ found_extension)
 log_message = REJECT: Bad attachment
 demime = cnf

deny message = Possible Micrsoft HTML archive attack ($ found_extension)
 log_message = REJECT: Bad attachment
 demime = hta

deny message = Possible Microsoft Internet Settings attack ($ found_extension)
 log_message = REJECT: Bad attachment
 demime = ins

deny message = Possible Windows Explorer Command attack ($ found_extension)
 log_message = REJECT: Bad attachment
 demime = scf

deny message = Possible Microsoft Windows Script attack ($ found_extension)
 log_message = REJECT: Bad attachment
 demime = sct

deny message = Possible Microsoft VBScript attack ($ found_extension)
 log_message = REJECT: Bad attachment
 demime = vbs: vbe

deny message = Possible Microsoft Script Host attack ($ found_extension)
 log_message = REJECT: Bad attachment
 demime = wsc: wsf: wsh

deny message = Possible Exchange Shortcut attack ($ found_extension)
 log_message = REJECT: Bad attachment
 demime = xnk

deny message = Possible Microsoft Access Shortcut attack ($ found_extension)
 log_message = REJECT: Bad attachment
 demime = mad: maf: mag: mam: maq: mar: mas: mat: mav: maw

# Messages of NUL-character
deny message = This message contains NUL characters
 log_message = REJECT: NUL characters!
 condition = $ {if> {$ body_zerocount} {0} {1} {0}}

# Syntax header
deny message = Incorrect headers syntax
 log_message = REJECT: Incorrect header syntax
 hosts = + relay_from_hosts:! *
 ! Verify = header_syntax

# Check for spam
.ifdef USE_SPAMD

warn set acl_m3 = $ acl_c_spam

warn set acl_m5 = $ acl_c_lp

warn message = X-Spam-Report: $ spam_report
 spam = exim: true
# Spam = nobody: true

# If SpamAssassin has returned more than one score, add the number of points * 20 to the total spam rating
warn condition = $ {if> {$ spam_score_int} {10} {1} {0}}
 set acl_m3 = $ {eval: $ acl_c_spam + $ spam_score_int * 2}

# Based on the total of number of spam points and define the settings yuzersky, tag or delete email spam
warn set acl_m4 = $ {lookup mysql {select count (users.on_spamassassin) from users, domains where username = '$ acl_m5' \
 and domains.enabled = '1' and users.enabled = '1' and users.sa_tag> 0 \
 and users.sa_tag <$ acl_m3 and users.domain_id = domains.domain_id}}

warn set acl_m6 = $ {lookup mysql {select count (users.on_spamassassin) from users, domains where username = '$ acl_m5' \
 and domains.enabled = '1' and users.enabled = '1' and users.sa_refuse> 0 \
 and users.sa_refuse <$ acl_m3 and users.domain_id = domains.domain_id}}

warn condition = $ {if> {$ acl_m3} {60} {1} {0}}
 log_message = SPAM: $ acl_m3 points

warn condition = $ {if eq {$ acl_m6} {yes} {yes} {no}}
 log_message = SPAM: $ acl_m3 points

.endif

# Check the email for viruses
.ifdef USE_AV
 deny malware = *
 log_message = MALWARE: $ malware_name
.endif

# Skip the rest 
accept

600.routers.conf

 dnslookup:
 driver = dnslookup
 domains =! + local_domains
 transport = remote_smtp
 ignore_target_hosts = 0.0.0.0: 127.0.0.0/8
 no_more

ditch_maxmsgsize:
 driver = redirect
 allow_fail
 condition = $ {if> {$ message_size} {$ {lookup mysql {select users.maxmsgsize from users, domains \
 where localpart = '$ {quote_mysql: $ local_part}' \
 and domain = '$ {quote_mysql: $ domain}' \
 and users.maxmsgsize> 0 \
 and users.domain_id = domains.domain_id} {$ {value} K} fail}} {yes} {no}}
 data =: fail: This user does not accept messages larger than $ {lookup mysql {select users.maxmsgsize from users, domains \
 where localpart = '$ {quote_mysql: $ local_part}' and domain = '$ {quote_mysql: $ domain}' \
 and users.maxmsgsize> 0 and users.domain_id = domains.domain_id} {$ {value}} fail} Kb.
# Local_part_suffix = - *
# local_part_suffix_optional
# retry_use_local_part

ditch_malware:
 driver = redirect
 allow_fail
 data =: blackhole:
 condition = $ {if and {{match {$ h_X-ACL-Warn:} {* malware *}} \..
 {Eq {$ {lookup mysql {select users.on_avscan from users, domains \
 where localpart = '$ {quote_mysql: $ local_part}' \
 and domain = '$ {quote_mysql: $ domain}' \
 and users.on_avscan = '1' \
 and users.domain_id = domains.domain_id}}} {1}}} {yes} {no}}

 ditch_spam:
 driver = redirect
 allow_fail
 data =: blackhole:
 condition = $ {if> {$ spam_score_int} {$ {lookup mysql {select users.sa_refuse from users, domains \
 where localpart = '$ {quote_mysql: $ local_part}' \
 and domain = '$ {quote_mysql: $ domain}' \
 and users.on_spamassassin = '1' \
 and users.domain_id = domains.domain_id \
 and users.sa_refuse> 0} {$ value} fail}} {yes} {no}}
# Local_part_suffix = - *
# local_part_suffix_optional
# retry_use_local_part

ditch_hdrmailer:
 driver = redirect
 allow_fail
 data =: blackhole:
 condition = $ {if eq {$ {lookup mysql {select count (blocklists.block_id) from blocklists, users, domains \
 where blocklists.blockhdr = 'X-Mailer' \
 and LOCATE (blocklists.blockval, '$ {quote_mysql: $ h_x-mailer:}')> 0 \
 and users.localpart = '$ {quote_mysql: $ local_part}' \
 and domains.domain = '$ {quote_mysql: $ domain}' \
 and domains.domain_id = blocklists.domain_id \
 and users.user_id = blocklists.user_id}}} {1} {yes} {no}}
# Local_part_suffix = - *
# local_part_suffix_optional
 retry_use_local_part

ditch_hdrto:
 driver = redirect
 allow_fail
 data =: blackhole:
 condition = $ {if eq {$ {lookup mysql {select count (blocklists.block_id) from blocklists, users, domains \
 where blocklists.blockhdr = 'To' \
 and LOCATE (blocklists.blockval, '$ {quote_mysql: $ h_to:}')> 0 \
 and users.localpart = '$ {quote_mysql: $ local_part}' \
 and domains.domain = '$ {quote_mysql: $ domain}' \
 and domains.domain_id = blocklists.domain_id \
 and users.user_id = blocklists.user_id}}} {1} {yes} {no}}
# Local_part_suffix = - *
# local_part_suffix_optional
 retry_use_local_part

ditch_hdrfrom:
 driver = redirect
 allow_fail
 data =: blackhole:
 condition = $ {if eq {$ {lookup mysql {select count (blocklists.block_id) from blocklists, users, domains \
 where blocklists.blockhdr = 'From' \
 and LOCATE (blocklists.blockval, '$ {quote_mysql: $ h_from:}')> 0 \
 and users.localpart = '$ {quote_mysql: $ local_part}' \
 and domains.domain = '$ {quote_mysql: $ domain}' \
 and domains.domain_id = blocklists.domain_id \
 and users.user_id = blocklists.user_id}}} {1} {yes} {no}}
# Local_part_suffix = - *
# local_part_suffix_optional
 retry_use_local_part

ditch_hdrsubject:
 driver = redirect
 allow_fail
 data =: blackhole:
 condition = $ {if eq {$ {lookup mysql {select count (blocklists.block_id) from blocklists, users, domains \
 where blocklists.blockhdr = 'Subject' \
 and LOCATE (blocklists.blockval, '$ {quote_mysql: $ h_subject:}')> 0 \
 and users.localpart = '$ {quote_mysql: $ local_part}' \
 and domains.domain = '$ {quote_mysql: $ domain}' \
 and domains.domain_id = blocklists.domain_id \
 and users.user_id = blocklists.user_id}}} {1} {yes} {no}}
# Local_part_suffix = - *
# local_part_suffix_optional
 retry_use_local_part

virtual_vacation:
 driver = accept
 ! Condition = $ {if and {{match {$ h_precedence:} {(i?) Junk | bulk | list}} \
 {Eq {$ {lookup mysql {select users.on_vacation from users, domains \
 where localpart = '$ {quote_mysql: $ local_part}' \
 and domain = '$ {quote_mysql: $ domain}' \
 and users.on_vacation = '1' \
 and users.domain_id = domains.domain_id}}} {1}}} {yes} {no}}
 no_verify
 no_expn
 unseen
 transport = virtual_vacation_delivery

virtual_forward:
 driver = redirect
 check_ancestor
 unseen = $ {if eq {$ {lookup mysql {select unseen from users, domains \
 where localpart = '$ {quote_mysql: $ local_part}' \
 and domain = '$ {quote_mysql: $ domain}' \
 and users.on_forward = '1' \
 and users.domain_id = domains.domain_id}}} {1} {yes} {no}}
 data = $ {lookup mysql {select forward from users, domains \
 where localpart = '$ {quote_mysql: $ local_part}' \
 and domain = '$ {quote_mysql: $ domain}' \
 and users.domain_id = domains.domain_id \
 and on_forward = '1'}}
 # We explicitly make this condition NOT forward mailing list mail!
 ! Condition = $ {if and {{match {$ h_precedence:} {(i?) Junk}} \
 {Eq {$ {lookup mysql {select users.on_forward from users, domains \
 where localpart = '$ {quote_mysql: $ local_part}' \
 and domain = '$ {quote_mysql: $ domain}' \
 and users.on_forward = '1' \
 and users.domain_id = domains.domain_id}}} {1}}} {yes} {no}}

virtual_domains:
 driver = redirect
 allow_fail
 data = $ {lookup mysql {select users.smtp from users, domains \
 where localpart = '$ {quote_mysql: $ local_part}' \
 and domain = '$ {quote_mysql: $ domain}' \
 and domains.enabled = '1' \
 and users.enabled = '1' \
 and users.domain_id = domains.domain_id}}
# Local_part_suffix = - *
# local_part_suffix_optional
 retry_use_local_part
 file_transport = virtual_delivery
 reply_transport = address_reply
 pipe_transport = address_pipe

.include /usr/local/etc/exim/610.routers-groups.conf

virtual_domains_catchall:
 driver = redirect
 allow_fail
 data = $ {lookup mysql {select users.smtp from users, domains where localpart = '*' \
 and domain = '$ {quote_mysql: $ domain}' \
 and users.domain_id = domains.domain_id}}
 retry_use_local_part
 file_transport = virtual_delivery
 reply_transport = address_reply
 pipe_transport = address_pipe_catchall

virtual_domain_alias:
 driver = redirect
 allow_fail
 data = $ {lookup mysql {select concat ( '$ {quote_mysql: $ local_part} @', domains.domain) \
 from domains, domainalias where domainalias.alias = '$ {quote_mysql: $ domain}' \
 and domainalias.domain_id = domains.domain_id}}
 retry_use_local_part 

610.routers-groups.conf

 # Group - a list of users
#
# If the group is declared public, anyone from the Internet may write to her
# Otherwise, only members of the group
#
# If you are not a member of the non-public group writes in it, he will receive "550 Unknown user"
 virtual_dom_groups:
  driver = redirect
  allow_fail
  senders = $ {if eq {Y} {$ {lookup mysql {select g.is_public \
                                      from groups g, domains d \
                                      where d.enabled = '1' and d.domain = '$ {quote_mysql: $ domain}' and \
                                            d.domain_id = g.domain_id and g.enabled = '1' and \
                                            g.name = '$ {quote_mysql: $ local_part}'}}} \
                 {$ Sender_address} \
                 {$ {Lookup mysql {select u.username \
                                 from domains d, groups g, group_contents c, users u \
                                 where d.enabled = '1' and d.domain = '$ {quote_mysql: $ domain}' and \
                                       d.domain_id = g.domain_id and g.name = '$ {quote_mysql: $ local_part}' and \
                                       g.enabled = '1' and \
                                       g.is_public = 'N' and c.member_id = u.user_id and \
                                       d.domain_id = u.domain_id and u.enabled = '1' \
                                       and u.username = '$ {quote_mysql: $ sender_address}'}}}}
  data = $ {lookup mysql {\
            select u.username \
            from domains d, groups g, group_contents c, users u \
            where d.enabled = '1' and \
                  d.domain = '$ {quote_mysql: $ domain}' and \
                  d.domain_id = g.domain_id and \
                  g.enabled = '1' and \
                  g.id = c.group_id and \
                  c.member_id = u.user_id and \
                  d.domain_id = u.domain_id and \
                  u.enabled = '1' and \
                  g.name = '$ {quote_mysql: $ local_part}'}}
  local_part_suffix = - *
  local_part_suffix_optional
  retry_use_local_part
  reply_transport = address_reply
  pipe_transport = address_pipe 

700.transports.conf

 remote_smtp:
  driver = smtp
  interface = MY_IP

local_delivery:
  driver = appendfile
  file = / var / mail / $ local_part
  delivery_date_add
  envelope_to_add
  return_path_add
  group = mail
  user = $ local_part
  mode = 0660
  no_mode_fail_narrower

virtual_delivery:
  driver = appendfile
  envelope_to_add
  return_path_add
  mode = 0600
  maildir_format = true
  create_directory = true
  directory = $ {lookup mysql {select smtp from users, domains \
                where localpart = '$ {quote_mysql: $ local_part}' \
                and domain = '$ {quote_mysql: $ domain}' \
                and users.domain_id = domains.domain_id}}
  user = $ {lookup mysql {select users.uid from users, domains \
                where localpart = '$ {quote_mysql: $ local_part}' \
                and domain = '$ {quote_mysql: $ domain}' \
                and users.domain_id = domains.domain_id}}
  group = $ {lookup mysql {select users.gid from users, domains \
                where localpart = '$ {quote_mysql: $ local_part}' \
                and domain = '$ {quote_mysql: $ domain}' \
                and users.domain_id = domains.domain_id}}
  quota = $ {lookup mysql {select users.quota from users, domains \
                where localpart = '$ {quote_mysql: $ local_part}' \
                and domain = '$ {quote_mysql: $ domain}' \
                and users.domain_id = domains.domain_id} {$ {value} M}}
  quota_is_inclusive = false
  #quota_size_regex =, S = (\ d +):
  quota_warn_threshold = 75%
  maildir_use_size_file = false
  quota_warn_message = "To: $ local_part @ $ domain \ n \
                        Subject: Mailbox quota warning \ n \ n \
                        This message was automatically generated by the mail delivery software. \ N \ n \
                        You are now using over 75% of your allocated mail storage quota. \ N \ n \
                        If your mailbox fills completely, further incoming messages will be automatically \ n \
                        returned to their senders. \ n \ n \
                        Please take note of this and remove unwanted mail from your mailbox. \ N "

virtual_vacation_delivery:
  driver = autoreply
  from = "$ {local_part} @ $ {domain}"
  to = $ {sender_address}
  subject = "Autoreply from $ {local_part} @ $ {domain}"
  text = $ {lookup mysql {select vacation from users, domains \
                where domain = '$ {quote_mysql: $ domain}' \
                and localpart = '$ {quote_mysql: $ local_part}' \
                and users.domain_id = domains.domain_id}}

mailman_transport:
  driver = pipe
  command = MAILMAN_WRAP \
            '$ {If def: local_part_suffix \
                  {$ {Sg {$ local_part_suffix} {- (\\ w +) (\\ + *.)} {\ $ 1}}} \
                  {Post}} '\
            $ local_part is
  current_directory = MAILMAN_HOME
  home_directory = MAILMAN_HOME
  user = MAILMAN_USER
  group = MAILMAN_GROUP

address_pipe:
  driver = pipe
  return_output
  user = $ {lookup mysql {select users.uid from users, domains where localpart = '$ {quote_mysql: $ local_part}' and domain = '$ {quote_mysql: $ domain}' and users.domain_id = domains.domain_id}}
  group = $ {lookup mysql {select users.gid from users, domains where localpart = '$ {quote_mysql: $ local_part}' and domain = '$ {quote_mysql: $ domain}' and users.domain_id = domains.domain_id}}

address_pipe_catchall:
  driver = pipe
  return_output
  user = $ {lookup mysql {select users.uid from users, domains where localpart = '*' and domain = '$ {quote_mysql: $ domain}' and users.domain_id = domains.domain_id}}
  group = $ {lookup mysql {select users.gid from users, domains where localpart = '*' and domain = '$ {quote_mysql: $ domain}' and users.domain_id = domains.domain_id}}

address_pipe_local:
  driver = pipe
  return_output

address_file:
  driver = appendfile
  delivery_date_add
  envelope_to_add
  return_path_add

address_directory:
    driver = appendfile
    maildir_format

address_reply:
  driver = autoreply 

800.retry.conf

 begin retry

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

* * F, 2h, 15m; G, 16h, 1h, 1.5; F, 14d, 6h

900.authenticators.conf

 plain_login:
        driver = plaintext
        public_name = PLAIN
        server_condition = $ {lookup mysql {SELECT '1' FROM users \
                                WHERE username = '$ {quote_mysql: $ 2}' \
                                AND clear = '$ {quote_mysql: $ 3}'} {yes} {no}}
        server_set_id = $ 2

fixed_login:
        driver = plaintext
        public_name = LOGIN
        server_prompts = "Username ::: Password ::"
        server_condition = $ {lookup mysql {SELECT '1' FROM users \
                                WHERE username = '$ {quote_mysql: $ 1}' \
                                AND clear = '$ {quote_mysql: $ 2}'} {yes} {no}}
        server_set_id = $ 1

fixed_cram:
        driver = cram_md5
        public_name = CRAM-MD5
        server_secret = $ {lookup mysql {SELECT clear FROM users \
                                WHERE username = '$ {quote_mysql: $ 1}'} {$ value} fail}
        server_set_id = $ 1 

dialup_hosts

 # Dialup hosts
^ \. * Dsl \. *
^ \. * Dialup \. *
^ \. * Dialin \. *
^ \. * Pool \. *
^ \. * Peer \. *
^ \. * Dhcp \. *
^ \. * Dynamic \. *
^ \. * Cable \. *
^ \. * Ppp \. *

# Expressions for digit in hosts
^ \ D + [- \.] \ D + [- \.] \ D + [- \.]
^ \ D {5}

# By ded3axap
^ * ([1-9] +) \\ -. ([0-9] +) \\ - ([0-9] +) \\ - ([1-9] +) *.
^. * ([1-9] +). ([0-9] +). ([0-9] +). ([1-9] +). *
^. * Pool. *
^. * Dial. *
^. * Dyn. *
^. * Ppp. *
^. * Fbx. *
^. * Cable. *
^. * Dsl. *
^. * Dynamic. *
^. * Fibertel. *
^. * Broadband. *
^. * Hsd1. *
^. * Telecable. *
^. * Dhcp. *
^. * Kabel. *
^. * Client. *
^. * In-addr. *
^. * User. *
^. * Cpe. *
^. * Tampabay. *
^. * Phx1. *
^. * Static. *
^. * Rev. *
^. * Speedy. *
^. * Genericrev. *
^. * Cdma. *
^. * Catv. *
^. * Customer. *

# Optional - by ded3axap
^. * Rima-tde \\. Net
^. * Comcast \\. Net
^. * Pppoe \\. Mtu-net \\. Ru
^. * Proxad \\. Net
^. * Bezeqint \\. Net
^. * Arcor-ip \\. Net
^. * Novis \\. Pt
^. * Rr \\. Com
^. * Verizon \\. Net
^. * Chello \\. Nl
^. * Ono \\. Com
^. * T-dialin \\. Net
^. * Telenet \\. I am
^. * Virtua.com \\. Br
^. * Veloxzone.com \\. Br
^. * Tpnet \\. Pl
^. * Com \\. Au
^. * Asianet \\. Co \\. Th
^. * Interbusiness \\. It
^. * Webandnetworksolutions \\. Com
^. * Xtra.co \\. Nz
^. * Atlanticbb \\. Net
^. * Sinor \\. Ru
^. * Tiscali \\. Fr
^. * Wanadoo \\. Fr
^. * Pacbell \\. Net
^. * Prodigy \\. Net
^. * Charter \\. Com
^. * Barak-online \\. Net
^. * Qwest \\. Net
^. * Cm \\. Vtr \\. Net
^. * Link \\. Com \\. Eg
^. * T-ipconnect \\. De
^. * Mindspring \\. Com
^. * Telesp \\. Net \\. Br
^. * Home \\. Nl
^. * Cable \\. Ntl \\. Com
^. * Netvision \\. Net \\. Il
^. * Btcentralplus \\. Com
^. * Surewest \\. Net
^. * Anteldata \\. Net \\. Uy
^. * Mm \\. Pl
^. * Euskaltel \\. Es
^. * Satnet \\. Net
^. * Kabelbw \\. De
^. * Skylink \\. Ru
^. * Consumerpcinc \\. Com
^. * Yourhostingaccount \\. Com 

system-filter

 logfile / var / log / exim / mainlog

if $ acl_c_spam matches ^ \\ d +
then
 # Build a new subject line - if the spam
        # Check the contents of the variable to counter spam score.
 headers add "X-Spam-score: $ acl_m3"

 # Rihtuem headers
 if $ acl_m4 is above 0
        then
                headers add "Old-Subject: $ h_subject:"
                headers remove "Subject"
                headers add "Subject: * SPAM * [$ acl_m3 points] $ h_old-subject:"
                headers add "X-Spam: YES"
# Old header reserve, just in case
 #headers remove "Old-Subject"
        endif

        if $ acl_m6 is above 0
        then
                fail text "Scored too much spam points"
                logwrite "SPAM: Spam count = $ acl_m3"
        endif
endif 

whitelist-hosts

127.0.0.1/32 

whitelist-sender

support@microsoft.com 

Create a database, fill dump

 CREATE TABLE IF NOT EXISTS `blocklists` (
 `Block_id` int (10) unsigned NOT NULL auto_increment,
 `Domain_id` mediumint (8) unsigned NOT NULL default '0'
 `User_id` int (10) unsigned default NULL,
 `Blockhdr` varchar (192) NOT NULL default '',
 `Blockval` varchar (192) NOT NULL default '',
 `Color` varchar (8) NOT NULL default '',
 PRIMARY KEY ( `block_id`)
) TYPE = MyISAM;

CREATE TABLE IF NOT EXISTS `domainalias` (
 `Domain_id` mediumint (8) unsigned NOT NULL default '0'
 `Alias` varchar (64) default NULL
) TYPE = MyISAM;

CREATE TABLE IF NOT EXISTS `domains` (
 `Domain_id` mediumint (8) unsigned NOT NULL auto_increment,
 `Domain` varchar (64) NOT NULL default '',
 `Maildir` varchar (128) NOT NULL default '',
 `Uid` smallint (5) unsigned NOT NULL default '1002',
 `Gid` smallint (5) unsigned NOT NULL default '6',
 `Max_accounts` int (10) unsigned NOT NULL default '0'
 `Quotas` int (10) unsigned NOT NULL default '0'
 `Type` varchar (5) default NULL,
 `Avscan` tinyint (1) NOT NULL default '0'
 `Blocklists` tinyint (1) NOT NULL default '0'
 `Complexpass` tinyint (1) NOT NULL default '0'
 `Enabled` tinyint (1) NOT NULL default '1'
 `Mailinglists` tinyint (1) NOT NULL default '0'
 `Maxmsgsize` mediumint (8) unsigned NOT NULL default '0'
 `Pipe` tinyint (1) NOT NULL default '0'
 `Spamassassin` tinyint (1) NOT NULL default '0'
 `Greylist` tinyint (4) NOT NULL default '1'
 `Sa_tag` smallint (5) unsigned NOT NULL default '0'
 `Sa_refuse` smallint (5) unsigned NOT NULL default '0'
 PRIMARY KEY ( `domain_id`),
 UNIQUE KEY `domain` (` domain`),
 KEY `domain_id` (` domain_id`),
 KEY `domains` (` domain`)
) TYPE = MyISAM;

INSERT INTO `domains` (` domain_id`, `domain`,` maildir`, `uid`,` gid`, `max_accounts`,` quotas`, `type`,` avscan`, `blocklists`,` complexpass`, `enabled`,` mailinglists`, `maxmsgsize`,` pipe`, `spamassassin`,` greylist`, `sa_tag`,` sa_refuse`) VALUES
(1, 'admin', '', 1002, 6, 0, 0, NULL, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0);

CREATE TABLE IF NOT EXISTS `exim_greylist` (
 `Id` bigint (20) NOT NULL auto_increment,
 `Relay_ip` varchar (80) default NULL,
 `Block_expires` datetime NOT NULL default '0000-00-00 00:00:00',
 `Record_expires` datetime NOT NULL default '9999-12-31 23:59:59',
 `Create_time` datetime NOT NULL default '0000-00-00 00:00:00',
 `Type` enum ( 'AUTO', 'MANUAL') NOT NULL default 'MANUAL',
 `Passcount` bigint (20) NOT NULL default '0'
 `Blockcount` bigint (20) NOT NULL default '0'
 PRIMARY KEY ( `id`)
) TYPE = MyISAM;

CREATE TABLE IF NOT EXISTS `exim_greylist_log` (
 `Id` bigint (20) NOT NULL auto_increment,
 `Listid` bigint (20) NOT NULL default '0'
 `Timestamp` datetime NOT NULL default '0000-00-00 00:00:00',
 `Kind` enum ( 'deferred', 'accepted') NOT NULL default 'deferred',
 PRIMARY KEY ( `id`)
) TYPE = MyISAM;

CREATE TABLE IF NOT EXISTS `groups` (
 `Id` int (10) NOT NULL auto_increment,
 `Domain_id` mediumint (8) unsigned NOT NULL,
 `Name` varchar (64) NOT NULL,
 `Is_public` char (1) NOT NULL default 'Y',
 `Enabled` tinyint (1) NOT NULL default '1'
 PRIMARY KEY ( `id`),
 UNIQUE KEY `group_name` (` domain_id`, `name`)
) TYPE = MyISAM;

CREATE TABLE IF NOT EXISTS `group_contents` (
 `Group_id` int (10) NOT NULL,
 `Member_id` int (10) NOT NULL,
 PRIMARY KEY ( `group_id`,` member_id`)
) TYPE = MyISAM;

CREATE TABLE IF NOT EXISTS `list_top_level_domains` (
 `Unic_id` int (3) NOT NULL auto_increment,
 `Zone` varchar (15) binary NOT NULL default '',
 `Description` varchar (64) binary NOT NULL default '',
 PRIMARY KEY ( `unic_id`),
 UNIQUE KEY `zone` (` zone`)
) TYPE = MyISAM;

INSERT INTO `list_top_level_domains` (` unic_id`, `zone`,` description`) VALUES
(1, '.ac', 'Ascension Island'),
(2, '.ad', 'Andorra'),
(3, '.ae', 'United Arab Emirates'),
(4, '.af', 'Afghanistan'),
(5, '.ag', 'Antigua and Barbuda'),
(6, '.ai', 'Anguilla'),
(7, '.al', 'Albania'),
(8, '.am', 'Armenia'),
(9, '.an', 'Netherlands Antilles'),
(10, '.ao', 'Angola'),
(11, '.aq', 'Antarctica'),
(12, '.ar', 'Argentina'),
(13, '.as', 'American Samoa'),
(14, '.at', 'Austria'),
(15, '.au', 'Australia'),
(16, '.aw', 'Aruba'),
(17, '.ax', 'Aland Islands'),
(18, '.az', 'Azerbaijan'),
(19, '.ba', 'Bosnia and Herzegovina'),
(20, '.bb', 'Barbados'),
(21, '.bd', 'Bangladesh'),
(22, '.be', 'Belgium'),
(23, '.bf', 'Burkina Faso'),
(24, '.bg', 'Bulgaria'),
(25, '.bh', 'Bahrain'),
(26, '.bi', 'Burundi'),
(27, '.bj', 'Benin'),
(28, '.bm', 'Bermuda'),
(29, '.bn', 'Brunei Darussalam'),
(30, '.bo', 'Bolivia'),
(31, '.br', 'Brazil'),
(32, '.bs', 'Bahamas'),
(33, '.bt', 'Bhutan'),
(34, '.bv', 'Bouvet Island'),
(35, '.bw', 'Botswana'),
(36, '.by', 'Belarus'),
(37, '.bz', 'Belize'),
(38, '.ca', 'Canada'),
(39, '.cc', 'Cocos (Keeling) Islands'),
(40, '.cd', 'Congo, The Democratic Republic o'),
(41, '.cf', 'Central African Republic'),
(42, '.cg', 'Congo, Republic of'),
(43, '.ch', 'Switzerland'),
(44, '.ci', 'Cote d'' Ivoire '),
(45, '.ck', 'Cook Islands'),
(46, '.cl', 'Chile'),
(47, '.cm', 'Cameroon'),
(48, '.cn', 'China'),
(49, '.co', 'Colombia'),
(50, '.cr', 'Costa Rica'),
(51, '.cu', 'Cuba'),
(52, '.cv', 'Cape Verde'),
(53, '.cx', 'Christmas Island'),
(54, '.cy', 'Cyprus'),
(55, '.cz', 'Czech Republic'),
(56, '.de', 'Germany'),
(57, '.dj', 'Djibouti'),
(58, '.dk', 'Denmark'),
(59, '.dm', 'Dominica'),
(60, '.do', 'Dominican Republic'),
(61, '.dz', 'Algeria'),
(62, '.ec', 'Ecuador'),
(63, '.ee', 'Estonia'),
(64, '.eg', 'Egypt'),
(65, '.eh', 'Western Sahara'),
(66, '.er', 'Eritrea'),
(67, '.es', 'Spain'),
(68, '.et', 'Ethiopia'),
(69, '.eu', 'European Union'),
(70, '.fi', 'Finland'),
(71, '.fj', 'Fiji'),
(72, '.fk', '(Malvinas) Falkland Islands'),
(73, '.fm', 'Micronesia, Federated States of'),
(74, '.fo', 'Faroe Islands'),
(75, '.fr', 'France'),
(76, '.ga', 'Gabon'),
(77, '.gb', 'United Kingdom'),
(78, '.gd', 'Grenada'),
(79, '.ge', 'Georgia'),
(80, '.gf', 'French Guiana'),
(81, '.gg', 'Guernsey'),
(82, '.gh', 'Ghana'),
(83, '.gi', 'Gibraltar'),
(84, '.gl', 'Greenland'),
(85, '.gm', 'Gambia'),
(86, '.gn', 'Guinea'),
(87, '.gp', 'Guadeloupe'),
(88, '.gq', 'Equatorial Guinea'),
(89, '.gr', 'Greece'),
(90, '.gs', 'South Georgia and the South Sand'),
(91, '.gt', 'Guatemala'),
(92, '.gu', 'Guam'),
(93, '.gw', 'Guinea-Bissau'),
(94, '.gy', 'Guyana'),
(95, '.hk', 'Hong Kong'),
(96, '.hm', 'Heard and McDonald Islands'),
(97, '.hn', 'Honduras'),
(98, '.hr', 'Croatia / Hrvatska'),
(99, '.ht', 'Haiti'),
(100, '.hu', 'Hungary'),
(101, '.id', 'Indonesia'),
(102, '.ie', 'Ireland'),
(103, '.il', 'Israel'),
(104, '.im', 'Isle of Man'),
(105, '.in', 'India'),
(106, '.io', 'British Indian Ocean Territory'),
(107, '.iq', 'Iraq'),
(108, '.ir', 'Iran, Islamic Republic of'),
(109, '.is', 'Iceland'),
(110, '.it', 'Italy'),
(111, '.je', 'Jersey'),
(112, '.jm', 'Jamaica'),
(113, '.jo', 'Jordan'),
(114, '.jp', 'Japan'),
(115, '.ke', 'Kenya'),
(116, '.kg', 'Kyrgyzstan'),
(117, '.kh', 'Cambodia'),
(118, '.ki', 'Kiribati'),
(119, '.km', 'Comoros'),
(120, '.kn', 'Saint Kitts and Nevis'),
(121, '.kp', 'Korea, Democratic People''s Repub '),
(122, '.kr', 'Korea, Republic of'),
(123, '.kw', 'Kuwait'),
(124, '.ky', 'Cayman Islands'),
(125, '.kz', 'Kazakhstan'),
(126, '.la', 'Lao People''s Democratic Republic '),
(127, '.lb', 'Lebanon'),
(128, '.lc', 'Saint Lucia'),
(129, '.li', 'Liechtenstein'),
(130, '.lk', 'Sri Lanka'),
(131, '.lr', 'Liberia'),
(132, '.ls', 'Lesotho'),
(133, '.lt', 'Lithuania'),
(134, '.lu', 'Luxembourg'),
(135, '.lv', 'Latvia'),
(136, '.ly', 'Libyan Arab Jamahiriya'),
(137, '.ma', 'Morocco'),
(138, '.mc', 'Monaco'),
(139, '.md', 'Moldova, Republic of'),
(140, '.me', 'Montenegro'),
(141, '.mg', 'Madagascar'),
(142, '.mh', 'Marshall Islands'),
(143, '.mk', 'Macedonia, The Former Yugoslav R'),
(144, '.ml', 'Mali'),
(145, '.mm', 'Myanmar'),
(146, '.mn', 'Mongolia'),
(147, '.mo', 'Macao'),
(148, '.mp', 'Northern Mariana Islands'),
(149, '.mq', 'Martinique'),
(150, '.mr', 'Mauritania'),
(151, '.ms', 'Montserrat'),
(152, '.mt', 'Malta'),
(153, '.mu', 'Mauritius'),
(154, '.mv', 'Maldives'),
(155, '.mw', 'Malawi'),
(156, '.mx', 'Mexico'),
(157, '.my', 'Malaysia'),
(158, '.mz', 'Mozambique'),
(159, '.na', 'Namibia'),
(160, '.nc', 'New Caledonia'),
(161, '.ne', 'Niger'),
(162, '.nf', 'Norfolk Island'),
(163, '.ng', 'Nigeria'),
(164, '.ni', 'Nicaragua'),
(165, '.nl', 'Netherlands'),
(166, '.no', 'Norway'),
(167, '.np', 'Nepal'),
(168, '.nr', 'Nauru'),
(169, '.nu', 'Niue'),
(170, '.nz', 'New Zealand'),
(171, '.om', 'Oman'),
(172, '.pa', 'Panama'),
(173, '.pe', 'Peru'),
(174, '.pf', 'French Polynesia'),
(175, '.pg', 'Papua New Guinea'),
(176, '.ph', 'Philippines'),
(177, '.pk', 'Pakistan'),
(178, '.pl', 'Poland'),
(179, '.pm', 'Saint Pierre and Miquelon'),
(180, '.pn', 'Pitcairn Island'),
(181, '.pr', 'Puerto Rico'),
(182, '.ps', 'Palestinian Territory, Occupied'),
(183, '.pt', 'Portugal'),
(184, '.pw', 'Palau'),
(185, '.py', 'Paraguay'),
(186, '.qa', 'Qatar'),
(187, '.re', 'Reunion Island'),
(188, '.ro', 'Romania'),
(189, '.rs', 'Serbia'),
(190, '.ru', 'Russian Federation'),
(191, '.rw', 'Rwanda'),
(192, '.sa', 'Saudi Arabia'),
(193, '.sb', 'Solomon Islands'),
(194, '.sc', 'Seychelles'),
(195, '.sd', 'Sudan'),
(196, '.se', 'Sweden'),
(197, '.sg', 'Singapore'),
(198, '.sh', 'Saint Helena'),
(199, '.si', 'Slovenia'),
(200, '.sj', 'Svalbard and Jan Mayen Islands'),
(201, '.sk', 'Slovak Republic'),
(202, '.sl', 'Sierra Leone'),
(203, '.sm', 'San Marino'),
(204, '.sn', 'Senegal'),
(205, '.so', 'Somalia'),
(206, '.sr', 'Suriname'),
(207, '.st', 'Sao Tome and Principe'),
(208, '.su', 'Soviet Union (being phased out)'),
(209, '.sv', 'El Salvador'),
(210, '.sy', 'Syrian Arab Republic'),
(211, '.sz', 'Swaziland'),
(212, '.tc', 'Turks and Caicos Islands'),
(213, '.td', 'Chad'),
(214, '.tf', 'French Southern Territories'),
(215, '.tg', 'Togo'),
(216, '.th', 'Thailand'),
(217, '.tj', 'Tajikistan'),
(218, '.tk', 'Tokelau'),
(219, '.tl', 'Timor-Leste'),
(220, '.tm', 'Turkmenistan'),
(221, '.tn', 'Tunisia'),
(222, '.to', 'Tonga'),
(223, '.tp', 'East Timor'),
(224, '.tr', 'Turkey'),
(225, '.tt', 'Trinidad and Tobago'),
(226, '.tv', 'Tuvalu'),
(227, '.tw', 'Taiwan'),
(228, '.tz', 'Tanzania'),
(229, '.ua', 'Ukraine'),
(230, '.ug', 'Uganda'),
(231, '.uk', 'United Kingdom'),
(232, '.um', 'United States Minor Outlying Isl'),
(233, '.us', 'United States'),
(234, '.uy', 'Uruguay'),
(235, '.uz', 'Uzbekistan'),
(236, '.va', '(Vatican City State) Holy See'),
(237, '.vc', 'Saint Vincent and the Grenadines'),
(238, '.ve', 'Venezuela'),
(239, '.vg', 'Virgin Islands, British'),
(240, '.vi', 'Virgin Islands, U'),
(241, '.vn', 'Vietnam'),
(242, '.vu', 'Vanuatu'),
(243, '.wf', 'Wallis and Futuna Islands'),
(244, '.ws', 'Samoa'),
(245, '.ye', 'Yemen'),
(246, '.yt', 'Mayotte'),
(247, '.yu', 'Yugoslavia'),
(248, '.za', 'South Africa'),
(249, '.zm', 'Zambia'),
(250, '.zw', 'Zimbabwe'),
(251, '.com', 'operated by VeriSign Global Registry Services'),
(252, '.net', 'operated by VeriSign Global Registry Services'),
(253, '.biz', 'restricted to businesses'),
(254, '.org', 'intended to serve the noncommercial community, but all are elig'),
(255, '.aero', 'reserved for members of the air-transport industry'),
(256, '.cat', 'reserved for the Catalan linguistic and cultural community'),
(257, '.coop', 'reserved for cooperative associations'),
(258, '.info', 'operated by Afilias Limited'),
(259, '.jobs', 'reserved for human resource managers'),
(260, '.mobi', 'reserved for consumers and providers of mobile products and serv'),
(261, '.muzeum', 'reserved for museums'),
(262, '.name', 'reserved for individuals'),
(263, '.pro', 'restricted to credentialed professionals and related entities'),
(264, '.travel', 'reserved for entities whose primary area of ​​activity is in the t'),
(265, '.edu', 'reserved for postsecondary institutions accredited by an agency'),
(266, '.mil', 'reserved exclusively for the United States Military'),
(267, '.int', 'used only for registering organizations established by internati'),
(268, '.gov', 'reserved exclusively for the United States Government');

CREATE TABLE IF NOT EXISTS `users` (
 `User_id` int (10) unsigned NOT NULL auto_increment,
 `Domain_id` mediumint (8) unsigned NOT NULL default '0'
 `Localpart` varchar (192) NOT NULL default '',
 `Username` varchar (255) NOT NULL default '',
 `Clear` varchar (255) default NULL,
 `Crypt` varchar (48) default NULL,
 `Uid` smallint (5) unsigned NOT NULL default '1002',
 `Gid` smallint (5) unsigned NOT NULL default '6',
 `Smtp` text,
 `Pop` varchar (255) default NULL,
 `Type` enum ( 'local', 'alias', 'catch', 'fail', 'piped', 'admin', 'site') NOT NULL default 'local',
 `Admin` tinyint (1) NOT NULL default '0'
 `On_avscan` tinyint (1) NOT NULL default '0'
 `On_blocklist` tinyint (1) NOT NULL default '0'
 `On_complexpass` tinyint (1) NOT NULL default '0'
 `On_forward` tinyint (1) NOT NULL default '0'
 `On_piped` tinyint (1) NOT NULL default '0'
 `On_spamassassin` tinyint (1) NOT NULL default '0'
 `On_vacation` tinyint (1) NOT NULL default '0'
 `Enabled` tinyint (1) NOT NULL default '1'
 `Flags` varchar (16) default NULL,
 `Forward` varchar (255) default NULL,
 `Unseen` bool default '0'
 `Maxmsgsize` mediumint (8) unsigned NOT NULL default '0'
 `Quota` int (10) unsigned NOT NULL default '0'
 `Realname` varchar (255) default NULL,
 `Sa_tag` smallint (5) unsigned NOT NULL default '0'
 `Sa_refuse` smallint (5) unsigned NOT NULL default '0'
 `Tagline` varchar (255) default NULL,
 `Vacation` varchar (255) default NULL,
 PRIMARY KEY ( `user_id`),
 UNIQUE KEY `username` (` localpart`, `domain_id`),
 KEY `local` (` localpart`)
) TYPE = MyISAM;

INSERT INTO `users` (` user_id`, `domain_id`,` localpart`, `username`,` clear`, `crypt`,` uid`, `gid`,` smtp`, `pop`,` type`, `admin`,` on_avscan`, `on_blocklist`,` on_complexpass`, `on_forward`,` on_piped`, `on_spamassassin`,` on_vacation`, `enabled`,` flags`, `forward`,` maxmsgsize`, `quota `,` realname`, `sa_tag`,` sa_refuse`, `tagline`,` vacation`) VALUES
(1, 1, 'siteadmin', 'siteadmin', '123465', MD5 ( '123465'), 65535, 65535, '', '', 'site', 1, 0, 0, 0, 0, 0, 0, 0, 1, NULL, NULL, 0, 0, 'SiteAdmin', 60, 600, NULL, NULL); 

The dump is necessary to pre-correct user and group values, which will work under the Exim (we had them written down, it came 1002, and 6, respectively). Stop the Sendmail, we correct /etc/rc.conf:

# /etc/rc.d/sendmail Stop
# Echo sendmail_enable = \ "NONE \" >> /etc/rc.conf
# Echo exim_enable = \ "YES \" >> /etc/rc.conf 

References

Exim4 Config File (Complete)

# ShareWiz Exim4 Config File

# SMTP Banner.
smtp_banner = ShareWiz Email Server
#smtp_banner="$primary_hostname Microsoft ESMTP MAIL Service, Version: 5.0.2195.6713 ready at $tod_full"
#received_header_text = 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}}${if def:sender_address {(envelope-from < $sender_address>)\n\t}}id $message_exim_id${if def:received_for {\n\tfor $received_for}}

# Primary host.
primary_hostname = sharewiz.net

# The ports to listen on.
# daemon_smtp_ports = smtp : smtps : submission.
daemon_smtp_ports = 25 : 465 : 587


# MySQL config settings.
MYSQL_SERVER=127.0.0.1
MYSQL_DB=email_accounts
MYSQL_USER=email
MYSQL_PASSWORD=Pa550513w0rd
hide mysql_servers = MYSQL_SERVER/MYSQL_DB/MYSQL_USER/MYSQL_PASSWORD


# local and relay to domains settings from mysql.
#domainlist local_domains = @:localhost:dsearch;/etc/exim4/virtual:${lookup mysql{SELECT fqdn AS domain FROM domains WHERE fqdn='${quote_mysql:$domain}' AND type='local' AND active=1}}
domainlist local_domains = ${lookup mysql{SELECT fqdn AS domain FROM domains WHERE fqdn='${quote_mysql:$domain}' AND type='local' AND active=1}}
domainlist relay_to_domains = ${lookup mysql{SELECT fqdn AS domain FROM domains WHERE fqdn='${quote_mysql:$domain}' AND type='relay' AND active=1}}
#domainlist relay_from_hosts = ${lookup mysql{SELECT fqdn AS domain FROM domains WHERE fqdn='${quote_mysql:$domain}' AND type='relay' AND active=1}}

# If exim is used localy in batch mode (exim4 -bs) then "$host" is empty, the ": :" adds the empty string.
#hostlist   own_hosts = 127.0.0.1 : : 192.168.1.2 : 5.42.134.35
hostlist   relay_from_hosts = 127.0.0.1
#domainlist local_domains = @ : sharewiz.net : mail.sharewiz.net
#domainlist public_domains = sharewiz.net
domainlist relay_to_domains =


# SpamAssassin.
# For sa-exim.
local_scan_path = /usr/lib/exim4/local_scan/sa-exim.so


# Anti-virus.
av_scanner = clamd:/var/run/clamav/clamd.ctl
spamd_address = 127.0.0.1 783


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 = *

rfc1413_hosts = !192.168.1.0/24
rfc1413_query_timeout = 5s

# Bounce handling
ignore_bounce_errors_after = 2d
timeout_frozen_after = 7d
#freeze_tell = postmaster

# Stop rogue spam bots from trashing your machine.
smtp_accept_max_nonmail = 30
smtp_max_unknown_commands = 1

# Allow anyone to authenticate (optional, but good).
auth_advertise_hosts = *

# Mandatory to use  "verify = helo".
helo_try_verify_hosts = !+own_hosts

# Greylisting
# Seconds after a greylisted message is accepted (10 minutes).
GREYLIST_TIMEOUT = ${eval:60*10}
# Integer spam score (times 10) threshold to activate selective greylisting (1.0 points).
GREYLIST_SPAM_THRESHOLD = ${eval:10*1}
# Messages bigger than this aren't spam-scanned.
SPAM_FILESIZE_LIMIT = 1M
# Messages bigger than this aren't virus-scanned.
VIRUS_FILESIZE_LIMIT = 32M

# Message size limit.
# The default if this is unset is 50 MB.
#message_size_limit = MESSAGE_SIZE_LIMIT


# Define spool directory
spool_directory = /var/spool/exim4


# Logging.
log_selector = +all -subject -arguments

#log_selector = +address_rewrite +all_parents +arguments +connection_reject +delay_delivery +delivery_size +dnslist_defer +incoming_interface +incoming_port +lost_incoming_connection +queue_run +received_sender +received_recipients +retry_defer +sender_on_delivery +size_reject +skip_delivery +smtp_confirmation +smtp_connection +smtp_protocol_error +smtp_syntax_error +subject +tls_cipher +tls_peerdn


# TLS setings.
tls_on_connect_ports = 465
# Defines what hosts to 'advertise' STARTTLS functionality to. The
# default, *, will advertise to all hosts that connect with EHLO.
tls_advertise_hosts = *
tls_certificate = /etc/exim4/mail.crt
tls_privatekey = /etc/exim4/mail.key

#tls_verify_certificates = ${if exists{/etc/ssl/certs/ca-certificates.crt}\
#                                     {/etc/ssl/certs/ca-certificates.crt}\
#                                     {/dev/null}}
#tls_verify_hosts =

# ACLs.
acl_smtp_mail = acl_check_mail
acl_smtp_rcpt = acl_check_rcpt
acl_smtp_mail = acl_check_sender
acl_smtp_connect = acl_check_host
acl_smtp_data = acl_check_data
acl_smtp_helo = acl_check_helo


# Macro to call the mysql function that returns 'yes' if the mail should be deferred:
GREYLIST_DEFER = SELECT greylist_defer('${quote_mysql:$sender_address_domain}', '${quote_mysql:$sender_host_address}')

The SQL INSERT should be modified to read:

     INSERT INTO greylist (sender_host_ip, from_domain, first_received, last_received, rcpt_count)
         VALUES (sender_ip, sender_domain, NOW(), NOW(), 1);
······

The SQL UPDATE should be modified to read:

      UPDATE greylist SET last_received = NOW(), rcpt_count = rcpt_count + 1
          WHERE from_domain = sender_domain AND sender_host_ip = sender_ip;
······



# log query for gathering statistics about locally delivered mail
MYSQL_LOG=INSERT INTO `spamlog` ( `ID`, `MessageID`, `SenderIP`, `SenderPort`, `SenderHostname`, `SenderHelo`, `SenderAddress`, `RecipientAddress`, `Username`, `Domain`, `LoadAverage`, `SpamScore`, `MessageSize`, `BodySize`, `MessageLines`, `BodyLines`, `ReceivedHeaders`, `ReceivedProtocol`, `Cipher`, `Authenticated`, `SenderVerify`, `Age`, `TimeStamp`) \
»·»·VALUES( '${quote_mysql:$message_exim_id}', \
»·»·»·'${quote_mysql:$header_Message-ID:}', \
»·»·»·'${quote_mysql:$sender_host_address}', \
»·»·»·'${quote_host_port}', \
»·»·»·'${quote_mysql:$sender_host_name}', \
»·»·»·'${quote_mysql:$sender_helo_name}', \
»·»·»·'${quote_mysql:$sender_address}', \
»·»·»·CONCAT('${quote_mysql:$original_local_part}','@','${quote_mysql:$original_domain}'), \
»·»·»·'${quote_mysql:$local_part}', '${quote_mysql:$domain}', \
»·»·»·'${quote_mysql:$load_average}/1000', \
»·»·»·'${quote_mysql:$header_X-Spam-Score:}', \
»·»·»·'${quote_mysql:$message_size}', \
»·»·»·'${quote_mysql:$message_body_size}', \
»·»·»·'${quote_mysql:$message_linecount}', \
»·»·»·'${quote_mysql:$body_linecount}', \
»·»·»·'${quote_mysql:$received_count}', \
»·»·»·'${quote_mysql:$received_protocol}', \
»·»·»·'${quote_mysql:$tls_cipher}', \
»·»·»·'${quote_mysql:$authenticated_id}', \
»·»·»·'${quote_mysql:$header_X-Sender-Verify:}', \
»·»·»·'${quote_mysql:$message_age}', \
»·»·»·NOW() )

/*
LOG = INSERT INTO LOG (d, sender, recipient, size, shost) values \
(Now (), '$ {quote_mysql: $ sender_address}', \
'$ {Quote_mysql: $ recipients}', $ message_size, '$ {quote_mysql: $ sender_host_address}')

acl_smtp_rcpt:
warn domains =! + local_domains
set acl_m1 = 1

acl_smtp_data:
warn condition = $ {if eq {$ acl_m1} {1}}
set acl_m19 = $ {lookup mysql {LOG}}
*/


event_action = ${if eq {msg:delivery}{$event_name} \
{${lookup pgsql {SELECT * FROM record_Delivery( \
    '${quote_pgsql:$sender_address_domain}',\
    '${quote_pgsql:${lc:$sender_address_local_part}}', \
    '${quote_pgsql:$domain}', \
    '${quote_pgsql:${lc:$local_part}}', \
    '${quote_pgsql:$host_address}', \
    '${quote_pgsql:${lc:$host}}', \
    '${quote_pgsql:$message_exim_id}')}} \
} {}}





begin acl

acl_check_mail:

  # Deny if not HELO is given.
  deny
    message = no HELO given before MAIL command.
    condition = ${if def:sender_helo_name {no}{yes}}

  # Accept by default.
  accept


acl_check_rcpt:

  # Block certain wellknown exploits, Deny for local domains if
  # local parts begin with a dot or contain @ % ! / |
  deny    message       = Restricted characters in address.
          domains       = +local_domains
          #local_parts   = ^[.] : ^.*[@%!/|]
          local_parts   = ^[.] : ^.*[@%!/|`#&?]


  # Allow local users to send outgoing messages using slashes
  # and vertical bars in their local parts.
  # Block outgoing local parts that begin with a dot, slash, or vertical
  # bar but allows them within the local part.
  # The sequence \..\ is barred. The usage of @ % and ! is barred as
  # before. The motivation is to prevent your users (or their virii)
  # from mounting certain kinds of attacks on remote sites.
  deny    message       = Restricted characters in address.
          domains       = !+local_domains
          #local_parts   = ^[./|] : ^.*[@%!] : ^.*/\\.\\./
          local_parts   = ^[./|] : ^.*[@%!`#&?] : ^.*/\\.\\./


  # Accept if the source is local SMTP (i.e. not over TCP/IP).
  # Test for this by testing for an empty sending host field.
  accept  hosts = :
          control = dkim_disable_verify



  # Accept mail to postmaster in any local domain, regardless of source.
  accept  local_parts = postmaster
          domains     = +local_domains
          #domains = +local_domains : +relay_to_domains

  # Accept mail to abuse in any local domain, regardless of source.
  accept  local_parts = abuse
          domains     = +local_domains
          #domains = +local_domains : +relay_to_domains

  # Accept mail to hostmaster in any local domain, regardless of source.
  accept  local_parts = hostmaster
          domains     = +local_domains




  # Local source whitelist.
  [todo]
  # Sender domains whitelist.
  # Accept if sender domain is in whitelist.
  accept  sender_domains = +whitelist_domains

  [todo]
  # Sender hosts whitelist.
  # Accept if sender host is in whitelist.
  accept  hosts = +whitelist_hosts
  accept  hosts = +whitelist_hosts_ip

  [todo]
  # Envelope senders whitelist.
  # Accept if envelope sender is in whitelist
  accept  senders = +whitelist_senders


  # Greylist.
  # Temporary reject message, if already greylisted and entry hasn't expired yet.
  # Authenticated users skip this.
  defer message         = Your Message is currently still greylisted!  Please try again later.
        log_message     = message from ${sender_address} over [${sender_host_address}] is still GreyListed.
        !authenticated  = *
        # true, if triple is in db and not yet GREYLIST_TIMEOUT seconds since first seen
        # false, else (older or not in db)
        condition       = ${if >={GREYLIST_TIMEOUT}{${lookup mysql{\
                            SELECT (UNIX_TIMESTAMP()-MAX(first_seen)) AS QueueTime \·
                            FROM greylist \
                            WHERE sender_ip = '${quote_mysql:$sender_host_address}' \·
                            AND sender_address = '${quote_mysql:$sender_address}' \
                          }{$value}{${eval:GREYLIST_TIMEOUT+1}}}}{true}{false}}


  # deny, if foreign, unauthenticated connection claims to come from a local domain.
  deny  message         = Sender claims to have a local address, but is neither authenticated nor relayed (try using SMTP-AUTH!).
        log_message     = Forged Sender address (claims to be local user [${sender_address}], but isn't authenticated).
        !hosts          = +relay_from_hosts
        !authenticated  = *
        condition       = ${if match_domain{$sender_address_domain}{+local_domains}}

  warn  message         = You cannot be localhost.localdomain in the internet.
        log_message     = HELO is faked as localhost.localdomain.
        condition       = ${if match{$sender_helo_name}{\Nlocalhost\.localdomain\N}}

  # We're doing HELO checks here, because we can't add headers in acl_smtp_helo.
  warn  message         = X-Invalid-HELO: HELO is IP only (See RFC2821 4.1.3)
        log_message     = HELO ($sender_helo_name) is IP only (See RFC2821 4.1.3)
        condition       = ${if isip{$sender_helo_name}}

  warn  message         = X-Invalid-HELO: HELO is no FQDN (contains no dot) (See RFC2821 4.1.1.1)
        log_message     = HELO ($sender_helo_name) is no FQDN (contains no dot) (See RFC2821 4.1.1.1)
        # Required because "[IPv6:<address>]" will have no .s
        condition       = ${if match{$sender_helo_name}{\N^\[\N}{no}{yes}}
        condition       = ${if match{$sender_helo_name}{\N\.\N}{no}{yes}}

  warn  message         = X-Invalid-HELO: HELO is no FQDN (ends in dot) (See RFC2821 4.1.1.1)
        log_message     = HELO ($sender_helo_name) is no FQDN (ends in dot) (See RFC2821 4.1.1.1)
        condition       = ${if match{$sender_helo_name}{\N\.$\N}}

  warn  message         = X-Invalid-HELO: HELO is no FQDN (contains double dot) (See RFC2821 4.1.1.1)
        log_message     = HELO ($sender_helo_name) is no FQDN (contains double dot) (See RFC2821 4.1.1.1)
        condition       = ${if match{$sender_helo_name}{\N\.\.\N}}

  warn  message         = X-Invalid-HELO: Host impersonating [$primary_hostname]
        log_message     = HELO ($sender_helo_name) impersonating [$primary_hostname]
        condition       = ${if match{$sender_helo_name}{$primary_hostname}{yes}{no}}
        # TODO: Don't generate loopback.

  warn  message         = X-Invalid-HELO: $interface_address is _my_ address
        log_message     = HELO ($sender_helo_name) uses _my_ address ($interface_address)
        # [own IP] or even without brackets as HELO
        condition       = ${if or{{\
                                eq{[$interface_address]}{$sender_helo_name}\
                          }{\···
                                eq{$interface_address}{$sender_helo_name}\
                          }}}

  warn  message         = X-Invalid-HELO: no HELO·
        log_message     = no HELO ($sender_helo_name)
        condition       = ${if !def:sender_helo_name}


  # Deny so-called "legal" spammers".
  deny message = Email blocked by RBL.
       # Only for domains that do want to be tested against RBLs.
       domains = +use_rbl_domains
       sender_domains = +blacklist_domains

  # Deny using hostname in bad_sender_hosts blacklist.
  deny message = Email blocked by BSHL.
       # Only for domains that do want to be tested against RBLs.
       domains = +use_rbl_domains
       hosts = +bad_sender_hosts

  # Deny using IP in bad_sender_hosts blacklist.
  deny message = Email blocked by BSHL.
       # Only for domains that do want to be tested against RBLs.
       domains = +use_rbl_domains
       hosts = +bad_sender_hosts_ip

  # Deny using email address in blacklist_senders.
  deny message = Email blocked by BSAL.
       domains = +use_rbl_domains
       senders = +blacklist_senders


  # Deny using .spamhaus.
  deny message = Email blocked by SPAMHAUS.
       # Only for domains that do want to be tested against RBLs.
       domains = +use_rbl_domains
       dnslists = sbl.spamhaus.org

  # Deny using ordb.
#  deny message = Email blocked by ORDB.
#       # only for domains that do want to be tested against RBLs
#       domains = +use_rbl_domains
#       dnslists = relays.ordb.org

  # Deny using sorbs smtp list.
  deny message = Email blocked by SORBS.
       # Only for domains that do want to be tested against RBLs.
       domains = +use_rbl_domains
       dnslists = dnsbl.sorbs.net=127.0.0.5

  # Next deny stuff from more "fuzzy" blacklists
  # but do bypass all checking for whitelisted host names
  # and for authenticated users

  # Deny using spamcop.
  deny message = Email blocked by SPAMCOP.
       hosts = !+relay_hosts
       domains = +use_rbl_domains
       !authenticated = *
       dnslists = bl.spamcop.net

  # Deny using njabl.
  deny message = Email blocked by NJABL.
       hosts = !+relay_hosts
       domains = +use_rbl_domains
       !authenticated = *
       dnslists = dnsbl.njabl.org

  # Deny using cbl.
  deny message = Email blocked by CBL.
       hosts = !+relay_hosts
       domains = +use_rbl_domains
       !authenticated = *
       dnslists = cbl.abuseat.org

  # Deny using all other sorbs ip-based blocklist besides smtp list.
  deny message = Email blocked by SORBS.
       hosts = !+relay_hosts
       domains = +use_rbl_domains
       !authenticated = *
       dnslists = dnsbl.sorbs.net!=127.0.0.6

  # Deny using sorbs name based list.
  deny message = Email blocked by SORBS.
       domains = +use_rbl_domains
       # rhsbl list is name based.
       dnslists = rhsbl.sorbs.net/$sender_address_domain


  drop message       = REJECTED because $sender_host_address is in a black list spamhaus.org
       dnslists      = zen.spamhaus.org
  drop message       = REJECTED because $sender_host_address is in a black list at $dnslist_domain\n$dnslist_text
       dnslists      = bl.spamcop.net
  drop message       = REJECTED because $sender_host_address is in a black list at $dnslist_domain\n$dnslist_text
       dnslists      = dnsbl.sorbs.net



  # Accept if address is in a local domain as long as recipient can be verified.
  accept  domains = +local_domains
          endpass
          message = "Unknown User"
          verify = recipient


  [todo]
  # Restrict port 587 to authenticated users only.
  # See also daemon_smtp_ports above.
  accept  hosts = +auth_relay_hosts
          condition = ${if eq {$interface_port}{587} {yes}{no}}
          endpass
          message = relay not permitted, authentication required.
          authenticated = *


  # Accept if address is in a domain for which we relay as long as recipient
  # can be verified
  accept  domains = +relay_domains
          endpass
          verify=recipient

  # Accept if the message comes from one of the hosts for which we are an
  # outgoing relay.
  accept
    hosts = +relay_from_hosts
    control = submission/sender_retain

  # Accept if message comes for a host for which we are an outgoing relay
  # recipient verification is omitted because many MUA clients don't cope
  # well with SMTP error responses. If you are actually relaying from MTAs
  # then you should probably add recipient verify here.
  accept  hosts = +relay_hosts
  accept  hosts = +auth_relay_hosts
          endpass
          message = authentication required
          authenticated = *
  deny    message = relay not permitted

  [todo]
  # Accept anything from authenticated users.
  accept authenticated = *

  # Defer if GREYLIST_DEFER is 'yes'.
  defer   condition = ${lookup mysql{GREYLIST_DEFER}}
          message   = Now greylisted - please try again in ten minutes.


  # To have proper return-path and envelopes.
  accept hosts         = +relay_from_hosts
#        control       = submission
        control       = submission/domain=

  accept authenticated = *
#        control       = submission
         #control       = submission/domain=
         control       = submission/sender_retain/domain=

  # Deny unless the sender address can be verified.
  #
  # This is disabled by default so that DNSless systems don't break. If
  # your system can do DNS lookups without delay or cost, you might want
  # to enable this feature.
#  deny
#    message = Sender verification failed
#    !acl = acl_local_deny_exceptions
#    !verify = sender

  # Verify senders.
  #
  # Sender verification denies unless sender address can be verified:
  # If you want to require sender verification, i.e., that the sending
  # address is routable and mail can be delivered to it, then
  # uncomment the next line. If you do not want to require sender
  # verification, leave the line commented out.
#  require verify        = sender
  #
  # Embed a header flag, if sender callout verification fails.·
  # This may lead to rejection in future, or give a hint to bayes filter.
  # The next two directives have complement verify conditions, so only one matches.
  warn message      = X-Sender-Verify: FAILED ($sender_verify_failure)
       log_message  = Sender ($sender_address) could not be verified using callout: $acl_verify_message ($sender_verify_failure)
       !verify      = sender/callout=10s,random

  warn message      = X-Sender-Verify: SUCCEEDED (sender exists & accepts mail)
       verify       = sender/callout=10s,random


  require message = relay not permitted
          domains = +local_domains : +relay_to_domains : +exdomains

  # Reject invalid recipients.
  require verify = recipient


  # Add here DNS blacklist checks.





  # Default at end of acl causes a "deny", but line below will give
  # an explicit error message:
  deny    message = relay not permitted

  # Enable this line and comment out line above to default to allow·
  # any message reaching here to be accepted.
  #accept


acl_check_data:

  # If there is a windows executable as attachment then we reject.
  #deny    message = This message contains an attachment of a type which we do not accept ($found_extension)
  #        demime = bat:btm:cmd:com:cpl:dll:exe:lnk:msi:pif:prf:reg:scr:vbs:url

  # Reject messages that have serious MIME errors.
  # This calls the demime condition again, but will return cached results.
  #deny message = Serious MIME defect detected ($demime_reason).
  #     demime = *
  #     condition = ${if >{$demime_errorlevel}{2}{1}{0}}


  # clamav
  #deny    message = This message contains a virus or other harmful content ($malware_name).
  #        demime = *·
  #        malware = *

  deny    malware    = *
          message    = This message contains a virus ($malware_name).


  # Deny if the message contains a virus. Before enabling this check, you
  # must install a virus scanner and set the av_scanner option above.
#  deny  message         = This message contains a virus ($malware_name) and is rejected.
#        log_message     = rejected VIRUS ($malware_name) from $sender_address to $recipients (ClamAV)
#        set acl_m0      = clamd:/var/run/clamav/clamd.sock
#        condition       = ${if < {$message_size}{VIRUS_FILESIZE_LIMIT}}
#        demime          = *
#        malware         = *

# 2009-08-01   disable f-prot for now, since its usage has changed
#                                  this is the place to configure additional virus scanning engines.
#                                  just copy and modify this block (read exim doc for available scanners)
#  deny message         = This message contains a virus ($malware_name) and is rejected.
#       log_message     = rejected VIRUS ($malware_name) from $sender_address to $recipients (F-Prot)
#       set acl_m0      = cmdline:/usr/bin/f-prot -ai -archive -collect -dumb -packed %s:Infection. :Infection. (.+)\$
#       condition       = ${if < {$message_size}{VIRUS_FILESIZE_LIMIT}}
#       demime          = *
#       malware         = *



  # Reject executeable double extensions in archives.
  deny  demime         = zip:rar:arj:tar:tgz:gz:bz2
        condition      = ${run{/etc/exim/scan_archive.sh $message_exim_id ${lc:$found_extension}}{no}{yes}}
        message        = This message contains an unwanted binary Attachment in ${uc:$found_extension} file using a double extension
        log_message    = ${uc:$found_extension} archive contains potential dangerous double extension.
        delay          = 15s


  # Add headers to all messages (:true).·
  # Before enabling this you must install SpamAssassin.·
  # You may also need to set the spamd_address option above.
  warn  message         = X-Spam-Score: $spam_score\n\
                          X-Spam-Score-Int: $spam_score_int\n\
                          X-Spam-Bar: $spam_bar\n\
                          X-Spam-Report: $spam_report
        !authenticated  = *
        condition       = ${if < {$message_size}{SPAM_FILESIZE_LIMIT}}
        spam            = spamassassin:true


  # Temp. reject messages that seem to have timeouts during spam-scan.
  defer message         = Temporary error while spam-scanning. Please try again later.
        log_message     = message temporarily rejected, because of spam-scan error (maybe timeout)
        !authenticated  = *
        condition       = ${if < {$message_size}{SPAM_FILESIZE_LIMIT}}
        condition       = ${if !def:spam_score}

  # Reject spam messages with score over 10+2*max_score_from_db (fallback=15 if mysql fails), using an extra condition.
  deny  message         = This message is classified as SPAM and therefore rejected. You scored $spam_score points. Congratulations!
        #spam           = spamassassin:true
        !authenticated  = *
        condition       = ${if >={$spam_score_int}{${lookup mysql{\
                                SELECT ((max(spam_threshold)*2+10)*10) AS spam_reject_threshold \
                                FROM user \
                                WHERE SMTP_allowed='YES' \
                          }{$value}{15}}}{true}{false}}



  ## spamassassin, spams are never big and spamassassin can die on big emails, so we
  ## limit its use under 500k.
  accept  condition = ${if >={$message_size}{500k}{yes}{no}}
          add_header = X-Spam-Note: SpamAssassin run bypassed due to message size
          warn    message = X-SA-Score: $spam_score·
                 spam = nobody:true·
          warn    message = X-SA-Report: $spam_report·
                  spam = nobody:true
                  condition = ${if >{$spam_score_int}{0}{true}{false}}
          warn    message = X-SA-Status: Yes·
                  spam = nobody:true
                  condition = ${if >{$spam_score_int}{50}{true}{false}}
          deny    message = This message scored $spam_score spam points.
                  spam = nobody:true
                  condition = ${if >{$spam_score_int}{70}{true}{false}}



  # Temporary reject message for greylisting, if integer spamscore is above GREYLIST_SPAM_THRESHOLD and the message (sender address + IP) is seen for the first time.
  # Authenticated users skip this.
  defer message         = Your Message will be greylisted! Please try again in GREYLIST_TIMEOUT seconds.
        log_message           = message from ${sender_address} over [${sender_host_address}] will be GreyListed as it scores $spam_score spam points
        !authenticated        = *
        condition             = ${if >={$spam_score_int}{GREYLIST_SPAM_THRESHOLD}{true}{false}}
        # false, if triple is in db (at this point if it's in the timeout has expired)
        # true, if not
        condition             = ${lookup mysql{ \
                                SELECT MAX(first_seen) \
                                  FROM greylist \
                                  WHERE SenderIP = '${quote_mysql:$sender_host_address}' \
                                  AND SenderAddress = '${quote_mysql:$sender_address}' \
                                }{false}{true}}
        # insert triple into database (which should succeed)
        condition             = ${lookup mysql{ \
                                  INSERT INTO greylist ( SenderIP, SenderAddress, first_seen ) \
                                  VALUES ( '${quote_mysql:$sender_host_address}', '${quote_mysql:$sender_address}', UNIX_TIMESTAMP() ) \
                                }{$value}fail}

  # Log, if mail successfully passed greylisting.
  warn  message         = X-GreyList: Message successfully passed GreyListing after $acl_m0 seconds.
        log_message     = message from ${sender_address} over [${sender_host_address}] with HELO ($sender_helo_name) successfully passed GreyListing after $acl_m0 seconds and scores $spam_score spam points
        !authenticated  = *
        # true, if triple is in db (at this point if it's in the timeout has expired)
        # false, if not
        condition       = ${lookup mysql{ \
                                SELECT MAX(first_seen) \
                                FROM greylist \
                                WHERE SenderIP = '${quote_mysql:$sender_host_address}' \
                                AND SenderAddress = '${quote_mysql:$sender_address}' \
                          }{true}{false}}
        set     acl_m0  = ${eval:$tod_epoch-${lookup mysql{ \
                                SELECT MAX(first_seen) \
                                FROM greylist \
                                WHERE SenderIP = '${quote_mysql:$sender_host_address}' \
                                AND SenderAddress = '${quote_mysql:$sender_address}' \
                          }{$value}}}

  # save exim version and current date in header
  warn  message         = X-Exim-Version: $version_number (build at $compile_date)\n\
                          X-Date: $tod_log\n\
                          X-Connected-IP: $sender_host_address:$sender_host_port

  # save additional information in header
  warn message          = X-Message-Linecount: $message_linecount\n\··
                          X-Body-Linecount: $body_linecount\n\
                          X-Message-Size: $message_size\n\
                          X-Body-Size: $message_body_size
                          #X-Received-Count: $received_count\n\
                          #X-Recipient-Count: $recipients_count\n\
                          #X-Local-Recipient-Count: $rcpt_count\n\
                          #X-Local-Recipient-Defer-Count: $rcpt_defer_count\n\
                          #X-Local-Recipient-Fail-Count: $rcpt_fail_count
  warn log_message = DEBUG  load_avgx1000: $load_average  spam_score: $spam_score  message_size: $message_size


#  deny message = contains blacklisted regex ($regex_match_string)
#       regex = [Mm]ortgage : URGENT BUSINESS PROPOSAL

  # Accept by default.
  accept





begin routers

dnslookup:
  driver = dnslookup
  domains = ! +local_domains : ! +exdomains
  transport = remote_smtp
  ignore_target_hosts = 0.0.0.0 : 127.0.0.0/8
  no_more


#system_aliases:

#  driver = redirect
#  allow_fail
#  allow_defer
#  data = ${lookup mysql{select goto from alias where address = '${local_part}'}{$value}}
#  file_transport = address_file
#  pipe_transport = address_pipe

system_aliases:
  driver = redirect
  allow_fail·
  allow_defer
  data = ${lookup mysql{SELECT aliases.goto AS goto FROM domains,aliases WHERE \
                (aliases.local_part='${quote_mysql:$local_part}' OR aliases.local_part='@') AND \
                aliases.active=1 AND \
                aliases.domain_id=domains.id AND \
                domains.fqdn='${quote_mysql:$domain}' AND \
                domains.active=1}}


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


localuser_spam_flag:
  driver = accept
  condition = ${lookup mysql{SELECT COUNT(account_id) FROM account WHERE username = '${local_part}'}{$value}}
  condition = ${if eq {$h_X-Spam-Flag}{YES} {1}{0}}
  transport = local_delivery_spam


localuser:
  driver = accept
  condition = ${lookup mysql{SELECT COUNT(account_id) FROM account WHERE username = '${local_part}'}{$value}}
  transport = local_delivery
  cannot_route_message = Unknown user


dovecot_user:
  driver = accept
  condition = ${lookup mysql{SELECT CONCAT(mailboxes.local_part,'@',domains.fqdn) AS goto FROM domains,mailboxes WHERE \
                mailboxes.local_part='${quote_mysql:$local_part}' AND \
                mailboxes.active=1 AND \
                mailboxes.domain_id=domains.id AND \
                domains.fqdn='${quote_mysql:$domain}' AND \
                domains.active=1}{yes}{no}}
  transport = dovecot_delivery



# Out-of-office.
user_vacation:
  driver = accept
  domains = ${lookup mysql{SELECT domains.fqdn AS domain FROM domains,mailboxes,vacations WHERE \
               vacations.active=1 AND \
               vacations.mailbox_id=mailboxes.id AND \
               mailboxes.active=1 AND \
               mailboxes.local_part='${quote_mysql:$local_part}' AND \
               mailboxes.domain_id=domains.id AND \
               domains.active=1 AND \
               domains.fqdn='${quote_mysql:$domain}'}}
  no_expn
  senders = !^.*-request@.* : !^owner-.*@.* : !^postmaster@.* : \
            ! ^listmaster@.* : !^mailer-daemon@.*
  transport = vacation_reply
  unseen
  no_verify




begin transports

remote_smtp:
  driver = smtp
local_delivery:
  driver = appendfile
  maildir_format = true
  #directory = /var/spool/mail/$domain/$local_part
  directory = ${lookup pgsql{SELECT maildir FROM account WHERE username = '$local_part'}{$value}}
 # file = /var/mail/$local_part
  delivery_date_add
  envelope_to_add
  return_path_add
  group = mail
  mode = 0660
  headers_remove = X-SA-Nie-Uruchamiaj-Mnie : X-SA-Exim-Connect-IP : X-SA-Exim-Rcpt-To : X-SA-Exim-Mail-From
  user = dovecot


dovecot_delivery:
  driver = appendfile
  maildir_format = true
  directory = /var/spool/mail/$domain/$local_part
  create_directory = true
  directory_mode = 0770
  mode_fail_narrower = false
  message_prefix =
  message_suffix =
  delivery_date_add
  envelope_to_add
  return_path_add
  user = mail
  group = mail
  mode = 0660


vacation_reply:
  driver = autoreply
  to = "${sender_address}"
  from = "${local_part}@${domain}"
  log = /var/spool/exim/msglog/exim_vacation.log
  once =/var/spool/exim/db/vacation.db
  once_repeat = 1d
  subject = "${lookup mysql{SELECT vacations.subject AS subject FROM vacations,mailboxes,domains WHERE \
               vacations.active=1 AND \
               vacations.mailbox_id=mailboxes.id AND \
               mailboxes.local_part='${quote_mysql:$local_part}' AND \
               mailboxes.active=1 AND \
               mailboxes.domain_id=domains.id AND \
               domains.fqdn='${quote_mysql:$domain}' AND \
               domains.active=1}}"
  text = "${lookup mysql{SELECT vacations.body AS body FROM vacations,mailboxes,domains WHERE \
            vacations.active=1 AND \
            vacations.mailbox_id=mailboxes.id AND \
            mailboxes.local_part='${quote_mysql:$local_part}' AND \
            mailboxes.active=1 AND \
            mailboxes.domain_id=domains.id AND \
            domains.fqdn='${quote_mysql:$domain}' AND \
            domains.active=1}}"
  file_optional = true




local_delivery_spam:
  driver = appendfile
  maildir_format
  directory = ${lookup mysql{SELECT maildir FROM account WHERE username = '$local_part'}{$value}}/.spam
 # file = /var/mail/$local_part
  delivery_date_add
  envelope_to_add
  return_path_add
  group = mail
  mode = 0660
  headers_remove = X-SA-Nie-Uruchamiaj-Mnie : X-SA-Exim-Connect-IP : X-SA-Exim-Rcpt-To : X-SA-Exim-Mail-From
  user = dovecot

address_pipe:
  driver = pipe
  return_output

address_file:
  driver = appendfile
  delivery_date_add
  envelope_to_add
  return_path_add

address_reply:
  driver = autoreply

begin retry

*                      *           F,2h,15m; G,16h,1h,1.5; F,4d,6h


begin rewrite



begin authenticators

#PLAIN:
#  driver                     = plaintext
#  server_set_id              = $auth2
#  server_prompts             = :
#  server_condition           = ${lookup pgsql{select count(account_id) from account where username = '$2' and password = '$3'}{$value}}
#  server_advertise_condition = ${if def:tls_cipher }

#LOGIN:
#  driver                     = plaintext
#  server_set_id              = $auth1
#  server_prompts             = <| Username: | Password:
#  server_condition           = ${lookup pgsql{select count(account_id) from account where username = '$1' and password = '$2'}{$value}}
#  server_advertise_condition = ${if def:tls_cipher }


auth_plain:
  driver = plaintext
  public_name = PLAIN
  server_condition = ${lookup mysql{SELECT CONCAT(mailboxes.local_part,'@',domains.fqdn) FROM mailboxes,domains WHERE \
                       mailboxes.local_part=SUBSTRING_INDEX('${quote_mysql:$auth2}','@',1) AND \
                       mailboxes.password=MD5('${quote_mysql:$auth3}') AND \
                       mailboxes.active=1 AND \
                       mailboxes.domain_id=domains.id AND \
                       domains.fqdn=SUBSTRING_INDEX('${quote_mysql:$auth2}','@',-1) AND \
                       domains.active=1}{yes}{no}}
  server_prompts = :
  server_advertise_condition = ${if def:tls_cipher }
  server_set_id = $auth2

auth_login:
  driver = plaintext
  public_name = LOGIN
  server_condition = ${lookup mysql{SELECT CONCAT(mailboxes.local_part,'@',domains.fqdn) FROM mailboxes,domains WHERE \
                       mailboxes.local_part=SUBSTRING_INDEX('${quote_mysql:$auth1}','@',1) AND \
                       mailboxes.password=MD5('${quote_mysql:$auth2}') AND \
                       mailboxes.active=1 AND \
                       mailboxes.domain_id=domains.id AND \
                       domains.fqdn=SUBSTRING_INDEX('${quote_mysql:$auth1}','@',-1) AND \
                       domains.active=1}{yes}{no}}
  server_prompts = Username:: : Password::
  server_advertise_condition = ${if def:tls_cipher }
  server_set_id = $auth1

cram:
  driver = cram_md5
  public_name = CRAM-MD5
  server_secret = ${lookup mysql{SELECT clear FROM users WHERE id='${quote_mysql:$1}'}{$value}fail}
  server_set_id = $1

SQL Config File

CREATE DATABASE email
  CHARACTER SET utf8mb4
  COLLATE utf8mb4_bin;
 
USE email;
·
CREATE TABLE IF NOT EXISTS mailboxes (
  id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
  domain_id INT(11) NOT NULL COMMENT 'domain-part of email-address',
  -- local_part VARCHAR(255) NOT NULL COMMENT 'local-part of email-address',
  username VARCHAR(255) NOT NULL COMMENT 'local-part of email-address',
  password VARCHAR(255) NULL COMMENT 'Password of the mailbox',
  description VARCHAR(255) NULL COMMENT 'Description of the mailbox',
 
 
    uid int(10) unsigned default '8',
    gid int(10) unsigned default '8',
    home VARCHAR(255) NOT NULL COMMENT 'Home directory',
 
    quota tinyint(4) default '0' COMMENT 'Quota',
 
  `allow_smtp` enum('NO','YES') NOT NULL default 'YES' COMMENT 'May receive mail (has a mailbox)',
  `allow_smtpauth` enum('NO','YES') NOT NULL default 'YES' COMMENT 'May send mails from anywhere (localhost always without auth)',
    `allow_pop3` enum('NO','YES') NOT NULL default 'YES' COMMENT 'May fetch mail through pop3',
  `allow_imap` enum('NO','YES') NOT NULL default 'YES' COMMENT 'May fetch mail through pop3/imap',
  `spam_threshold` double NOT NULL default '5' COMMENT 'Tag as spam, if above',
  `spam_tag` varchar(64) NOT NULL default '{SPAM?} ' COMMENT 'String to prepend to subject, if spam',
 
  active TINYINT(1) NOT NULL DEFAULT 0 COMMENT 'Whether the mailbox is active',
  created TIMESTAMP NOT NULL DEFAULT NOW(),
  modified TIMESTAMP NULL,
 
  PRIMARY KEY  (`id`),
  UNIQUE KEY `mailbox` (`domain`, `username` (191))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='Mailboxes definitions';
 
-- ALTER TABLE `mytable1` ADD INDEX `theindex` (`mycolumn` (191),`mycolumnb`);
 
CREATE TABLE IF NOT EXISTS aliases (
  id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
  domain_id INT(11) NOT NULL COMMENT 'domain-part of email-address',
  -- local_part VARCHAR(255) NOT NULL COMMENT 'local-part of email address',
  username VARCHAR(255) NOT NULL COMMENT 'Local-part of email address',
  -- goto VARCHAR(255) NOT NULL 'Address (or more comma-seperated) to forward mail to',
  goto TEXT NOT NULL COMMENT 'Address (or more comma-seperated) to forward mail to',
  description VARCHAR(255) NULL COMMENT 'Description of the alias',
  active TINYINT(1) NOT NULL DEFAULT 0 COMMENT 'Whether the alias is active',
  created TIMESTAMP NOT NULL DEFAULT NOW(),
  modified TIMESTAMP NULL,
 
  UNIQUE KEY `mailbox` (`domain`, `username` (191))
  KEY `domain` (`domain` (191)),
  KEY `username` (`username` (191)),
 
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='Alias definitions';
 
CREATE TABLE IF NOT EXISTS vacations (
  id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
  mailbox_id INT(11) NOT NULL,
  subject VARCHAR(255) NOT NULL,
  body TEXT NOT NULL,
  description VARCHAR(255) NULL COMMENT 'Description of the vacation',
    start_date TIMESTAMP NULL,
    end_date TIMESTAMP NULL,
  active TINYINT(1) NOT NULL DEFAULT 0,
  created TIMESTAMP NOT NULL DEFAULT NOW(),
  modified TIMESTAMP NULL,
 
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='Vacation definitions';
 
CREATE TABLE IF NOT EXISTS domains (
  id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
  -- fqdn VARCHAR(255) NOT NULL,
  domain VARCHAR(255) NOT NULL COMMENT 'Fully qualified domain name (fqdn)',
  -- type ENUM('local','relay') NOT NULL DEFAULT 'local',
  type ENUM('local','relay','virtual') NOT NULL DEFAULT 'local',
  description VARCHAR(255) NULL,
  active TINYINT(1) NOT NULL DEFAULT 0,
  created TIMESTAMP NOT NULL DEFAULT NOW(),
  modified TIMESTAMP NULL,
 
  PRIMARY KEY  (`id`),
  -- KEY `fqdn` (`fqdn`(191))
  KEY `domain` (`domain`(191))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='Domain definitions';
 
CREATE TABLE IF NOT EXISTS `greylist` (
  id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `sender_ip` VARCHAR(15) NOT NULL COMMENT 'IP of Sender',
  `sender_address` VARCHAR(1024) NOT NULL COMMENT 'Email-address of Sender',
  `first_seen` int(11) NOT NULL COMMENT 'UNIX TimeStamp of first attempt',
  active TINYINT(1) NOT NULL DEFAULT 1,
  created TIMESTAMP NOT NULL DEFAULT NOW(),
  modified TIMESTAMP NULL,
 
  PRIMARY KEY  (`id`),
  KEY `sender_ip` (`sender_IP`),
  KEY `sender_address` (`sender_address`(191))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='Greylisting definitions';
 
 
CREATE TABLE IF NOT EXISTS `dnsbl` (
  id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `ip` varchar(15) NOT NULL,
  `hostname` varchar(255) default NULL,
  `dnsbl` varchar(255) default NULL,
  description VARCHAR(255) NULL,
  `count` int(11) NOT NULL default '1',
  active TINYINT(1) NOT NULL DEFAULT 0,
  created TIMESTAMP NOT NULL DEFAULT NOW(),
  modified TIMESTAMP NULL,
 
  PRIMARY KEY  (`id`),
  UNIQUE KEY (`ip`),
  KEY `hostname` (`hostname`(191)),
  KEY `dnsbl` (`dnsbl`(191))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='DNSBL';
 
 
-- http://wiki.rsyslog.com/index.php/EximAmalgamatedLog
 
CREATE TABLE IF NOT EXISTS `log` (
  id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `exim_id` varchar(16) NOT NULL,
  `message_id` varchar(255) default NULL,
  `date_in` datetime default NULL,
  `date_last_processed` datetime default NULL,
  `date_completed` datetime default NULL,
  `from_addr` varchar(100) default NULL,
  `first_to_addr` varchar(100) default NULL,
  `additional_to_addr` varchar(255) default NULL,
  `host_from` varchar(100) default NULL,
  `first_host_to` varchar(100) default NULL,
  `size` int(11) default NULL,
  `subject` varchar(255) default NULL,
  `av_scan_result` varchar(255) default NULL,
  `sa_action` varchar(255) default NULL,
  `spamd_result` varchar(255) default NULL,·
  `from_domain` varchar(100),
  `to_domain` varchar(100),
  `notes` varchar(255) default NULL,
  UNIQUE KEY `exim_id` (`exim_id`),
  KEY `message_id` (`message_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='Mail Log';
 
 
# log query for gathering statistics about locally delivered mail
MYSQL_LOG=INSERT INTO `spamlog` ( `id`, `message_id`, `sender_ip`, `sender_port`, `sender_hostname`, `sender_helo`, `sender_address`, `recipient_address`, `username`, `domain`, `load_average`, `spam_score`, `message_size`, `body_size`, `message_lines`, `body_lines`, `received_headers`, `received_protocol`, `cipher`, `authenticated`, `sender_verify`, `age`, `time_stamp`) \
VALUES( '${quote_mysql:$message_exim_id}', \
  '${quote_mysql:$header_Message-ID:}', \
  '${quote_mysql:$sender_host_address}', \
  '${quote_mysql:$sender_host_port}', \
  '${quote_mysql:$sender_host_name}', \
  '${quote_mysql:$sender_helo_name}', \
  '${quote_mysql:$sender_address}', \
  CONCAT('${quote_mysql:$original_local_part}','@','${quote_mysql:$original_domain}'), \
  '${quote_mysql:$local_part}', '${quote_mysql:$domain}', \
  '${quote_mysql:$load_average}/1000', \
  '${quote_mysql:$header_X-Spam-Score:}', \
  '${quote_mysql:$message_size}', \
  '${quote_mysql:$message_body_size}', \
  '${quote_mysql:$message_linecount}', \
  '${quote_mysql:$body_linecount}', \
  '${quote_mysql:$received_count}', \
  '${quote_mysql:$received_protocol}', \
  '${quote_mysql:$tls_cipher}', \
  '${quote_mysql:$authenticated_id}', \
  '${quote_mysql:$header_X-Sender-Verify:}', \
  '${quote_mysql:$message_age}', \
  NOW() )
 
 
 
 
 
GRANT ALL ON email.* to 'email'@'localhost' IDENTIFIED BY 'password';
FLUSH PRIVILEGES;
 
-- Populate primary domain.
INSERT INTO domains VALUES(NULL,'sharewiz.net','local','ShareWiz local delivery',1,NOW(),NOW());
 
-- Populate·
INSERT INTO mailboxes VALUES(NULL,1,'admin',MD5('password - choose a good one'),'Admin account admin@sharewiz.net',1,NOW(),NOW());
 
 
-- Populate aliases.
INSERT INTO aliases VALUES (NULL, 1, 'postmaster', 'admin', '', 1, NOW(), NOW());
INSERT INTO aliases VALUES (NULL, 1, 'mailer-daemon', 'postmaster', '', 1, NOW(), NOW());
INSERT INTO aliases VALUES (NULL, 1, 'root', 'postmaster', '', 1, NOW(), NOW());
INSERT INTO aliases VALUES (NULL, 1, 'bin', 'root', '', 1, NOW(), NOW());
INSERT INTO aliases VALUES (NULL, 1, 'daemon', 'root', '', 1, NOW(), NOW());
INSERT INTO aliases VALUES (NULL, 1, 'sync', 'root', '', 1, NOW(), NOW());
INSERT INTO aliases VALUES (NULL, 1, 'mail', 'root', '', 1, NOW(), NOW());
INSERT INTO aliases VALUES (NULL, 1, 'pop', 'root', '', 1, NOW(), NOW());
INSERT INTO aliases VALUES (NULL, 1, 'uucp', 'root', '', 1, NOW(), NOW());
INSERT INTO aliases VALUES (NULL, 1, 'ftp', 'root', '', 1, NOW(), NOW());
INSERT INTO aliases VALUES (NULL, 1, 'nobody', 'root', '', 1, NOW(), NOW());
INSERT INTO aliases VALUES (NULL, 1, 'www', 'root', '', 1, NOW(), NOW());
INSERT INTO aliases VALUES (NULL, 1, 'named', 'root', '', 1, NOW(), NOW());
INSERT INTO aliases VALUES (NULL, 1, 'postgres', 'root', '', 1, NOW(), NOW());
INSERT INTO aliases VALUES (NULL, 1, 'mysql', 'root', '', 1, NOW(), NOW());
INSERT INTO aliases VALUES (NULL, 1, 'squid', 'root', '', 1, NOW(), NOW());
INSERT INTO aliases VALUES (NULL, 1, 'operator', 'root', '', 1, NOW(), NOW());
INSERT INTO aliases VALUES (NULL, 1, 'abuse', 'root', '', 1, NOW(), NOW());
INSERT INTO aliases VALUES (NULL, 1, 'hostmaster', 'root', '', 1, NOW(), NOW());
INSERT INTO aliases VALUES (NULL, 1, 'webmaster', 'root', '', 1, NOW(), NOW());
 
 
# Clear old entries from the greylist table
DELETE FROM greylist WHERE last_received < NOW() - INTERVAL 30 DAY;
exim4/config.txt · Last modified: 2020/07/15 09:30 by 127.0.0.1

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki