Dovecot imap send spam to junk – Server Fault

Still trying to make a spam solution for opensource

Also see

I am using

  • Ubuntu 18.04 64 bit
  • dovecot
  • spamassassin 3.4.1
  • amavisd

The goal is to run an e-mail server, which I achieved already. I can access the e-mails at the server using Thunderbird and the imap protocol.

For the postfix configuration I followed this tutorial: but using Maildir instead.

Dovecot got configured following:

In addition I installed fail2ban, which got tested successfully.

The next step is e-mail filtering. Following worked out nicely. Spamassassin is blocking all spam. But acutally I do not want to block it, I just want that spamassassin marks it as spam and that the spam gets redirected into my spam-folder. This is just in case something gets filtered out that was not a spam.

For that I set /etc/amavis/conf.d/21-ubuntu_defaults:

$final_spam_destiny       = D_PASS;

and the subject gets added ****SPAM****

The next step is that dovecot automatically moves this mail to my junk folder. And there I get stuck. I followed this tutorial:

and there the part “Sending spam to the Junk folder”. But it doesn’t work. I have seen that sieve is not working for imap. But I cannot find any tutorial or manual on imap_sieve, that would solve my problem. Does anyone of you has an idea? I also do not find any log entry where I could see that sieve is working (or not)?

3 Answers

I got a bit further in my problem:

By setting conf.d/10-logging.conf

mail_debug = yes

and conf.d/90-sieve.conf

sieve_plugins = sieve_imapsieve
sieve_global_dir = /etc/dovecot/sieve/`

as well as in:

conf.d/90-plugin.conf `

  plugin {
   sieve_plugins = sieve_imapsieve sieve_extprograms
   imapsieve_mailbox1_name = INBOX
   imapsieve_mailbox1_after = file:/etc/dovecot/sieve/default.sieve
  sieve_global_extensions = +vnd.dovecot.pipe +vnd.dovecot.environment

and sieve/default.sieve: `

 require ["fileinto", "mailbox", "imap4flags"];
 if header :contains "subject" ["*SPAM*"] {
    setflag "\\Seen";
    #setflag "\\Deleted";
    fileinto :create "Junk";

as well as compiling by sievec sieve/default.sieve I made it that junk mail gets copied into the junk folder. But unfortunately the mail stays as well in the Inbox. It seems it is just copied?

I solved the problem by another approach. Maybe not the best solution, but it works for me. I implement an incronetab, which is triggered, as soon as there is a new e-mail in the maildir.

`/home/myuser/Maildir/new/ IN_CREATE python3.6 /var/lib/ $@ $#`

The looks as follows:

import subprocess
import sys
import time


path = sys.argv[1]
file = sys.argv[2]
base_path = path[0:len(path)-4]
new_path = base_path + "cur/"
new_file = file + str(r'\:2\,')

full_path = new_path + new_file
command = "head -n 50 " + full_path
e_mail = subprocess.check_output([command], shell=True)
e_mail = e_mail.decode('ascii')
e_mail = e_mail.splitlines()

spam = False
for iterator in range (0, len(e_mail)):
if "X-Spam-Flag: YES" in e_mail[iterator]:
spam = True

if spam is True:
new_path = base_path + "/.Junk/cur/" + new_file + "S"
command = "mv " + full_path + " " + new_path
subprocess.check_output([command], shell=True)

The waiting time is needed, because dovecot moves the mail in the meanwhile from new to cur. The code is not fast enough to do ot while it is all in new.

the rest my code checks if the e-mail has a spam flag and if so, it moves it to the Junk folder of the user. The way to read in the e-mail is a bit unusual, but due to the “/” in the name of the mail I struggled a lot to read it in directly. I add “S” at the end of the name of the file, when I move it to the Junk so that it is marked as read. Then thunderbird does not bother me with a new mail there.

Please feel free to comment.

The problem you faced is in the sieve execution order. You have to rename the plugin rule from after to before

plugin {
   sieve_plugins = sieve_imapsieve sieve_extprograms
   imapsieve_mailbox1_name = INBOX
   imapsieve_mailbox1_before = file:/etc/dovecot/sieve/default.sieve
  sieve_global_extensions = +vnd.dovecot.pipe +vnd.dovecot.environment

Then your messages will be proceeded by default.sieve and stopped before normal delivery if *SPAM* pattern is present in the subject.

My strong advise is to use name like before1.sieve instead of default.sieve for sieve_before because default.sieve has a special meaning. Also it would be much better to add some special header to the message like X-SPAM-DETECTED instead of subject manipulations.


Here is my complete solution. I’ve used eximfor MTA and dovecot for delivery/sieving

exim have an ACL that invoke the spamassassin to calculate the score for message.
Two custom headers are added if score above the threshold:

warn     spam   = spamd
    condition   = ${if >{$spam_score_int}{49}}
    add_header  = X-Spam-Score: $spam_score_int
    add_header  = X-Spam-Ooops: Detected

Then the router pass the message to the transport:

    driver      = accept
    condition   = <some site specific code>
    transport   = dovelda

The transport is obvious:

    driver      = pipe
    user        = mailnull
    command     = /long/path/deliver -d $local_part@$domain -f $sender_address

deliver rely on the dovecot’s config:

plugin {
  sieve_plugins                 = sieve_imapsieve sieve_extprograms
  sieve_global_extensions       = +vnd.dovecot.pipe +vnd.dovecot.environment
  sieve_pipe_bin_dir            = /usr/local/etc/dovecot

## Two sieves only - common and personal
sieve_before = /long/path/common.sieve
sieve_dir = /var/mail/%d/%n
sieve = /var/mail/%d/%n/user.sieve
. . . . . . .

common.sieve is quite simple:

require "fileinto";
require "variables";
require "imap4flags";
if exists "X-Spam-Ooops"
   fileinto "Junk";
elsif anyof (header :contains "From" "postmaster@")
{  ## postmaster's message should be delivered at any cost
   setflag "flagvar" "\Flagged";
   fileinto :flags "${flagvar}" "INBOX";
   ## Trigger to launch the next script in the sequence

That’s all. Any message that have score above permitted will be marked by X-Spam-Ooopsheader and dropped into the user’s Junksubfolder.

  • Thanks for the idea! I tested it and I still have the same behavior. Spam can pass easily and sieve is not triggered. Any further ideas how to fix that problem? Marc Sep 11 ’18 at 19:13
  • Thank you very much for your code! I tested it but my problem remains. Only when I click at the spam mail, the mail gets moved to Junk. But my solution with incrontab works. Since it is my private server and not a professional system, I can live with my incrontab solution. But thanks again! 🙂 Marc Oct 9 ’18 at 9:05

Your Answer

Log in


By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Hits: 4580