Filter spam emails from being forwarded by exim4

5,245

You have an acl_check_data acl where you invoke spamassassin. When SA detects spam exim sets the variable acl_m2=$spam_score_int. Now you can check that variable later in the routers and behave accordingly. F.e. do the next:

begin routers
nospam:
        driver          = accept
        condition       = ${if eq{$local_part@$domain}{[email protected]}}
        condition       = ${if >{$acl_m2}{SPAM_SCORE}}
        transport       = devnull

go2gmail:
        driver          = redirect
        condition       = ${if eq{$local_part@$domain}{[email protected]}}
        data            = [email protected]   
        pipe_transport  = address_pipe
        unseen
. . . . .
dnslookup:
        . . . . .

It is strictly significant that this two routers are placed before the dnslookup and all the magic has been done before message could be sended to the outer space. First router checks the variable and recipient's address and if they both are "bad" - simply drop the message to the blackhole. If not - the next router will redirect message to the gmail instead of original destination. And then the rest of routers will do their work. Also I've add the unseen verb to the second router. That's mean that the original message also will be processed and delivered to the original destination - i.e. to the local maildir where it will be accessible via roundcube.

Share:
5,245

Related videos on Youtube

Dipankar Maikap
Author by

Dipankar Maikap

Updated on September 18, 2022

Comments

  • Dipankar Maikap
    Dipankar Maikap almost 2 years

    I was studying and searching 2 days about how to configure my exim/spamassassin/clamd configuration.

    I have the next situation:

    I have an email [email protected] redirected to [email protected]. Unfortunately, every time [email protected] receives a spam email, forwards it to [email protected]. In this situation, gmail deny it because identify it as spam, bounce it back, server try to forward the bounce and so on. I'm at the risk to get the IP blacklisted by google because of "sending spam".

    The problem is....spamassassin correctly identify the spam and move it to Junk folder. I know that there is a way to filter the emails and forward them from Roundcube, but I have a control panel which make use of .forward file and I need to be able to do it out of Roundcube.

    This is my exim4 config file

    ##########################################################################
    SPAMASSASSIN = yes
    SPAM_SCORE = 50
    CLAMD =  yes
    ##########################################################################
    
    domainlist local_domains = dsearch;/etc/exim4/domains/
    domainlist relay_to_domains = dsearch;/etc/exim4/domains/
    hostlist   relay_from_hosts = 127.0.0.1
    hostlist   whitelist = net-iplsearch;/etc/exim4/white-blocks.conf
    hostlist   spammers = net-iplsearch;/etc/exim4/spam-blocks.conf
    no_local_from_check
    untrusted_set_sender = *
    acl_smtp_connect = acl_check_spammers
    acl_smtp_mail = acl_check_mail
    acl_smtp_rcpt = acl_check_rcpt
    acl_smtp_data = acl_check_data
    acl_smtp_mime = acl_check_mime
    
    .ifdef SPAMASSASSIN
    spamd_address = 127.0.0.1 783
    .endif
    
    .ifdef CLAMD
    av_scanner = clamd: /var/run/clamav/clamd.ctl
    .endif
    
    tls_advertise_hosts = *
    tls_certificate = /usr/local/ssl/certificate.crt
    tls_privatekey = /usr/local/ssl/certificate.key
    
    daemon_smtp_ports = 25 : 465 : 587 : 2525
    tls_on_connect_ports = 465
    never_users = root
    host_lookup = *
    rfc1413_hosts = *
    rfc1413_query_timeout = 5s
    ignore_bounce_errors_after = 2d
    timeout_frozen_after = 7d
    
    DKIM_DOMAIN = ${lc:${domain:$h_from:}}
    DKIM_FILE = /etc/exim4/domains/${lc:${domain:$h_from:}}/dkim.pem
    DKIM_PRIVATE_KEY = ${if exists{DKIM_FILE}{DKIM_FILE}{0}}
    
    
    ##########################################################################
    begin acl
    ##########################################################################
    acl_check_spammers:
      accept hosts = +whitelist
      drop    message       = Your host in blacklist on this server.
              log_message   = Host in blacklist
              hosts         = +spammers
      deny    message       = rejected because $sender_host_address is in a black list at $dnslist_domain\\n$dnslist_text
              dnslists      = ${readfile {/etc/exim4/dnsbl.conf}{:}}
      accept
    
    acl_check_mail:
      deny
              condition     = ${if eq{$sender_helo_name}{}}
              message       = HELO required before MAIL
    #  drop
    #          condition     = ${if isip{$sender_helo_name}}
    #          message       = Access denied - Invalid HELO name (See RFC2821 4.1.3)
      drop    message       = Helo name contains a ip address (HELO was $sender_helo_name) and not is valid
              condition     = ${if match{$sender_helo_name}{\N((\d{1,3}[.-]\d{1,3}[.-]\d{1,3}[.-]\d{1,3})|([0-9a-f]{8})|([0-9A-F]{8}))\N}{yes}{no}}
              condition     = ${if match {${lookup dnsdb{>: defer_never,ptr=$sender_host_address}}\}{$sender_helo_name}{no}{yes}}
              delay         = 45s
    #  drop
    #          condition     = ${if match{$sender_helo_name}{\N^\[\N}{no}{yes}}
    #          condition     = ${if match{$sender_helo_name}{\N\.\N}{no}{yes}}
    #          message       = Access denied - Invalid HELO name (See RFC2821 4.1.1.1)
      drop
              condition     = ${if isip{$sender_helo_name}}
              message       = Access denied - Invalid HELO name (See RFC2821 4.1.3)
    #  drop
    #          condition     = ${if match{$sender_helo_name}{\N\.$\N}}
    #          message       = Access denied - Invalid HELO name (See RFC2821 4.1.1.1)
    #  drop    message       = "REJECTED - Bad HELO - Host impersonating [$sender_helo_name]"
    #          condition     = ${if match{$sender_helo_name}{$primary_hostname}}
      drop    condition     = ${if eq{[$interface_address]}{$sender_helo_name}}
              message       = $interface_address is _my_ address
      accept
    
    
    acl_check_rcpt:
      accept  hosts         = :
    
      deny    message       = Restricted characters in address
              domains       = +local_domains
              local_parts   = ^[.] : ^.*[@%!/|]
    
      deny    message       = Restricted characters in address
              domains       = !+local_domains
              local_parts   = ^[./|] : ^.*[@%!] : ^.*/\\.\\./
    
      require verify        = sender
    
      accept  hosts         = +relay_from_hosts
              control       = submission
    
      accept  authenticated = *
              control       = submission/domain=
    
      require message       = relay not permitted
              domains       = +local_domains : +relay_to_domains
    
      deny    message       = smtp auth requried
             sender_domains = +local_domains
             !authenticated = *
    
      require verify        = recipient
    
    .ifdef CLAMD
      warn    set acl_m0    = no
      warn    condition     = ${if exists {/etc/exim4/domains/$domain/antivirus}{yes}{no}}
              set acl_m0    = yes
    .endif
    .ifdef SPAMASSASSIN
      warn    set acl_m1    = no
      warn    condition     = ${if exists {/etc/exim4/domains/$domain/antispam}{yes}{no}}
              set acl_m1    = yes
    .endif
      accept
    
    
    acl_check_data:
    .ifdef CLAMD
             deny message   = Message contains a virus ($malware_name) and has been rejected
             malware        = *
             condition      = ${if eq{$acl_m0}{yes}{yes}{no}}
    .endif
    
    .ifdef SPAMASSASSIN
      warn
             !authenticated = *
             hosts          = !+relay_from_hosts
             condition      = ${if < {$message_size}{100K}}
             condition      = ${if eq{$acl_m1}{yes}{yes}{no}}
             spam           = spamd:true/defer_ok
             add_header     = X-Spam-Score: $spam_score_int
             add_header     = X-Spam-Bar: $spam_bar
             add_header     = X-Spam-Report: $spam_report
             set acl_m2     = $spam_score_int
      warn
             condition      = ${if !eq{$acl_m2}{} {yes}{no}}
             condition      = ${if >{$acl_m2}{SPAM_SCORE} {yes}{no}}
             add_header     = X-Spam-Status: Yes
             message        = SpamAssassin detected spam (from $sender_address to $recipients).
    .endif
      accept
    
    
    acl_check_mime:
      deny   message       = Blacklisted file extension detected
             condition     = ${if match {${lc:$mime_filename}}{\N(\.ade|\.adp|\.bat|\.chm|\.cmd|\.com|\.cpl|\.exe|\.hta|\.ins|\.isp|\.jse|\.lib|\.lnk|\.mde|\.msc|\.msp|\.mst|\.pif|\.scr|\.sct|\.shb|\.sys|\.vb|\.vbe|\.vbs|\.vxd|\.wsc|\.wsf|\.wsh)$\N}{1}{0}}
      accept
    
    ##########################################################################
    begin authenticators
    ##########################################################################
    dovecot_plain:
      driver = dovecot
      public_name = PLAIN
      server_socket = /var/run/dovecot/auth-client
      server_set_id = $auth1
    
    dovecot_login:
      driver = dovecot
      public_name = LOGIN
      server_socket = /var/run/dovecot/auth-client
      server_set_id = $auth1
    
    ##########################################################################
    begin routers
    ##########################################################################
    
    dnslookup:
      driver = dnslookup
      domains = !+local_domains
      transport = remote_smtp
      no_more
    
    userforward:
      errors_to =
      driver = redirect
      check_local_user
      file = $home/.forward
      allow_filter
      no_verify
      no_expn
      check_ancestor
      file_transport = address_file
      pipe_transport = address_pipe
      reply_transport = address_reply
    
    procmail:
      driver = accept
      check_local_user
      require_files = ${local_part}:+${home}/.procmailrc:/usr/bin/procmail
      transport = procmail
      no_verify
    
    autoreplay:
      driver = accept
      require_files = /etc/exim4/domains/$domain/autoreply.${local_part}.msg
      condition = ${if exists{/etc/exim4/domains/$domain/autoreply.${local_part}.msg}}{yes}{no}}
      retry_use_local_part
      transport = userautoreply
      unseen
    
    aliases:
      errors_to =
      driver = redirect
      headers_add = X-redirected: yes
      data = ${extract{1}{:}{${lookup{$local_part@$domain}lsearch{/etc/exim4/domains/$domain/aliases}}}}
      require_files = /etc/exim4/domains/$domain/aliases
      redirect_router = dnslookup
      pipe_transport = address_pipe
      unseen
    
    localuser_fwd_only:
      driver = accept
      transport = devnull
      condition = ${if exists{/etc/exim/domains/$domain/fwd_only}{${lookup{$local_part}lsearch{/etc/exim/domains/$domain/fwd_only}{true}{false}}}}
    
    localuser_spam:
      driver = accept
      transport = local_spam_delivery
      condition = ${if eq {${if match{$h_X-Spam-Status:}{\N^Yes\N}{yes}{no}}} {${lookup{$local_part}lsearch{/etc/exim4/domains/$domain/passwd}{yes}{no_such_user}}}}
    
    localuser:
      driver = accept
      transport = local_delivery
      condition = ${lookup{$local_part}lsearch{/etc/exim4/domains/$domain/passwd}{true}{false}}
    
    catchall:
      driver = redirect
      headers_add = X-redirected: yes
      require_files = /etc/exim4/domains/$domain/aliases
      data = ${extract{1}{:}{${lookup{*@$domain}lsearch{/etc/exim4/domains/$domain/aliases}}}}
      file_transport = local_delivery
      redirect_router = dnslookup
    
    terminate_alias:
      driver = accept
      transport = devnull
      condition = ${lookup{$local_part@$domain}lsearch{/etc/exim4/domains/$domain/aliases}{true}{false}}
    
    
    ##########################################################################
    begin transports
    ##########################################################################
    remote_smtp:
      driver = smtp
      #helo_data = $sender_address_domain
      dkim_domain = DKIM_DOMAIN
      dkim_selector = mail
      dkim_private_key = DKIM_PRIVATE_KEY
      dkim_canon = relaxed
      dkim_strict = 0
    
    
    procmail:
      driver = pipe
      command = "/usr/bin/procmail -d $local_part"
      return_path_add
      delivery_date_add
      envelope_to_add
      user = $local_part
      initgroups
      return_output
    
    local_delivery:
      driver = appendfile
      maildir_format
      maildir_use_size_file
      user = ${extract{2}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/$domain/passwd}}}}
      group = mail
      create_directory
      directory_mode = 770
      mode = 660
      use_lockfile = no
      delivery_date_add
      envelope_to_add
      return_path_add
      directory = "${extract{5}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/$domain/passwd}}}}/mail/$domain/$local_part"
      quota = ${extract{6}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/$domain/passwd}}}}M
      quota_warn_threshold = 75%
    
    local_spam_delivery:
      driver = appendfile
      maildir_format
      maildir_use_size_file
      user = ${extract{2}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/$domain/passwd}}}}
      group = mail
      create_directory
      directory_mode = 770
      mode = 660
      use_lockfile = no
      delivery_date_add
      envelope_to_add
      return_path_add
      directory = "${extract{5}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/$domain/passwd}}}}/mail/$domain/$local_part/.Junk"
      quota = ${extract{6}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/$domain/passwd}}}}M
      quota_directory = "${extract{5}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/$domain/passwd}}}}/mail/$domain/$local_part"
      quota_warn_threshold = 75%
    
    address_pipe:
      driver = pipe
      return_output
    
    address_file:
      driver = appendfile
      delivery_date_add
      envelope_to_add
      return_path_add
    
    address_reply:
      driver = autoreply
    
    userautoreply:
      driver = autoreply
      file = /etc/exim4/domains/$domain/autoreply.${local_part}.msg
      from = "${local_part}@${domain}"
      subject = "${if def:h_Subject: {Autoreply: ${quote:${escape:$h_Subject:}}} {Autoreply Message}}"
      to = "${sender_address}"
    
    devnull:
      driver = appendfile
      file = /dev/null
    
    ##########################################################################
    begin retry
    *                      *           F,2h,15m; G,16h,1h,1.5; F,4d,6h
    ##########################################################################
    begin rewrite
    

    This is my spamassassin configuration

    # This is the right place to customize your installation of SpamAssassin.
    #
    # See 'perldoc Mail::SpamAssassin::Conf' for details of what can be
    # tweaked.
    #
    # Only a small subset of options are listed below
    #
    ###########################################################################
    
    #   Add *****SPAM***** to the Subject header of spam e-mails
    #
    # rewrite_header Subject *****SPAM*****
    
    
    #   Save spam messages as a message/rfc822 MIME attachment instead of
    #   modifying the original message (0: off, 2: use text/plain instead)
    #
     report_safe 0
     clear_report_template
     report_contact [email protected] 
     report host: _HOSTNAME_ | contact: _CONTACTADDRESS_ | scores: _TESTSSCORES(,)_ | autolearn=_AUTOLEARN_, score=_AUTOLEARNSCORE_
    
    #   Set which networks or hosts are considered 'trusted' by your mail
    #   server (i.e. not spammers)
    #
    # trusted_networks 212.17.35.
    
    
    #   Set file-locking method (flock is not safe over NFS, but is faster)
    #
    # lock_method flock
    
    
    #   Set the threshold at which a message is considered spam (default: 5.0)
    #
     required_score 5.0
    
    
    #   Use Bayesian classifier (default: 1)
    #
     use_bayes 1
    
    
    #   Bayesian classifier auto-learning (default: 1)
    #
     bayes_auto_learn 1
    
    
    #   Set headers which may provide inappropriate cues to the Bayesian
    #   classifier
    #
     bayes_ignore_header X-Bogosity
     bayes_ignore_header X-Spam-Flag
     bayes_ignore_header X-Spam-Status
     bayes_ignore_header X-Spam-Report
    
    #   Some shortcircuiting, if the plugin is enabled
    # 
    ifplugin Mail::SpamAssassin::Plugin::Shortcircuit
    #
    #   default: strongly-whitelisted mails are *really* whitelisted now, if the
    #   shortcircuiting plugin is active, causing early exit to save CPU load.
    #   Uncomment to turn this on
    #
    # shortcircuit USER_IN_WHITELIST       on
    # shortcircuit USER_IN_DEF_WHITELIST   on
    # shortcircuit USER_IN_ALL_SPAM_TO     on
    # shortcircuit SUBJECT_IN_WHITELIST    on
    
    #   the opposite; blacklisted mails can also save CPU
    #
    # shortcircuit USER_IN_BLACKLIST       on
    # shortcircuit USER_IN_BLACKLIST_TO    on
    # shortcircuit SUBJECT_IN_BLACKLIST    on
    
    #   if you have taken the time to correctly specify your "trusted_networks",
    #   this is another good way to save CPU
    #
    # shortcircuit ALL_TRUSTED             on
    
    #   and a well-trained bayes DB can save running rules, too
    #
    # shortcircuit BAYES_99                spam
    # shortcircuit BAYES_00                ham
    
    endif # Mail::SpamAssassin::Plugin::Shortcircuit
    
  • Dipankar Maikap
    Dipankar Maikap about 10 years
    Wow, I haven't expected an answer after so much time. Finally! Thank you so much. However, I don't understand the [email protected] and the [email protected]. It doesn't looks like some variables, wouldn't emails be forwarded to [email protected] ? Thank you.
  • Kondybas
    Kondybas about 10 years
    That's not a variables, that's a plain strings containing real email addresses you want to filter/redirect. If your local address is [email protected] you have to put that string instead of [email protected]. The same with [email protected] - that is just placeholder for the real email you want to redirect clean messages to.
  • Kondybas
    Kondybas about 10 years
    Proposed solution works ONLY with explicitly defined email address while all others are stay intacted and processed as usual. And even messages to the selected address will be splitted into two copies - one will go to the gmail while the other will be delivered in usual way. Nevertheless, decision is your.