====== 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 ====
######################################################################
# 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 ()
==== 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 ====
https://translate.google.com/translate?hl=en&sl=auto&tl=en&u=http%3A%2F%2Fjared.kiev.ua%2F2010%2F01%2Fisp-mailserver-1-exim%2F
http://jared.kiev.ua/2010/01/isp-mailserver-1-exim/
===== 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:]" 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;