spamassassin
This commit is contained in:
parent
5cef1bb63d
commit
97b2105a1f
7 changed files with 105 additions and 16 deletions
|
@ -8,6 +8,8 @@ This draws heavily on Sovereign by Alex Payne (https://github.com/al3x/sovereign
|
|||
Deploying to EC2 from the command line
|
||||
--------------------------------------
|
||||
|
||||
Amazon's EC2 isn't a great place to host a mail server. Do you still need to request permission to send email first? And you don't know if you'll get an IP address with a bad reputation from its previous owner. But it makes deployment easy, so it may at least be useful for testing.
|
||||
|
||||
Sign up for Amazon Web Services.
|
||||
|
||||
Create an Access Key at https://console.aws.amazon.com/iam/home?#security_credential. Download the key and save the information somewhere secure.
|
||||
|
@ -54,6 +56,8 @@ Somehow download these files.
|
|||
...
|
||||
logout
|
||||
|
||||
You'll also want to set reverse DNS (PTR), which is something your hosting provider will probably have a control panel for.
|
||||
|
||||
Terminate your instance with:
|
||||
|
||||
ec2-terminate-instances $INSTANCE
|
||||
|
|
|
@ -109,17 +109,22 @@ EOF
|
|||
sed -i "s/#port = 143/port = 0/" /etc/dovecot/conf.d/10-master.conf
|
||||
sed -i "s/#port = 110/port = 0/" /etc/dovecot/conf.d/10-master.conf
|
||||
|
||||
# Modify the unix socket for LMTP.
|
||||
sed -i "s/unix_listener lmtp \(.*\)/unix_listener \/var\/spool\/postfix\/private\/dovecot-lmtp \1\n user = postfix\n group = postfix\n/" /etc/dovecot/conf.d/10-master.conf
|
||||
|
||||
# Add an additional auth socket for postfix. Check if it already is
|
||||
# set to make sure this is idempotent.
|
||||
if grep -q "mailinabox-postfix-private-auth" /etc/dovecot/conf.d/10-master.conf; then
|
||||
# already done
|
||||
true;
|
||||
else
|
||||
sed -i "s/\(\s*unix_listener auth-userdb\)/ unix_listener \/var\/spool\/postfix\/private\/auth \{ # mailinabox-postfix-private-auth\n mode = 0666\n user = postfix\n group = postfix\n \}\n\1/" /etc/dovecot/conf.d/10-master.conf
|
||||
fi
|
||||
# Create a Unix domain socket specific for postgres to connect via LMTP because
|
||||
# postgres is already configured to use this location, and create a TCP socket
|
||||
# for spampd to inject mail on (if it's configured later). dovecot's standard
|
||||
# lmtp unix socket is also listening.
|
||||
cat > /etc/dovecot/conf.d/99-local.conf << EOF;
|
||||
service lmtp {
|
||||
unix_listener /var/spool/postfix/private/dovecot-lmtp {
|
||||
user = postfix
|
||||
group = postfix
|
||||
}
|
||||
inet_listener lmtp {
|
||||
address = 127.0.0.1
|
||||
port = 10026
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# Drew Crawford sets the auth-worker process to run as the mail user, but we don't care if it runs as root.
|
||||
|
||||
|
|
48
scripts/spamassassin.sh
Normal file
48
scripts/spamassassin.sh
Normal file
|
@ -0,0 +1,48 @@
|
|||
# Spam filtering with spamassassin via spampd.
|
||||
|
||||
apt-get -q -y install spampd dovecot-antispam
|
||||
|
||||
# Hook into postfix. Replace dovecot with spampd as the mail delivery agent.
|
||||
tools/editconf.py /etc/postfix/main.cf virtual_transport=lmtp:[127.0.0.1]:10025
|
||||
|
||||
# Hook into dovecot. This is actually the default but we don't want to lose track of it.
|
||||
tools/editconf.py /etc/default/spampd DESTPORT=10026
|
||||
|
||||
# Automatically move spam into a folder called Spam. Enable the sieve plugin.
|
||||
# (Note: Be careful if we want to use multiple plugins later.)
|
||||
# The sieve scripts are installed by users_update.sh.
|
||||
sudo sed -i "s/#mail_plugins = .*/mail_plugins = \$mail_plugins sieve/" /etc/dovecot/conf.d/20-lmtp.conf
|
||||
|
||||
# Enable the antispam plugin to detect when a message moves between folders so we can
|
||||
# pass it to sa-learn for training. (Be careful if we use multiple plugins later.)
|
||||
sudo sed -i "s/#mail_plugins = .*/mail_plugins = \$mail_plugins antispam/" /etc/dovecot/conf.d/20-imap.conf
|
||||
|
||||
# When mail is moved in or out of the dovecot Spam folder, re-train.
|
||||
# from http://wiki2.dovecot.org/Plugins/Antispam
|
||||
cat > /usr/bin/sa-learn-pipe.sh << EOF;
|
||||
cat<&0 >> /tmp/sendmail-msg-\$\$.txt
|
||||
/usr/bin/sa-learn \$* /tmp/sendmail-msg-\$\$.txt > /dev/null
|
||||
rm -f /tmp/sendmail-msg-\$\$.txt
|
||||
exit 0
|
||||
EOF
|
||||
|
||||
chmod a+x /usr/bin/sa-learn-pipe.sh
|
||||
|
||||
cat > /etc/dovecot/conf.d/99-local-spampd.conf << EOF;
|
||||
plugin {
|
||||
antispam_backend = pipe
|
||||
antispam_spam_pattern_ignorecase = SPAM
|
||||
antispam_allow_append_to_spam = yes
|
||||
antispam_pipe_program_spam_arg = /usr/bin/sa-learn-pipe.sh --spam
|
||||
antispam_pipe_program_notspam_arg = /usr/bin/sa-learn-pipe.sh --ham
|
||||
antispam_pipe_program = /bin/bash
|
||||
}
|
||||
EOF
|
||||
|
||||
# Initial training?
|
||||
# sa-learn --ham storage/mail/mailboxes/*/*/cur/
|
||||
# sa-learn --spam storage/mail/mailboxes/*/*/.Spam/cur/
|
||||
|
||||
sudo service spampd restart
|
||||
sudo service dovecot restart
|
||||
|
22
scripts/users_update.sh
Normal file
22
scripts/users_update.sh
Normal file
|
@ -0,0 +1,22 @@
|
|||
# Install dovecot sieve scripts to automatically move spam into the Spam folder.
|
||||
|
||||
db_path=$STORAGE_ROOT/mail/users.sqlite
|
||||
|
||||
for user in `echo "SELECT email FROM users;" | sqlite3 $db_path`; do
|
||||
maildir=`echo $user | sed "s/\(.*\)@\(.*\)/\2\/\1/"`
|
||||
|
||||
# Write the sieve file to move mail classified as spam into the spam folder.
|
||||
mkdir -p $STORAGE_ROOT/mail/mailboxes/$maildir; # in case user has not received any mail
|
||||
cat > $STORAGE_ROOT/mail/mailboxes/$maildir/.dovecot.sieve << EOF;
|
||||
require ["regex", "fileinto", "imap4flags"];
|
||||
|
||||
if allof (header :regex "X-Spam-Status" "^Yes") {
|
||||
setflag "\\\\Seen";
|
||||
fileinto "Spam";
|
||||
stop;
|
||||
}
|
||||
EOF
|
||||
|
||||
|
||||
done
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
import imaplib, os
|
||||
|
||||
username = "testuser@" + os.environ.get("DOMAIN", "testdomain.com")
|
||||
|
||||
M = imaplib.IMAP4_SSL(os.environ["INSTANCE_IP"])
|
||||
M.login("testuser@testdomain.com", "testpw")
|
||||
M.login(username, "testpw")
|
||||
M.select()
|
||||
print("Login successful.")
|
||||
typ, data = M.search(None, 'ALL')
|
||||
|
|
|
@ -4,20 +4,27 @@ import sys, re
|
|||
|
||||
# sanity check
|
||||
if len(sys.argv) < 3:
|
||||
print("usage: python3 editconf.py /etc/file.conf NAME=VAL [NAME=VAL ...]")
|
||||
print("usage: python3 editconf.py /etc/file.conf [-s] NAME=VAL [NAME=VAL ...]")
|
||||
sys.exit(1)
|
||||
|
||||
# parse command line arguments
|
||||
filename = sys.argv[1]
|
||||
settings = sys.argv[2:]
|
||||
|
||||
delimiter = "="
|
||||
delimiter_re = r"\s*=\s*"
|
||||
if settings[0] == "-s":
|
||||
settings.pop(0)
|
||||
delimiter = " "
|
||||
delimiter_re = r"\s+"
|
||||
|
||||
# create the new config file in memory
|
||||
found = set()
|
||||
buf = ""
|
||||
for line in open(filename):
|
||||
for i in range(len(settings)):
|
||||
name, val = settings[i].split("=", 1)
|
||||
m = re.match("\s*" + re.escape(name) + "\s*=\s*(.*?)\s*$", line)
|
||||
m = re.match("\s*" + re.escape(name) + delimiter_re + "(.*?)\s*$", line)
|
||||
if m:
|
||||
# If this is already the setting, do nothing.
|
||||
if m.group(1) == val:
|
||||
|
@ -33,7 +40,7 @@ for line in open(filename):
|
|||
break
|
||||
|
||||
# add the new setting
|
||||
buf += name + "=" + val + "\n"
|
||||
buf += name + delimiter + val + "\n"
|
||||
|
||||
# note that we've applied this option
|
||||
found.add(i)
|
||||
|
@ -46,7 +53,8 @@ for line in open(filename):
|
|||
# Put any settings we didn't see at the end of the file.
|
||||
for i in range(len(settings)):
|
||||
if i not in found:
|
||||
buf += settings[i] + "\n"
|
||||
name, val = settings[i].split("=", 1)
|
||||
buf += name + delimiter + val + "\n"
|
||||
|
||||
# Write out the new file.
|
||||
with open(filename, "w") as f:
|
||||
|
|
Loading…
Reference in a new issue