В общей картине что у нас есть? У нас есть
- RedHat Enterprise Linux 6.2
 - Настроеный кластер PostgreSQL
 - Настроеный MDA - Dovecot2
 - Установленый Clamav
 - Установленый Spamassassin
 - Установленый Exim 4.77
 
Правим /etc/exim/exim.conf
Код: Выделить всё
DOMAIN_QUERY = SELECT domain FROM domain WHERE domain='${domain}' AND active=true
# БД+Хосты
hide pgsql_servers = pgpool.domain.tld/mail/mail/пароль_пользователя_БД
domainlist local_domains = ${lookup pgsql{SELECT domain FROM domain WHERE domain='${domain}' AND active=true}}
domainlist relay_to_domains = ${lookup pgsql{DOMAIN_QUERY}}
domainlist dummy_domains =
hostlist relay_from_hosts = localhost:127.0.0.1/8:<ext_if_ip>:mail.domain.tld:domain.tld
hostlist spamers = ${lookup pgsql{SELECT host FROM blacklist WHERE host='${sender_host_address}'}}
host_lookup = *   
rfc1413_hosts = * 
rfc1413_query_timeout = 0s
allow_domain_literals = false
# TLS/SSL                      
tls_advertise_hosts = *                              
tls_certificate = /etc/pki/tls/private/exim.pem   
tls_privatekey = /etc/pki/tls/private/exim.pem    
daemon_smtp_ports = 25 : 465 : 587                   
tls_on_connect_ports = 465 
# Цепляем антивирь и антиспам
spamd_address = 127.0.0.1 783
av_scanner = clamd:/tmp/clamd.sock
smtp_banner = mx.domain.tld ESMTP Postfix 2.9.1/2.9.1  (CentOS 5.3); $tod_full
local_interfaces = 127.0.0.1 : <ext_ip_if>
qualify_domain = mx.domain.tld
qualify_recipient = mx.domain.tld
primary_hostname = mx.domain.tld
never_users = root
exim_user = exim
exim_group = exim
trusted_users = lighttpd
dsn_from = Mail Delivery System <Mailer-Daemon@$qualify_domain>
# Логи, тайминги
ignore_bounce_errors_after = 1d
timeout_frozen_after = 1d
delay_warning = 4h:8h:24h:48h
log_selector = \
    +all_parents \
    +connection_reject \
    +incoming_interface \
    +lost_incoming_connection \
    +received_sender \
    +received_recipients \
    +smtp_confirmation \
    +smtp_syntax_error \
    +smtp_protocol_error \
    -queue_run
# Тюним параметры SMTP 
smtp_accept_max = 500
smtp_accept_max_per_connection = 250
smtp_accept_max_per_host = 20
smtp_connect_backlog = 50
smtp_accept_queue_per_connection = 30
split_spool_directory = true
remote_max_parallel = 15
message_size_limit = 64M
smtp_enforce_sync = true
allow_mx_to_ip
disable_ipv6 = true
auto_thaw = 1h
# Небольшой фейк с заголовком
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 $qualify_domain \
  ${if def:received_protocol {with $received_protocol}} \
  ${if def:tls_cipher {($tls_cipher)\n\t}}\
  (Postfix 2.9.1)\n\t\
  ${if def:sender_address \
  {(envelope-from <$sender_address>)\n\t}}\
  id $message_exim_id\
  ${if def:received_for {\n\tfor $received_for}}
# Списки доступа
acl_smtp_mail = acl_check_mail
acl_smtp_dkim = acl_check_dkim
acl_smtp_rcpt = acl_check_rcpt
acl_smtp_data = acl_check_data
begin acl
acl_check_mail:
  deny    condition = ${if eq{$sender_helo_name}{} {1}}
       message = Nice boys say HELO first
  
  warn condition = ${if eq{$sender_host_name}{} {1}}
       set acl_m_greylistreasons = Host $sender_host_address lacks reverse DNS\n$acl_m_greylistreasons
  
  accept
# Проверяем соответствие DKIM домену отправителя
acl_check_dkim:
  deny 	message 	= Mail from DKIM-domain without DKIM-signature! Wassup?!
          sender_domains = ${lookup pgsql{SELECT array_to_string(array_agg(domains), ':') AS domains FROM dkim_domains WHERE active=true}} # Запись в базе в виде | gmail.com | gmail.com |
          dkim_signers 	= ${lookup pgsql{SELECT array_to_string(array_agg(signers), ':') AS signers FROM dkim_domains WHERE active=true}}
          dkim_status 	= none:invalid:fail
  accept
acl_check_rcpt:
  accept  hosts = :
          control = dkim_disable_verify
  deny    message       = Restricted characters in address
          domains       = +local_domains
          local_parts   = ^[.] : ^.*[@%!/|]
  deny    message       = Restricted characters in address
          domains       = !+local_domains
          local_parts   = ^[./|] : ^.*[@%!] : ^.*/\\.\\./
  accept  local_parts   = postmaster
          domains       = +local_domains
  require verify        = sender
  accept  hosts         = +relay_from_hosts
          control       = submission
          control       = dkim_disable_verify
# Ratelimit - ограничиваем частоту отправляемых писем в час. Данные выбираем... конечно из базы
  warn    authenticated   = *
          ratelimit       = ${lookup pgsql{SELECT rate FROM mailbox WHERE username='${quote_pgsql:$authenticated_id}' LIMIT 1}} / 1h / strict / $authenticated_id
          log_message     = Authenticated sender rate $sender_rate / $sender_rate_period
  deny    authenticated   = *
          ratelimit       = ${lookup pgsql{SELECT rate FROM mailbox WHERE username='${quote_pgsql:$authenticated_id}' LIMIT 1}} / 1h / strict / $authenticated_id
          log_message     = Authenticated sender rate $sender_rate / $sender_rate_period
# Авторизованый пользователь минует проверку DKIM
  accept  authenticated = *
          control       = submission
          control       = dkim_disable_verify
# Наш собственный блеклист
  deny    message       = "Your address in banlist!"
          senders       = ${lookup pgsql{SELECT sender FROM blacklist WHERE sender='${quote_pgsql:$sender_address}' OR sender='*@${quote_pgsql:$sender_address_domain}' LIMIT 1}}
  deny    hosts         = +spamers
          message       = "Host rejected by spam list on rbl.domain.tld!"
# Проверка корректности
  require message = relay not permitted
          domains = +local_domains : +relay_to_domains
  require verify = recipient
  deny    message       = "HELO/EHLO required by SMTP RFC"
          condition     = ${if eq{$sender_helo_name}{}{yes}{no}}
  deny    condition     = ${if match{$sender_helo_name}{\N^\d+$\N}{yes}{no}}
          hosts         = !127.0.0.1:!localhost:*
          message       = "There can not be only numbers in HELO!"
  deny    condition     = ${if eq{$sender_address}{}{yes}{no}}
          hosts         = +relay_from_hosts
          message       = "Your message have not return address"
  deny    message   = "The use of IP is forbidden in HELO!"
          hosts     = *:!+relay_from_hosts
          condition = ${if eq{$sender_helo_name}\
                      {$sender_host_address}{true}{false}}
  deny    condition = ${if eq{$sender_helo_name}\
                      {$interface_address}{yes}{no}}
          hosts     = !127.0.0.1 : !localhost : *
          message   = "The use of my IP is forbidden!"
# хосты на динамике нам тоже ни к чему
  deny    message   = "Dynamic hosts is forbidden!"
          condition = ${if match{$sender_host_name}\
                     {dsl|dial|pool|peer|dhcp|cable} {yes}{no}}
# Если домен отправителя имеет SPF-запись смотрим соответствует ли она IP-адресу с которого пришло письмо (требуется пакет libspf2)
  deny    message     = [SPF] $sender_host_address is not allowed to send mail \
                  from $sender_address_domain.
          log_message = SPF check failed.
          set acl_m9  = -ipv4=$sender_host_address \
                  -sender=$sender_address \
                  -helo=$sender_helo_name
          set acl_m9  = ${run{/usr/bin/spfquery $acl_m9}}
          condition   = ${if eq {$runrc}{1}{true}{false}}
# Смотрим нет ли отправителя в блеклистах
  deny    message       = rejected because $sender_host_address is in a black list at $dnslist_domain\n$dnslist_text
          hosts         = !+relay_from_hosts
          !authenticated = *
          log_message   = found in $dnslist_domain
          dnslists      = ${lookup pgsql{SELECT array_to_string(array_agg(dnsblists), ':') AS test FROM dnsbl WHERE bl=true}}
  accept
# Проверка тела письма
acl_check_data:
  warn    condition  = ${if !def:h_Message-ID: {1}}
          set acl_m_greylistreasons = Message lacks Message-Id: header. Consult RFC2822.\n$acl_m_greylistreasons
  deny       malware    = *
           message    = This message contains a virus ($malware_name).
  accept  condition  = ${if >={$message_size}{100000} {1}}
           add_header = X-Spam-Note: SpamAssassin run bypassed due to message size
  warn    spam       = nobody/defer_ok
           add_header = X-Spam-Flag: YES
  
  accept  condition  = ${if !def:spam_score_int {1}}
           add_header = X-Spam-Note: SpamAssassin invocation failed
  warn    add_header = X-Spam-Score: $spam_score ($spam_bar)\n\
                        X-Spam-Report: $spam_report
  deny       condition = ${if >{$spam_score_int}{100} {1}}
           message   = Your message scored $spam_score SpamAssassin point. Report follows:\n\
    	    	        $spam_report
  accept
# Роутеры
begin routers
# Резольв
dnslookup:
	driver = dnslookup
	domains = !+local_domains
	transport = remote_smtp
	ignore_target_hosts = 0.0.0.0 : 127.0.0.0/8
	no_more
# Проверяем не отключен-ли домен пользователя
disabled_domains:
	driver = redirect
	condition = ${lookup pgsql{SELECT domain FROM domain WHERE domain='${domain}' AND active=false}}
	allow_fail = yes
	data = :fail: Domain disabled
	no_more
# Проверяем не отключен-ли пользователь
disabled_users:
	driver = redirect
	condition = ${lookup pgsql{SELECT username FROM mailbox WHERE username='${quote_pgsql:$local_part@$domain}' AND active=false}}
	allow_fail = yes
	data = :fail: User disabled
	no_more
# Проверим не является ли пользователь алиасом
system_aliases:
	driver = redirect
	allow_fail
	allow_defer
	data = ${lookup pgsql{SELECT goto FROM alias WHERE address='${quote_pgsql:$local_part@$domain}' OR address='${quote_pgsql:@$domain}'}}
# Проверим существует-ли пользователь, если да письмо проходит дальше в транспортировщик к MDA
dovecot_user:
	driver = accept
	condition = ${if eq{} {${lookup pgsql{SELECT username FROM mailbox WHERE local_part='${local_part}' AND domain='${domain}' AND active=true}}}{no}{yes}}
	transport = dovecot_delivery
# Транспорты
begin transports
# Определим какой домен юзать для подписи DKIM
DKIM_DOMAIN      = ${lc:${domain:$h_from:}}
remote_smtp:
      driver = smtp
      interface = <ext_if_ip>
# Подписываем исходящую почту DKIM-ключом
      dkim_domain = DKIM_DOMAIN
      dkim_selector = delta
      dkim_private_key = ${lookup pgsql{SELECT rsa_key FROM dkim WHERE domain='${quote_pgsql:$dkim_domain}' LIMIT 1}{$value}}
      dkim_canon = relaxed
# Доставка в dovecot посредством LDA
dovecot_delivery:
    driver = pipe
    command = /usr/libexec/dovecot/dovecot-lda -d $local_part@$domain -f $sender_address
    message_prefix =
    message_suffix =
    delivery_date_add
    envelope_to_add
    return_path_add
    log_output
    user = mail
address_pipe:
    driver = pipe
    return_output
address_reply:
    driver = autoreply
begin retry
*                      *           F,2h,15m; G,16h,1h,1.5; F,4d,6h
begin rewrite
# Авторизация пользователей. Мы юзаем Dovecot 
begin authenticators
auth_plain:
 driver = dovecot
 public_name = PLAIN
 server_socket = /var/run/dovecot/auth-client
 server_set_id = $auth1
auth_login:
 driver = dovecot
 public_name = LOGIN
 server_socket = /var/run/dovecot/auth-client
 server_set_id = $auth1
auth_cram_md5:
 driver = dovecot
 public_name = CRAM-MD5
 server_socket = /var/run/dovecot/auth-client
 server_set_id = $auth1Код: Выделить всё
# service clamd start
# service spamassassin start
# service exim startАх, да... совсем забыл - DKIM!!!
Сгенерим пару ключей:
Код: Выделить всё
#openssl genrsa -out dkim.private.key 768
#openssl rsa -in dkim.private.key -out dkim.public.key -pubout -outform PEMСодержимое dkim.public.key (только строчки с данными в одну строчку, коментарии нам не нужны) внесем в конфигу нашей зоны dns в виде текстовой записи
Код: Выделить всё
delta._domainkey.domain.tld.   TXT v=DKIM1; t=y; k=rsa; p=<ключ>
