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