use the Dovecot managesieve service to manage sieve scripts

This lets roundcube's manageseive plugin do cool things like vacation responses.

Also:

* Run the spam filtering sieve script out of a global sieve file that we'll place in /etc/dovecot. It is no longer necessary to create per-user sieve files for this. Remove them with a new migration. Remove the code that created them.

* Corrects the spam script. Backslashes were double-escaped probably because this script started embedded within the bash script. Not sure how this was working until now.

this adapts work by @h8h in #103
This commit is contained in:
Joshua Tauberer 2014-07-10 07:40:51 +00:00
parent e713af5f5a
commit 85bd2c8804
5 changed files with 44 additions and 22 deletions

View file

@ -1,7 +1,7 @@
require ["regex", "fileinto", "imap4flags"]; require ["regex", "fileinto", "imap4flags"];
if allof (header :regex "X-Spam-Status" "^Yes") { if allof (header :regex "X-Spam-Status" "^Yes") {
setflag "\\\\Seen"; setflag "\\Seen";
fileinto "Spam"; fileinto "Spam";
stop; stop;
} }

View file

@ -84,16 +84,6 @@ def add_mail_user(email, pw, env):
if "INBOX" not in existing_mboxes: utils.shell('check_call', ["doveadm", "mailbox", "create", "-u", email, "-s", "INBOX"]) if "INBOX" not in existing_mboxes: utils.shell('check_call', ["doveadm", "mailbox", "create", "-u", email, "-s", "INBOX"])
if "Spam" not in existing_mboxes: utils.shell('check_call', ["doveadm", "mailbox", "create", "-u", email, "-s", "Spam"]) if "Spam" not in existing_mboxes: utils.shell('check_call', ["doveadm", "mailbox", "create", "-u", email, "-s", "Spam"])
# Create the user's sieve script to move spam into the Spam folder, and make it owned by mail.
maildirstat = os.stat(env["STORAGE_ROOT"] + "/mail/mailboxes")
(em_user, em_domain) = email.split("@", 1)
user_mail_dir = env["STORAGE_ROOT"] + ("/mail/mailboxes/%s/%s" % (em_domain, em_user))
if not os.path.exists(user_mail_dir):
os.makedirs(user_mail_dir)
os.chown(user_mail_dir, maildirstat.st_uid, maildirstat.st_gid)
shutil.copyfile(utils.CONF_DIR + "/dovecot_sieve.txt", user_mail_dir + "/.dovecot.sieve")
os.chown(user_mail_dir + "/.dovecot.sieve", maildirstat.st_uid, maildirstat.st_gid)
# Update things in case any new domains are added. # Update things in case any new domains are added.
return kick(env, "mail user added") return kick(env, "mail user added")
@ -222,3 +212,4 @@ if __name__ == "__main__":
if len(sys.argv) > 1 and sys.argv[1] == "update": if len(sys.argv) > 1 and sys.argv[1] == "update":
from utils import load_environment from utils import load_environment
print(kick(load_environment())) print(kick(load_environment()))

View file

@ -20,7 +20,8 @@ source /etc/mailinabox.conf # load global vars
# Install packages. # Install packages.
apt_install \ apt_install \
dovecot-core dovecot-imapd dovecot-lmtpd dovecot-sqlite sqlite3 dovecot-sieve dovecot-core dovecot-imapd dovecot-lmtpd dovecot-sqlite sqlite3 \
dovecot-sieve dovecot-managesieved
# The dovecot-imapd dovecot-lmtpd packages automatically enable IMAP and LMTP protocols. # The dovecot-imapd dovecot-lmtpd packages automatically enable IMAP and LMTP protocols.
@ -86,18 +87,35 @@ tools/editconf.py /etc/dovecot/conf.d/15-lda.conf \
# SIEVE # SIEVE
# Enable the Dovecot sieve plugin which let's us set a script that automatically moves # Enable the Dovecot sieve plugin which let's users run scripts that process
# spam into the user's Spam mail filter. (Note: Be careful if we want to use multiple # mail as it comes in. We'll also set a global script that moves mail marked
# plugins later.) # as spam by Spamassassin into the user's Spam folder.
#
# The actual sieve script is copied into user mailboxes at the time the user account
# is created. Our script moves spam into the user's Spam folder.
sudo sed -i "s/#mail_plugins = .*/mail_plugins = \$mail_plugins sieve/" /etc/dovecot/conf.d/20-lmtp.conf sudo sed -i "s/#mail_plugins = .*/mail_plugins = \$mail_plugins sieve/" /etc/dovecot/conf.d/20-lmtp.conf
# PERMISSIONS cat > /etc/dovecot/conf.d/99-local-sieve.conf << EOF;
plugin {
# The path to our global sieve which handles moving spam to the Spam folder.
sieve_before = /etc/dovecot/sieve-spam.sieve
# Make the place for mailboxes. # The path to the user's main active script. ManageSieve will create a symbolic
mkdir -p $STORAGE_ROOT/mail # link here to the actual sieve script. It should not be in the mailbox directory
# (because then it might appear as a folder) and it should not be in the sieve_dir
# (because then I suppose it might appear to the user as one of their scripts).
sieve = $STORAGE_ROOT/mail/sieve/%d/%n.sieve
# Directory for :personal include scripts for the include extension. This
# is also where the ManageSieve service stores the user's scripts.
sieve_dir = $STORAGE_ROOT/mail/sieve/%d/%n
}
EOF
# Copy the global sieve script into where we've told Dovecot to look for it. Then
# compile it. Global scripts must be compiled now because Dovecot won't have
# permission later.
cp `pwd`/conf/sieve-spam.txt /etc/dovecot/sieve-spam.sieve
sievec /etc/dovecot/sieve-spam.sieve
# PERMISSIONS
# Ensure configuration files are owned by dovecot and not world readable. # Ensure configuration files are owned by dovecot and not world readable.
chown -R mail:dovecot /etc/dovecot chown -R mail:dovecot /etc/dovecot
@ -107,6 +125,10 @@ chmod -R o-rwx /etc/dovecot
mkdir -p $STORAGE_ROOT/mail/mailboxes mkdir -p $STORAGE_ROOT/mail/mailboxes
chown -R mail.mail $STORAGE_ROOT/mail/mailboxes chown -R mail.mail $STORAGE_ROOT/mail/mailboxes
# Same for the sieve scripts.
mkdir -p $STORAGE_ROOT/mail/sieve
chown -R mail.mail $STORAGE_ROOT/mail/sieve
# Allow the IMAP port in the firewall. # Allow the IMAP port in the firewall.
ufw_allow imaps ufw_allow imaps

View file

@ -36,6 +36,15 @@ def migration_1(env):
except: except:
pass pass
def migration_2(env):
# Delete the .dovecot_sieve script everywhere. This was formerly a copy of our spam -> Spam
# script. We now install it as a global script, and we use managesieve, so the old file is
# irrelevant. Also delete the compiled binary form.
for fn in glob.glob(os.path.join(env["STORAGE_ROOT"], 'mail/mailboxes/*/*/.dovecot.sieve')):
os.unlink(fn)
for fn in glob.glob(os.path.join(env["STORAGE_ROOT"], 'mail/mailboxes/*/*/.dovecot.svbin')):
os.unlink(fn)
def get_current_migration(): def get_current_migration():
ver = 0 ver = 0
while True: while True:

View file

@ -62,7 +62,7 @@ cat - > /usr/local/lib/roundcubemail/config/config.inc.php <<EOF;
\$config['support_url'] = 'https://mailinabox.email/'; \$config['support_url'] = 'https://mailinabox.email/';
\$config['product_name'] = 'Mail-in-a-Box/Roundcube Webmail'; \$config['product_name'] = 'Mail-in-a-Box/Roundcube Webmail';
\$config['des_key'] = '$SECRET_KEY'; \$config['des_key'] = '$SECRET_KEY';
\$config['plugins'] = array('archive', 'zipdownload', 'password'); \$config['plugins'] = array('archive', 'zipdownload', 'password', 'managesieve');
\$config['skin'] = 'larry'; \$config['skin'] = 'larry';
\$config['login_autocomplete'] = 2; \$config['login_autocomplete'] = 2;
\$config['password_charset'] = 'UTF-8'; \$config['password_charset'] = 'UTF-8';