Pimp your Exim4 – Categorize Mails Like Google

   Categorization in folders

You installed SpamAssasin or Rspamd but still the inboxes get to many irrelevant un-important mails that flood the inbox and making it look like it got a spam flood, but these mails aren’t even spam.. some of them is updates from Meta FaceBook some other from your Google Ad Account 
  • Someone liked your page, 
  • Linkedin: People in <country> Also follow these accounts: 
  • ecommerce you use: Check these products. Free coupon for 5% off
  • Don’t miss the updates on our platform
  • Discounts for the next 5 days
  • 3 People left a comment on your post
Etc, you get the point, you have 12 unread messages but right now you ain’t willing to read any of these because they are un-important for the moment to you and you missed the important mail from a potential customer who was asking if you can serve him with his problem.
Gooogle/gmail takes care of that issue by applying “labels” automatically.. which is nice: 

Here is how we can do something like that with Exim4 and IMAP, no sieve script.  in exim4 configuration we will create new routes and transports 
Of course it will be far from perfect but it will do the job but even gmail isn’t prefect as it labels mails with mistakes pretty often if you would like something that touches perfection maybe you should give a try to use machine learning with the Neural network module of rspamd and see if you can train it to classify your emails in a more decent way. 
First assuming you have dovecot for IMAP you should create first the new folders in that case of the tutorial example, lets say Social, Updates, Promotions. eg you add in your /etc/dovecot/dovecot.conf in namespace {  } add:

     mailbox Social {
        auto = subscribe
    }
      mailbox Promotions {
        auto = subscribe
    }
      mailbox Updates {
        auto = subscribe

    }
Next create the ‘filters’ on exim4, that would be either /etc/exim4/exim4.conf or /etc/exim4/exim4.conf.template
Frist start by building the appropriate routes for our folders, so you search in the file for :
begin routers
Search for localuser_spam:, or localuser:
 
For example, it looks like this: 

localuser:
  driver = accept
  transport = local_delivery

  condition = ${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/passwd}{true}{false}}
You copy and paste the whole block right after the previous and you create a new one. eg. localuser_social then you change the condition with the conditions i will provide to you and the transport with local_social so it becomes something like:

localuser_social:
  driver = accept
  transport = local_social
condition = ${if or {  
    {match{${lc:$header_from:}}{.*@facebook.com}}
    {match{${lc:$header_from:}}{.*@facebookmail.com}}
    {match{${lc:$header_from:}}{.*@*.facebook.com}}
    {match{${lc:$header_from:}}{.*@twitter.com}}
    {match{${lc:$header_from:}}{.*@*.twitter.com}}
    {match{${lc:$header_from:}}{.*@instagram.com}}
    {match{${lc:$header_from:}}{.*@*.instagram.com}}
    {match{${lc:$header_from:}}{.*@linkedin.com}}
    {match{${lc:$header_from:}}{.*@*.linkedin.com}}
    {match{${lc:$header_from:}}{.*@pinterest.com}}
    {match{${lc:$header_from:}}{.*@*.pinterest.com}}
    {match{${lc:$header_from:}}{.*@tiktok.com}}
    {match{${lc:$header_from:}}{.*@*.tiktok.com}}
}{yes}{no}}

 As you see, our condition will match all the known e-mail addresses from social media by their domain name.

Now it is time to create the transport for it, so you need to find “begin transports”  and then after it search for local_delivery:  and also copy paste the whole transport as you did with the route before. 

Change the name to what you used in the route before, transport = local_social so that means if the original local_delivery transport looks like this for example:

local_delivery:
  driver = appendfile
  maildir_format
  maildir_use_size_file
  user = ${extract{2}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/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/${lookup{$domain}dsearch{/etc/exim4/domains/}}/passwd}}}}/mail/${lookup{$domain}dsearch{/etc/exim4/domains/}}/${lookup{$local_part}dsearch{${extract{5}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/passwd}}}}/mail/${lookup{$domain}dsearch{/etc/exim4/domains/}}}}”
  quota = ${extract{6}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/passwd}}}}M

  quota_warn_threshold = 75%
Our copied should new transport look like:
local_social:
  driver = appendfile
  maildir_format
  maildir_use_size_file
  user = ${extract{2}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/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/${lookup{$domain}dsearch{/etc/exim4/domains/}}/passwd}}}}/mail/${lookup{$domain}dsearch{/etc/exim4/domains/}}/${lookup{$local_part}dsearch{${extract{5}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/passwd}}}}/mail/${lookup{$domain}dsearch{/etc/exim4/domains/}}}}/.Social
  quota = ${extract{6}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/passwd}}}}M
  quota_warn_threshold = 75%
Notice the value in directory we added the ./Social at the end of the path.
Now save and restart the services and our new route/transport should be working fine if you followed the tutorial correctly.
If you want to add more folders such as Promotions, Updates, Forums like gmail, then you repeat the above process again and again creating routes and transports for these… adjusting things as you like. 
Here I will provide you some examples of conditions for these new routes to save you time
Promotions:

  condition = ${if or {
  {match{${lc:$header_subject:}}{.*% off.*}}
  {match{${lc:$header_subject:}}{.*discount.*}}
  {match{${lc:$header_subject:}}{.*buy.*}}
  {match{${lc:$header_subject:}}{.*recommended.*}}
  {match{${lc:$header_subject:}}{.*promotion.*}}
  {match{${lc:$header_subject:}}{.*sales.*}}
  {match{${lc:$header_subject:}}{.*pair with.*}}
  {match{${lc:$header_subject:}}{.*new items.*}}
  {match{${lc:$header_subject:}}{.*new products.*}}
  {match{${lc:$header_subject:}}{.*limited time.*}}
  {match{${lc:$header_from:}}{.*sales*[^@]*@.*.com}}
  {match{${lc:$header_from:}}{.*deals*[^@]*@.*}}
  {match{${lc:$header_from:}}{.*marketing*[^@]*@.*}}
  {match{${lc:$header_from:}}{.*promotion*[^@]*@.*}}
  {match{${lc:$header_from:}}{.*deals@.*}}
  {match{${lc:$header_from:}}{.*marketing@.*}}
  {match{${lc:$header_from:}}{.*offers@.*}}
  {match{${lc:$header_from:}}{.*promotions@.*}}
  {match{${lc:$header_from:}}{.*@groupon.com}}

}{yes}{no}}


Updates
:

condition = ${if or {
    {match{${lc:$header_from:}}{.*transaction@.}}
    {match{${lc:$header_from:}}{.*no-reply@.}}
    {match{${lc:$header_from:}}{.*newsletter@.}}
    {match{${lc:$header_from:}}{.*newsletters@.}}
    {match{${lc:$header_from:}}{.*news-letter@.}}
    {match{${lc:$header_from:}}{.*noreply@.}}
    {match{${lc:$header_from:}}{.*support@.}}
    {match{${lc:$header_subject:}}{.*alert.*}}
    {match{${lc:$header_subject:}}{.*report.*}}
    {match{${lc:$header_subject:}}{.*downtime.*}}
    {match{${lc:$header_subject:}}{.*update.*}}
    {match{${lc:$header_subject:}}{.*updates.*}}
    {match{${lc:$header_subject:}}{.*maintenance.*}}
    {match{${lc:$header_subject:}}{.*reminder.*}}
    {match{${lc:$header_subject:}}{.*order.*}}
    {match{${lc:$header_subject:}}{.*transaction.*}}
    {match{${lc:$header_from:}}{.*@amazon.com}}
    {match{${lc:$header_from:}}{.*transaction*[^@]*@.*}}
    {match{${lc:$header_from:}}{.*orders*[^@]*@.*}}
    {match{${lc:$header_from:}}{.*order*[^@]*@.*}}

  }{yes}{no}}


Forums
:

condition = ${if or {
    {match{${lc:$header_from:}}{.*forum@.}}
    {match{${lc:$header_subject:}}{.*new topic.*}}
    {match{${lc:$header_subject:}}{.*new post.*}}
    {match{${lc:$header_subject:}}{.*new reply.*}}
    {match{${lc:$header_subject:}}{^Re: [*/]}}

  }{yes}{no}}
 
Thats all folks, i hope that helped you.

Leave a Reply