100% found this document useful (1 vote)
162 views20 pages

Installing Postfix - Clamav - Spamassassin - Dovecot - Postfixadmin On Debian Squeeze

The document discusses installing and configuring a mail server with Postfix, Dovecot, and PostfixAdmin on Debian. It covers installing packages, configuring the PostfixAdmin database, configuring Postfix to use virtual domains and mailboxes from the database, and setting permissions.

Uploaded by

Santhosh Kumar
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
100% found this document useful (1 vote)
162 views20 pages

Installing Postfix - Clamav - Spamassassin - Dovecot - Postfixadmin On Debian Squeeze

The document discusses installing and configuring a mail server with Postfix, Dovecot, and PostfixAdmin on Debian. It covers installing packages, configuring the PostfixAdmin database, configuring Postfix to use virtual domains and mailboxes from the database, and setting permissions.

Uploaded by

Santhosh Kumar
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 20

Installing

If you're using wheezy, skip adding squeeze-backports to sources.list.d and the pin
in preferences.d. Also, you won't need to specify any release from which to install
packages (everything can just come from wheezy directly).

We'll be installing dovecot 2.x, which is in squeeze-backports:

echo deb http://backports.debian.org/debian-backports squeeze-backports main >


/etc/apt/sources.list.d/squeeze_backports.list
The postfixadmin package is only available in wheezy. However, since it's quite
simply a web application that doesn't require specific versions of its
dependencies, we can install the package directly in squeeze. So first, we'll want
to ensure we can access wheezy packages, but that they don't upgrade automatically:

echo deb http://debian.mirror.iweb.ca/debian wheezy main >


/etc/apt/sources.list.d/wheezy.list
cat > /etc/apt/preferences.d/no_auto_wheezy <<EOF
Package: *
Pin: release n=squeeze
Pin-Priority: 900

Package: *
Pin: release n=wheezy
Pin-Priority: -10
EOF
Move on to installing packages. We'll want to install postfixadmin's dependencies
from squeeze, but the package itself from wheezy:

apt-get update
apt-get install postfix postfix-mysql openssl ssl-cert
apt-get install php5-imap php5-mysql wwwconfig-common dbconfig-common
apt-get -t squeeze-backports install dovecot-imapd dovecot-mysql
apt-get -t wheezy install postfixadmin
Let postfixadmin create its own database during installation. This'll make our work
easier.

Configuring
Priming the database
Since we'd like to be able to test each step of the configuration, we'll need to
start by building the database structure and by priming it with some data. This
might seem a bit backwards, since our starting point is the web app that will
control accounts when everything is set up, but actually the web app only depends
on the presence of the database and the web server to let us play with it (e.g. you
can control accounts as long as you have a database. Postfix and Dovecot will be
using the data from the database when we'll tell them to).

We'll start by modifying the config file to our needs. Let's use the
/etc/postfixadmin/config.local.php file so that our changes survive package
upgrades. Here's an example of what you might want to override (declare) in this
file:

<?
$CONF['default_language'] = 'en';
$CONF['admin_email'] = '[email protected]';
$CONF['default_aliases'] =array (
'abuse' => '[email protected]',
'hostmaster' => '[email protected]',
'postmaster' => '[email protected]',
'webmaster' => '[email protected]'
);
$CONF['domain_path'] = 'YES';
$CONF['domain_in_mailbox'] = 'NO';
$CONF['aliases'] = 0; // optional : I'm setting a default of unlimited aliases for
new domains
$CONF['mailboxes'] = 0; // idem
$CONF['backup'] = 'NO'; // In my case, the users won't need this (I'll automate
the backup)
$CONF['sendmail'] = 'NO'; // It's better to have a real webmail
$CONF['fetchmail'] = 'NO'; // This could be useful, but for now I prefer
simplifying the interface
$CONF['user_footer_link'] = 'http://your.host/postfixadmin/';
$CONF['footer_text'] = 'Return to http://your.host/postfixadmin/';
$CONF['footer_link'] = 'http://your.host/postfixadmin/';
$CONF['welcome_text'] = <<<EOM
Hi,

Welcome to the team, sonny! Here at "someprovider" inc. we pride ourselves in our
world domination efforts.
blah blah blah blah
EOM;
$CONF['create_mailbox_subdirs_prefix'] = ''; // recommended value that should be
used with Dovecot.
$CONF['theme_logo'] = 'images/logo-default.png'; // optional.. it's the right-most
part of a URL so it needs to be accessible via your web server
$CONF['theme_css'] = 'css/default.css'; // idem
Go to the postfixadmin's setup page on your web server:
http://your.host/postfixadmin/setup.php This will create the tables in which
postfixadmin keeps accounts and other info.

Next we need to create a setup password. This password will ensure that setup.php
is not used by just anybody to create unwanted "super admin" accounts. Enter a
password for the setup page and send the form. Then, copy the line that's printed
out with your password's hash (should look like a line with $CONF in the example
configuration overrides above) and paste it at the end of
/etc/postfixadmin/config.local.php.

Visit setup.php again (reload the page). This time, type in the setup password,
then an email address, and enter a password for the new super admin account and
send the form. This email address needs to be from a domain that actually exists,
not on the server you're setting up, else you'll get the message "Admin is not a
valid email address!". If you really need to use an address from a domain that does
not resolve, you can add the line "$CONF['emailcheck_resolve_domain']='NO';" to
config.local.php). That email will then have super admin privileges on the data:
this means that it can administrate all of the domains understood by postfix and
manage administrator accounts (other accounts that can administrate a subset of the
domains).

Now go to the main postfix admin page and login with the super admin you've just
created. Once inside, create a new domain: in the menus, hover over 'Domain List'
and click on 'New Domain'. For this howto, I'll create the domain example.com

Create a new mailbox by hovering over 'Virtual List' and clicking on 'Add Mailbox'.
I'll create the mailbox named someone, thus creating the e-mail
[email protected].

Now we should have enough info in the database for testing the next steps.

Basic SMTP with virtual domains and mailboxes with Postfix


Create the directory that will hold the mailboxes for the virtual accounts and give
it to the mail user so that Dovecot, our final LDA, can create directories and
files in there:

mkdir /var/mail/vmail
chown mail:mail /var/mail/vmail
Create a read-only user on the postfixadmin database:

mysql -p -e "GRANT SELECT ON postfixadmin.* TO postfix@localhost IDENTIFIED BY


'something';"
We'll put all config files for accessing Postfix's virtual resources (in the
database) via MySQL into a directory that we need to create:

mkdir /etc/postfix/virtual
Now, under the directory we've just created, we'll create a bunch of config files:

relay_domains.cf

user = postfix
password = something
hosts = localhost
dbname = postfixadmin
query = SELECT domain FROM domain WHERE domain='%s' AND backupmx = true
alias_maps.cf

user = postfix
password = something
hosts = localhost
dbname = postfixadmin
query = SELECT goto FROM alias a INNER JOIN domain d ON a.domain=d.domain WHERE
a.address='%s' AND d.active = true AND a.active = true
domains_maps.cf

user = postfix
password = something
hosts = localhost
dbname = postfixadmin
query = SELECT domain FROM domain WHERE domain='%s' AND backupmx = false AND active
= true
mailbox_maps.cf

user = postfix
password = something
hosts = localhost
dbname = postfixadmin
query = SELECT maildir FROM mailbox m INNER JOIN domain d ON m.domain=d.domain
WHERE m.username='%s' AND m.active = true AND d.active = true
mailbox_limits.cf

user = postfix
password = something
hosts = localhost
dbname = postfixadmin
query = SELECT quota FROM mailbox m INNER JOIN domain d ON m.domain=d.domain WHERE
m.username='%s' AND m.active = true AND d.active = true
If you've read the tutorials that I link to in the bibliography, or searched for
tutorials about virtual domains and mailboxes at all, you might have observed that
contrary to all the other tutorials out there, I don't use simple SELECT statements
in alias_maps.cf, mailbox_maps.cf and mailbox_limits.cf. This is because what they
teach you is buggy! When you disable a domain in postfixadmin you expect that
domain to cease working altogether. With simple SELECT statements you can still
login to individual mailboxes and send out e-mail even though the domain has been
disabled! So to fix that I use an INNER JOIN on the domain table to check whether
the appropriate domain is active or not. With this, when you disable a domain in
the web interface, it stops working for real; expect support calls if users were
still working with their accounts at that moment ;)

The newly created files contain a database password so you might like to tighten
permissions a little bit so that only the postfix daemon is authorized to read
them:

chown -R root:postfix /etc/postfix/virtual


chmod 0750 /etc/postfix/virtual
chmod 0640 /etc/postfix/virtual/*.cf
With the above permissions you should be fine, but if the postfix daemon logs a
bunch of messages like the following in /var/log/mail.err, it means the daemon
can't access the files in the /etc/postfix/virtual directory so you should fix
their permissions:

Sep 21 23:59:39 debian-squeeze postfix/proxymap[2510]: fatal: open


/etc/postfix/virtual/relay_domains.cf: Permission denied
Now that we have everything, we need to indicate to postfix that it needs to use
those configuration files:

postconf -e 'relay_domains = proxy:mysql:/etc/postfix/virtual/relay_domains.cf'


postconf -e 'virtual_alias_maps = proxy:mysql:/etc/postfix/virtual/alias_maps.cf'
postconf -e 'virtual_mailbox_domains =
proxy:mysql:/etc/postfix/virtual/domains_maps.cf'
postconf -e 'virtual_mailbox_maps =
proxy:mysql:/etc/postfix/virtual/mailbox_maps.cf'
postconf -e 'virtual_create_maildirsize = yes'
postconf -e 'virtual_mailbox_extended = yes'
postconf -e 'virtual_mailbox_limit_maps =
proxy:mysql:/etc/postfix/virtual/mailbox_limit_maps.cf'
postconf -e 'virtual_mailbox_limit_override = yes'
postconf -e "virtual_maildir_limit_message = Sorry, the user's maildir has
overdrawn his diskspace quota, please try again later."
postconf -e 'virtual_overquota_bounce = yes'
postconf -e 'virtual_mailbox_base = /var/mail/vmail'
postconf -e "virtual_minimum_uid = $(id -u mail)"
postconf -e 'virtual_transport = dovecot'
postconf -e 'dovecot_destination_recipient_limit = 1'
postconf -e "virtual_uid_maps = static:$(id -u mail)"
postconf -e "virtual_gid_maps = static:$(id -g mail)"
postconf -e 'transport_maps = hash:/etc/postfix/transport'
touch /etc/postfix/transport
postmap /etc/postfix/transport
Now add the following line to the end of /etc/postfix/master.cf:

dovecot unix - n n - - pipe


flags=DRhu user=mail:mail argv=/usr/lib/dovecot/deliver -f ${sender} -d ${user}@$
{nexthop} -a ${recipient}
And reload config:

postfix reload
To save up on storage space used, we'll enable reading and writing gzip files in
Dovecot. Delivery and retrieval will use a little more CPU with this setting, but
e-mail files should take at least twice as less disk space. Add the following line
to /etc/dovecot/conf.d/10-mail.conf:

mail_plugins = zlib
And in /etc/dovecot/conf.d/90-plugin.conf, add configuration for the plugin inside
the plugin block, like this:

plugin {
zlib_save_level = 6
zlib_save = gz
}
XXX: here there's a bug: dovecot doesn't know about users at this point because we
haven't configured its userdb dictionary method. You can either comment out
"virtual_transport" to have postfix do the final delivery, or configure userdb and
all glue from next section (auth with dovecot) before testing delivery. Since this
HOWTO is getting really old, I won't reorganize everything, but a notice about this
problem seemed required.

Now restart Dovecot to enable the plugin:

service dovecot restart


Testing delivery
There we are, we have a functional virtual mailboxes-based SMTP reception system.
It's not yet fit for relaying mail for users of the domains your server is hosting,
but that'll come later. If you'd like to test out your setup, you can use the
following:

apt-get install swaks


swaks [email protected] --server=localhost
ls -l /var/mail/vmail/example.com/someone/new # You should see the delivered mail
there.
Mail retrieval with Dovecot
Next stop, mail retrieval with dovecot. In dovecot 2.x, most of the configuration
has been broken down into files in /etc/dovecot/conf.d, but some of it stayed in
files laying in /etc/dovecot. Let's begin by configuring the SQL connection. We
need to tell dovecot where to find user passwords. Remove contents of
/etc/dovecot/dovecot-sql.conf.ext and replace it with the following:

driver = mysql
connect = host=127.0.0.1 dbname=postfixadmin user=postfix password=something
default_pass_scheme = MD5-CRYPT
password_query = SELECT username as user, password, CONCAT('/var/mail/vmail/',
maildir) as userdb_home, 8 as userdb_uid, 8 as userdb_gid FROM mailbox INNER JOIN
domain ON mailbox.domain=domain.domain WHERE username='%u' AND domain.active = true
AND mailbox.active = true;
user_query = SELECT CONCAT('/var/mail/vmail/', maildir) as home, 8 as uid, 8 as gid
FROM mailbox INNER JOIN domain ON mailbox.domain=domain.domain WHERE username='%u'
AND domain.active = true AND mailbox.active = true;
In a similar fashion to what we did in the postfix SQL config files, the above
queries will prevent users to login to dovecot and postfix (via SASL for sending
out email) when their domain has been disabled.

Now, replace the contents of /etc/dovecot/conf.d/10-mail.conf with the following:

mail_location = maildir:%h
mail_uid = mail
mail_gid = mail
first_valid_uid = 8
first_valid_gid = 8
namespace inbox {
inbox = yes
}
Replace the contents of 10-auth.conf by:

auth_mechanisms = plain login


passdb {
driver = sql
args = /etc/dovecot/dovecot-sql.conf.ext
}
userdb {
driver = sql
args = /etc/dovecot/dovecot-sql.conf.ext
}
Open up the file 10-master.conf in an editor and somewhere near the end of the
file, uncomment and change the line #user = root so that it looks something like
the following:

service auth-worker {
user = nobody
}
Replace the contents of 10-ssl.conf by the following. For the howto, we'll be using
the self-signed certificate that's created by the dovecot package upon
installation. If you're using your own certificate change the path to point to the
right files for your case:

ssl = required
ssl_cert = </etc/ssl/certs/dovecot.pem
ssl_key = </etc/ssl/private/dovecot.pem
Now, restart the service:

service dovecot restart


Testing mail retrieval with Dovecot
And now we should be able to test a connection. There's no quick and handy tool for
testing this out, so brace yourselves: we'll have to make an IMAP session manually
(it's not very complicated, really). From your computer, or another point which
should have acces to the IMAP server:

openssl s_client -connect youhost.domain:143 -starttls imap


[... you'll see a bunch of info about the SSL certificate bein printed out]
. login [email protected] something
[... list of capabilities]
. select inbox
[... if you did at least one test in the last step, you should see 1 EXISTS in the
output]
. fetch 1 rfc822.text
[... message body]
. logout
Let's try logging in without encryption to see if we get through (we shouldn't !).
If the server responds that login was successful there's a problem somewhere.

telnet localhost 143


. login [email protected] something
* BAD [ALERT] Plaintext authentication not allowed without SSL/TLS, but your client
did it anyway. If anyone was listening, the password was exposed.
. logout
Mail delivery for authenticated users
We're close to going round the loop in the graph. We'll configure SMTP to let
people relay mail to external domains (e.g. send mail to domains that we are not
hosting), but only authenticated users should be able to do that, else you have an
open relay and can be the source of much spam in the world! Authentication and
reception of e-mails that are to be relayed elsewhere needs to be encrypted.

We'll need to configure Postfix so that it knows how to behave with SSL
connections, and then we'll tell Postfix to use Dovecot's SASL library for
authentication (Postfix will use Dovecot's authentication mechanism we configured
earlier).

Dovecot SASL
First things first: let's tell Dovecot how to "expose" SASL, its login facilities.
In /etc/dovecot/conf.d/10-master.conf, modify the block "service auth" so that it
looks like this:

service auth {
unix_listener /var/spool/postfix/private/auth {
mode = 0660
user = postfix
group = postfix
}
}
When you're done, restart dovecot:

service dovecot restart


Postfix STARTTLS + SASL on port 25
Let's now work on Postfix. First, configure TLS. For this example, I'll use the
same cert as was used with Dovecot:

postconf -e 'smtpd_tls_cert_file = /etc/ssl/certs/dovecot.pem'


postconf -e 'smtpd_tls_key_file = /etc/ssl/private/dovecot.pem'
postconf -e 'smtp_tls_session_cache_database = btree:
$data_directory/smtp_tls_session_cache'
postconf -e 'smtpd_tls_session_cache_database = btree:
$data_directory/smtpd_tls_session_cache'
postconf -e 'smtp_tls_security_level = may'
postconf -e 'smtpd_tls_security_level = may'
postconf -e 'smtpd_tls_ask_ccert = no'
postconf -e 'smtpd_tls_loglevel = 0'
postconf -e 'tls_random_source = dev:/dev/urandom'
Then, we want to tell it to use dovecot's SASL style authentication:

postconf -e 'smtpd_sasl_auth_enable = yes'


postconf -e 'smtpd_tls_auth_only = yes'
postconf -e 'smtpd_sasl_type = dovecot'
postconf -e 'smtpd_sasl_path = private/auth'
postconf -e 'smtpd_sasl_exceptions_networks = $mynetworks'
postconf -e 'smtpd_sasl_security_options = noanonymous'
postconf -e 'smtpd_sasl_tls_security_options = noanonymous'
postconf -e 'broken_sasl_auth_clients = yes'
postconf -e 'smtpd_relay_restrictions =
permit_mynetworks,permit_sasl_authenticated,reject_unauth_destination'
postconf -e 'smtpd_recipient_restrictions =
permit_mynetworks,reject_non_fqdn_recipient,permit_sasl_authenticated,reject_unauth
_destination,reject_rbl_client zen.spamhaus.org,reject_rhsbl_helo
dbl.spamhaus.org,reject_rhsbl_sender dbl.spamhaus.org'
postconf -e 'smtpd_sender_restrictions =
permit_mynetworks,reject_unknown_sender_domain'
postconf -e 'smtpd_helo_restrictions = reject_invalid_helo_hostname'
postconf -e 'smtpd_data_restrictions =
reject_unauth_pipelining,reject_multi_recipient_bounce,permit'
# Those two configs should help a little bit with older spammers
postconf -e 'smtpd_helo_required = yes'
postconf -e 'disable_vrfy_command = yes'
postfix reload
Postfix STARTTLS + SASL on port 587 (mail submission)
Some ISPs have taken very drastic measures to block some worms and spam and they
decided to entirely block port 25 out of home users. For those users, mail delivery
will not work. So we need to configure Postfix to listen to another port: the Mail
Submission port, 587.

In /etc/postfix/master.cf, right above the line that starts with "smtp inet", add
the following:

submission inet n - - - - smtpd


-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
-o smtpd_sasl_type=dovecot
-o smtpd_sasl_path=private/auth
-o smtpd_sasl_security_options=noanonymous
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
-o smtpd_sender_login_maps=proxy:mysql:/etc/postfix/virtual/alias_maps.cf
-o smtpd_sender_restrictions=reject_sender_login_mismatch
-o
smtpd_recipient_restrictions=reject_non_fqdn_recipient,permit_sasl_authenticated,re
ject
Now reload postfix config:

postfix reload
Testing mail relay
To test mail relay for authenticated users, you should go to another computer which
should have access to the mail server.

First, let's see if things work. Watch out not to put any sensible password here.
you can remove the --auth-password argument to have it ask the password upon
startup, which will be echoed to the screen (d'oh!!):

swaks --tls --from [email protected] --to external@email_address --server


server.domain:25 --auth LOGIN --auth-user [email protected] --auth-password
something
swaks --tls --from [email protected] --to external@email_address --server
server.domain:587 --auth LOGIN --auth-user [email protected] --auth-password
something
Now let's verify that relaying without being authenticated fails:

# This should give "Relay access denied"


swaks --tls --from [email protected] --to external@email_address --server
server.domain:25

# This should give "Client host rejected: Access denied"


swaks --tls --from [email protected] --to external@email_address --server
server.domain:587
Filtering out undesired crap
Now that we're able to receive and send email and let users read them, we should
make our users' lives better by filtering crap out. We'll use four different tools
to reject undesired messages: ClamAV, greylisting, SpamAssassin and Sender Policy
Framework checking.

Like described at the beginning of the howto, we'll be using Milters so that we can
reject crap before queueing it on the disk, so legitimate senders will know that
their message didn't get through with a bounce that states a reason why it wasn't
accepted.

In all cases, we'll want to set postfix to accept mail by default when a milter
fails to function properly, else we'd loose e-mails because of the errors:

postconf -e 'milter_default_action = accept'


clamav-milter
Scanning mail with ClamAV is all about preventing virii and also a bunch of
phishing and scamming messages from getting to users. This helps you to remove
infections from spreading on your corporate / community computers (because -- yes
-- some people will open those infected files if they reach them). Running ClamAV
uses a good amount of RAM, so if you're setting up a mail system for yourself and
you think you'll be wise enough to avoid infected files, you can skip this step.
However, scanning for virii is almost mandatory for a system that will deliver mail
for a good number of users, especially when a bunch of users are not computer
geeks. But even for computer geeks, the sheer volume of crap that can get to their
email is going to be annoying them badly.

So let's start. First, install the milter and some additional signature files for
filtering more email-related badness (we need to install the backports version of
the package to get up-to-date signatures correctly):

apt-get install clamav-milter


apt-get -t squeeze-backports install clamav-unofficial-sigs
Next, we need to tell it to let postfix have write access to it's socket. Edit
/etc/default/clamav-milter and uncomment the last line:

SOCKET_RWGROUP=postfix
Note that if you are running wheezy with the wheezy-updates source (and you
should!) with the clamav-milter version 0.98.5, the file in /etc/default doesn't
exist anymore and the bug with regards to the socket permission has been fixed. So
you should skip editing the file as mentioned just above and instead ensure you
have the following in your /etc/clamav/clamav-milter.conf:

MilterSocketGroup postfix
MilterSocketMode 660
Postfix runs in a chroot by default, so we'll have to reconfigure the milter to
place its socket inside postfix's chroot directory. But first, we need to create a
directory for the socket:

mkdir /var/spool/postfix/clamav
chown clamav /var/spool/postfix/clamav
We also want to change the action taken when an infected e-mail is detected to
reject it immediately. To ensure our config stays through upgrades, we'll do it the
debian way: run dpkg-reconfigure clamav-milter and answer the following:

Handle configuration automatically --> yes


User for daemon --> clamav
Additional groups --> none (empty field)
path to socket --> /var/spool/postfix/clamav/clamav-milter.ctl
group owner for the socket --> clamav
permissions (mode) for socket --> 660
remove stale socket --> yes
wait timeout for clamd --> 120
foreground --> no
chroot --> none (empty field)
pid file --> /var/run/clamav/clamav-milter.pid
temporary path --> /tmp
clamd socket --> unix:/var/run/clamav/clamd.ctl
hosts excluded for scanning --> none (empty field)
mail whitelist --> none (empty field)
action for "infected" mail --> reject
action on error --> defer
reason for rejection --> Rejecting harmful email: %v found.
headers -> replace
log file --> /var/log/clamav/clamav-milter.log
disable log file locking --> no
maximum log file size --> 0
log time --> yes
use syslog --> no
log facility (type of syslog message) --> LOG_LOCAL6
verbose logging --> no
log level when infected --> off
log level when no threat --> off
size limit for scanned messages --> 25
The above reconfiguration should have automatically restarted clamav-milter. Verify
that the socket is in place. Normally, the clam daemon should be enabled in the
boot procedure, but it's possible that you need to start it manually right after
install: service clamav-daemon start

Next, we'll configure Postfix to use the milter to inspect incoming e-mail.
Remember the smtp process is running inside a chroot, so the path needs to have its
root at the top of the chroot dir:

postconf -e 'smtpd_milters = unix:/clamav/clamav-milter.ctl'


postfix reload
Testing the filter by sending a virus
To test this out, we'll have to send a malicious file to the SMTP server in the
hope that it will block it. For this, you can install the package clamav-testfiles
on your computer; it will install sample virus files under /usr/share/clamav-
testfiles. Let's send one as an e-mail attachment:

swaks [email protected] --server=localhost --attach - --suppress-data <


/usr/share/clamav-testfiles/clam.exe
You should see the rejection message you configured towards the end:

<** 550 5.7.1 Rejecting harmful email: ClamAV-Test-File found.


spamass-milter
Next thing we want to add in the filtering pipe is spam filtering. SpamAssassin is
a powerful solution used by many for this purpose. We'll integrate it with postfix
via a milter so that we can reject very awful mail right up front.

Let's start by installing the necessary packages:

apt-get install spamass-milter


Now, in /etc/default/spamass-milter we want to add "-m" so that it doesn't change
the subject header (required for running as a milter with Postfix), "-r -1" so that
it rejects what SpamAssassin flags as spam and "-I" to avoid scanning mail sent by
logged-in users:

OPTIONS="-u spamass-milter -i 127.0.0.1 -m -r -1 -I"


Restart the milter:

service spamass-milter restart


The spamass-milter connects, by default, to a spamd instance running on the same
server (localhost). We need to configure SpamAssassin and start it. However, since
it runs under root by default, we'll start by creating a dedicated user for the
daemon:

adduser --shell /bin/false --home /var/lib/spamassassin --disabled-password


--disabled-login --gecos "" spamd
Open up /etc/default/spamassassin and change three lines in it to enable the
daemon, the automatic update for rules and also to add options so that we use the
user we created above instead of "root" and so that it uses the helper directory we
created above. The lines should look like the following:

ENABLED=1
CRON=1
OPTIONS="--create-prefs --max-children 5 --helper-home-dir=/var/lib/spamassassin -u
spamd -g spamd -x"
Now let's update the rules for the first time and restart the daemon:

sa-update
service spamassassin restart
We have all the needed pieces, so let's tell postfix to use the milter:

postconf -e 'smtpd_milters = unix:/clamav/clamav-milter.ctl,


unix:/spamass/spamass.sock'
postfix reload
Testing the spam filter
For testing this, we'll use the special string from GTUBE. This string triggers a
special rule that sets the score to a very high value so that SpamAssassin flags
the mail as spam without a doubt.

Since we installed the package "clamav-unofficial-sigs" earlier, ClamAV will be


catching a bunch of spams, phishing and scams by signature. When I first tried
using the GTUBE signature to verify spam filtering, it was filtered by ClamAV
instead of SpamAssassin, which is not what we want to verify here. So I've had to
disable the clamav milter in /etc/postfix/main.cf so that the emails goes straight
to spamass-milter.

On your computer, download a text file with the GTUBE signature line and use it as
the body of a test email:

wget -O /tmp/gtube.txt https://spamassassin.apache.org/gtube/gtube.txt


swaks --from [email protected] [email protected]
--server=your.domain --body=/tmp/gtube.txt
The email should be blocked with the message:

<** 550 5.7.1 Blocked by SpamAssassin


Don't forget to re-enable the clamav milter after your tests are done.

milter-greylist
Greylisting is a simple method that drives off a good portion of dumb spammer bots.
It bases on the assumption that spammers won't come back after their deed is done.
So when it first receives mail from a sender, it refuses it with a "Temporarily
unavailable" error message that has the purpose to make the client try again later.
The sender is then accepted from the second trial onward. Since most spammers don't
come back, they'll get that defferal message and it'll prevent them from sending
you their crap.

The reason we're installing this milter last is that it can be a bit annoying when
testing the other milters to have to wait around 30mins before being able to send
actual tests. However, since greylisting is lightweight and cuts out a bunch of old
spammers, we'll place it as the first one in the list so that we avoid running
ClamAV and SpamAssassin on most useless spam.
Let's install the milter:

apt-get install milter-greylist


Edit the config file /etc/milter-greylist/greylist.conf place the socket file under
Postfix's chroot directory. We'll also want to edit the ACLs properly so that the
milter works like we intend it to (you probably want to edit the list "my network"
so that if reflects your server's real situation). Here's a condensed version of
the resulting config file. Add more ACLs as you see fit:

pidfile "/var/run/milter-greylist.pid"
dumpfile "/var/lib/milter-greylist/greylist.db" 600
dumpfreq 10m
socket "/var/spool/postfix/milter-greylist/milter-greylist.sock" 660
user "greylist"
quiet
list "my network" addr { 127.0.0.1/8 192.0.2.0/24 }
list "broken mta" addr { \
[... cut for brevity. You might consider keeping this list here from default
config]
}
racl whitelist list "my network"
racl whitelist list "broken mta"
racl greylist default delay 30m autowhite 30d
Now, edit /etc/default/milter-greylist and set the following (make sure that the
socket path is good, since the value that is commented out by default points to a
different filename than the one set by default in the milter config file -- the
filename that we're using):

ENABLED=1
SOCKET="/var/spool/postfix/milter-greylist/milter-greylist.sock"
Let's create the directory where the socket will be held. Because of a longstanding
bug in the debian package we need to hack our way to having the right permissions
for the socket. We can then restart the milter:

mkdir /var/spool/postfix/milter-greylist
chmod 2755 /var/spool/postfix/milter-greylist
chown greylist:postfix /var/spool/postfix/milter-greylist
service milter-greylist restart
The only step left is to let Postfix know how to use that milter. We'll want to
place it before the two milters we set above since they are both very slow and CPU
intensive. This way, greylisting will remove dumb spammers while also avoiding them
to overload your CPU (which could easily lead to a denial of service):

postconf -e 'milter_connect_macros = i b j _ {daemon_name} {if_name} {client_addr}'


postconf -e 'smtpd_milters = unix:/milter-greylist/milter-greylist.sock,
unix:/clamav/clamav-milter.ctl, unix:/spamass/spamass.sock'
postfix reload
Testing Greylist
If you want to have a better understanding of what's going on, you can comment out
the line "quiet" in /etc/milter-greylist/greylist.conf. This will make the
rejection message specify how much time is left for the greylisting.

Send an e-mail to a user on the server in the same manner as you did above when
testing delivery, although for this test you'll need to send the e-mail from
another computer (since we whitelisted 127.0.0.1):

swaks [email protected] --server=your.host


You should get rejected with a message looking like this:
<** 451 4.7.1 Greylisting in action, please come back in 00:23:33
Wait until that period is elapsed and re-try sending your mail. You should now be
accepted.

Make sure you go back to the config file and comment out the "quiet" line again so
that you don't tell spammers how much time they need to wait.

Additional functionality
Vacation autoreplies
Postfixadmin comes with a script for handling vacation/away messages (e.g.
autoreplies). By default, though, that script is not functional. And the reason for
this is that some of its dependencies are in "non-free". So in order to activate
this feature, we'll first have to ensure that we are using the non-free section.
Since I don't yet, here's how I've added it:

sed -i 's/\(main\)$/\1 contrib non-free/' /etc/apt/sources.list


apt-get update
Now, all the remaining steps come almost exaclty as they were written on this
tutorial (and also documented in
/usr/share/doc/postfixadmin/examples/VIRTUAL_VACATION/INSTALL.TXT.gz, which comes
with the postfixadmin package).

First, install the script's dependencies:

apt-get install libmail-sender-perl libdbd-mysql-perl libemail-valid-perl libmime-


perl liblog-log4perl-perl liblog-dispatch-perl libgetopt-argvfile-perl libmime-
charset-perl libmime-encwords-perl
Next, we'll create a user solely for running the script. It will run as a transport
for postfix, so we need to isolate it from accessing anything useful. We'll also
copy the script into the user's home directory. Lastly, we'll setup a log directory
in which the user is able to write so that we can have something to debug problems:

groupadd -r -g 65501 vacation


useradd -r -u 65501 -g vacation -d /var/spool/vacation -s /sbin/nologin vacation
mkdir /var/spool/vacation
cp /usr/share/doc/postfixadmin/examples/VIRTUAL_VACATION/vacation.pl.gz
/var/spool/vacation/
gunzip /var/spool/vacation/vacation.pl.gz
chown -R vacation:vacation /var/spool/vacation
chmod -R 0700 /var/spool/vacation
The script parses, if it exists, an alternate configuration file in which we can
override some values. But first, since the script needs to be able to update the
vacation_notification table, let's grant insertion privileges to the "postfix" user
so that we can use the lesser-priviledged account with it:

mysql -e 'GRANT INSERT,UPDATE ON postfixadmin.vacation_notification TO


"postfix"@"localhost"';
Create the file /etc/postfixadmin/vacation.conf and set its content to the
following:

# db_type - uncomment one of these


our $db_type = 'mysql';

# leave empty for connection via UNIX socket


our $db_host = '';

# connection details
our $db_username = 'postfix';
our $db_password = 'something';
our $db_name = 'postfixadmin';
our $vacation_domain = 'autoreply.example.com';

# Set to 1 to enable logging to syslog.


our $syslog = 1;
# 2 = debug + info, 1 = info only, 0 = error only
our $log_level = 1;

# notification interval, in seconds


# set to 0 to notify only once
# e.g. 1 day ...
#my $interval = 60*60*24;
# disabled by default
our $interval = 0;

# perl will crash if the imported script doesn't end with a positive value .... wth
1;
Now, we need to enable the feature in the postfixadmin configuration. Edit
/etc/postfixadmin/config.local.php and add the following lines:

$CONF['vacation'] = 'YES';
$CONF['vacation_domain'] = 'autoreply.example.com';
Last but not least, we need to teach postfix how to handle mail directed to that
subdomain we configured above. First, we'll setup a new transport which sends mail
to the perl script we just installed, then we'll map the subdomain to that
transport.

Edit /etc/postfix/master.cf and add the following to the end of the file:

vacation unix - n n - - pipe


flags=Rq user=vacation argv=/var/spool/vacation/vacation.pl -f ${sender} $
{recipient}
Since we've already created an empty transport map file earlier, we now only need
to add an entry to it and to refresh it so that mail to the special subdomain is
sent to the transport we just created. Edit /etc/postfix/transport and add the
following line:

autoreply.example.com vacation
Now refresh the compiled form of the file, add a final configuration item that's
needed so that things go well with multiple recipients, and reload postfix so that
it considers the new transport:

postmap /etc/postfix/transport
postconf -e 'vacation_destination_recipient_limit = 1'
postfix reload
Testing vacation messages
If you need more output from the vacation script to better debug what's happening,
edit /etc/postfixadmin/vacation.conf and change the value for "$log_level" to 2.

To test this feature, we will first need to set the vacation message for an
address. Login to postfixadmin as the super admin and go to the "Virtual list" and
then click on the link named "Set vacation" beside "[email protected]". Now type
some text and hit the "Change/save vacation message" button. You should now see the
link you used is marked "VACATION IS ON".

Now send an email to that address and see what happens:

swaks --from [email protected] [email protected]


--server=hostname.yourdomain
You should see something similar to the following in syslog:

Dec 4 02:54:42 debian-squeeze /var/spool/vacation/vacation.pl: DEBUG - Script


argument SMTP recipient is : 'someone#[email protected]' and
smtp_sender : '[email protected]'
Dec 4 02:54:42 debian-squeeze /var/spool/vacation/vacation.pl: DEBUG - Converted
autoreply mailbox back to normal style - from
someone#[email protected] to [email protected]
Dec 4 02:54:42 debian-squeeze /var/spool/vacation/vacation.pl: DEBUG - Email
headers have to: '[email protected]' and From: '[email protected]'
Dec 4 02:54:43 debian-squeeze /var/spool/vacation/vacation.pl: DEBUG - Found
'[email protected]' has vacation active
Dec 4 02:54:43 debian-squeeze /var/spool/vacation/vacation.pl: DEBUG - Attempting
to send vacation response for: unknown to: [email protected],
[email protected], [email protected] (test_mode = 0)
Dec 4 02:54:43 debian-squeeze /var/spool/vacation/vacation.pl: DEBUG - Asked to
send vacation reply to [email protected] thanks to unknown
Dec 4 02:54:43 debian-squeeze /var/spool/vacation/vacation.pl: DEBUG - Will send
vacation response for unknown: FROM: [email protected] (orig_to:
[email protected]), TO: [email protected]; VACATION SUBJECT: Out of
Office ; VACATION BODY: I will be away from january until mars.#015#012For urgent
matters you can contact this person.
Dec 4 02:54:43 debian-squeeze postfix/smtpd[4267]: connect from
localhost[127.0.0.1]
Dec 4 02:54:43 debian-squeeze milter-greylist: smfi_getsymval failed for {i}
Dec 4 02:54:43 debian-squeeze milter-greylist: (unknown id): Sender IP 127.0.0.1
and address <[email protected]> are SPF-compliant, bypassing greylist
Dec 4 02:54:43 debian-squeeze postfix/smtpd[4267]: 0864440DBB:
client=localhost[127.0.0.1]
Dec 4 02:54:43 debian-squeeze postfix/cleanup[4272]: 0864440DBB: message-
id=<[email protected]>
Dec 4 02:54:43 debian-squeeze milter-greylist: smfi_getsymval failed for {if_addr}
Dec 4 02:54:43 debian-squeeze postfix/qmgr[4091]: 0864440DBB:
from=<[email protected]>, size=585, nrcpt=1 (queue active)
Dec 4 02:54:43 debian-squeeze postfix/smtpd[4267]: disconnect from
localhost[127.0.0.1]
Dec 4 02:54:43 debian-squeeze /var/spool/vacation/vacation.pl: DEBUG - Vacation
response sent to [email protected], from [email protected]
Dec 4 02:54:43 debian-squeeze postfix/pipe[4277]: 8C70B40851:
to=<someone#[email protected]>, orig_to=<[email protected]>,
relay=vacation, delay=16, delays=16/0.03/0/0.41, dsn=2.0.0, status=sent (delivered
via vacation service)
Dec 4 02:54:43 debian-squeeze postfix/qmgr[4091]: 8C70B40851: removed
Dec 4 02:54:43 debian-squeeze postfix/smtp[4279]: 0864440DBB:
to=<[email protected]>, relay=your.hostname[1.2.3.4]:25, delay=0.7,
delays=0.07/0.03/0.49/0.1, dsn=2.0.0, status=sent (250 2.0.0 Ok: queued as
98826FC1EFA)
Dec 4 02:54:43 debian-squeeze postfix/qmgr[4091]: 0864440DBB: removed
If all went well you should now have received an email with the appropriate subject
and body. If you're having difficulty understanding the above log output, here's a
short summary of what it says:

The script searches whether the addressed email has its vacation message set and
sends a message with the subject and body that were set.
The script then connects to localhost to send an e-mail from the receiver to the
sender and the message is queued.
The script exits after succeeding in its duty
The queued message is processed by postfix and is sent to the original sender.
If you changed the "$log_level" to 2 earlier, don't forget to set it back to 1 else
you'll have lots of useless lines in your logs.

With the above settings, if a notification gets sent to the original sender but you
don't receive it and want to test it again, you'll have to make a manipulation:
either truncate the "vacation_notification" table or change "vacation.conf" to set
"$interval" to something very low, like 1 (see above). Another trick is to remove
the auto-reply in postfixadmin, which will delete all notifications for that
address, and then to set it back.

quota
In order to get quota to work, you need to tell dovecot how to get quota
information, and then to activate it in the postfixadmin interface.

First, let's load the plugin by adding it to the list of plugins in


/etc/dovecot/conf.d/10-mail.conf:

mail_plugins = $mail_plugins zlib quota


and also in /etc/dovecot/conf.d/20-imap.conf:

# Space separated list of plugins to load (default is global mail_plugins).


mail_plugins = $mail_plugins imap_quota
Next, we need to tell dovecot to use per-user quota values. We'll add a second rule
in there so that the Trash directory has a little bit more space so that people can
do some cleanup when they are overquota. Edit /etc/dovecot/conf.d/90-quota.conf:

plugin {
# [...]
quota = maildir:User quota
quota_rule2 = Trash:storage=+100M
}
Telling dovecot where to find quota info is pretty simple, we need to modify
"user_query" in dovecot's SQL configuration so that it returns a quota_rule column
with dovecot's quota_rule format. Since we're using prefetch for userdb, we'll have
to add the column to the "password_query" too. Edit /etc/dovecot/dovecot-
sql.conf.ext and add the column. The two queries should now look like this:

password_query = SELECT username as user, password, CONCAT('/var/mail/vmail/',


maildir) as userdb_home, 8 as userdb_uid, 8 as userdb_gid, concat('*:bytes=',
quota) as userdb_quota_rule FROM mailbox INNER JOIN domain ON
mailbox.domain=domain.domain WHERE username='%u' AND domain.active = true AND
mailbox.active = true;
user_query = SELECT CONCAT('/var/mail/vmail/', maildir) as home, 8 as uid, 8 as
gid, concat('*:bytes=', quota) as quota_rule FROM mailbox INNER JOIN domain ON
mailbox.domain=domain.domain WHERE username='%u' AND domain.active = true AND
mailbox.active = true;
Now to enable quotas in the postfixadmin interface, edit
/etc/postfixadmin/config.local.php and add the following to it:

$CONF['quota'] = 'YES';
$CONF['maxquota'] = 0; // I decided to not set a quota by default, but change this
value to a number of Mb that should be the default value for your case.
Finally, restart dovecot:

service dovecot restart


Testing user quotas
In order to test this feature, we'll have to set a low quota on a user. Login to
postfixadmin and click on the "Edit" link beside a user, then specify a low quota
and click on the "Save" button. For this example we'll set a quota of 1Mb to the
user "[email protected]".

Find a file slightly below the quota you set (note that the contents of the mail
itself is also accounted for in the quota, so the attachment shouldn't be exactly
as big as the limit), and send it as an attachment to that user. We'll generate one
with random content:

dd if=/dev/urandom of=900k_file bs=1024 count=900


swaks --from [email protected] [email protected]
--server=hostname.yourdomain --attach - --suppress-data < 900k_file
This first attachment should be able to get to destination (supposing you haven't
already sent more than 100kb of test emails). If you launch that swaks command
again, you'll get an answer that looks odd at first: the server tells you "OK
message queued as <some_message_ID>". However, if you look at the syslog, you'll
see a message about an email being sent to [email protected]:

Dec 4 16:48:09 debian-squeeze postfix/pipe[5316]: 3B73A40DA7:


to=<[email protected]>, relay=dovecot, delay=1.1, delays=0.97/0.02/0/0.1,
dsn=2.0.0, status=sent (delivered via dovecot service)
Dec 4 16:48:09 debian-squeeze postfix/qmgr[4601]: 3B73A40DA7: removed
Dec 4 16:48:09 debian-squeeze postfix/cleanup[5313]: AA1D940DB0: message-
id=<[email protected]>
Dec 4 16:48:09 debian-squeeze postfix/qmgr[4601]: AA1D940DB0: from=<>, size=1930,
nrcpt=1 (queue active)
Dec 4 16:48:10 debian-squeeze postfix/smtp[5323]: AA1D940DB0:
to=<[email protected]>, relay=your_mx[1.2.3.4]:25, delay=0.47,
delays=0.01/0.01/0.35/0.1, dsn=2.0.0, status=sent (250 2.0.0 Ok: queued as
13017FC3158)
Dec 4 16:48:10 debian-squeeze postfix/qmgr[4601]: AA1D940DB0: removed
Now in your inbox, you should see a message got to you that says your e-mail was
rejected and in the body, you can see the cause which is because the user's inbox
is over quota.

Configuring Mailman
We'd like to be able to control mailing lists under lists.example.com. Make sure to
create the appropriate DNS entry and to have it pointed to the mail server's IP
address. Since this tutorial does a pretty good job of explaining the process and
showing how to do things, we'll mostly stick to the steps there and keep
explanations only to what differs that tutorial or needs further clarification.

If you remember we chose at the beginning of this howto to assume you already had a
web server. We'll be working with Apache, so if you need to adapt to other
software, you'll need to do it on your own. But it shouldn't be fairly difficult.

apt-get install mailman

ln -s /etc/mailman/apache.conf /etc/apache2/sites-available/lists.example.com
a2ensite lists.example.com
Edit /etc/mailman/apache.conf, uncomment the vhost block at the end and change it
to suit your needs. (see the tutorial mentioned above for details)

mkdir /var/www/lists
apache2ctl graceful
Edit /etc/mailman/mm_cfg.py and ensure the following configuration is present:

[...]
DEFAULT_URL_PATTERN = 'http://%s/'
[...]
DEFAULT_EMAIL_HOST = 'lists.example.com'
[...]
DEFAULT_URL_HOST = 'lists.example.com'
[...]
GLOBAL_PIPELINE.insert(1, 'SpamAssassin')
SPAMASSASSIN_HOST='127.0.0.1:783'

postconf -e 'relay_domains = proxy:mysql:/etc/postfix/virtual/relay_domains.cf


lists.example.com'
postconf -e 'mailman_destination_recipient_limit = 1'
Edit /etc/postfix/transport and append the following line:

lists.example.com mailman

postmap /etc/postfix/transport
postfix reload
newlist --urlhost=lists.example.com --emailhost=lists.example.com mailman
Edit /etc/aliases and append to it the following lines:

mailman: "|/var/lib/mailman/mail/mailman post mailman"


mailman-admin: "|/var/lib/mailman/mail/mailman admin mailman"
mailman-bounces: "|/var/lib/mailman/mail/mailman bounces mailman"
mailman-confirm: "|/var/lib/mailman/mail/mailman confirm mailman"
mailman-join: "|/var/lib/mailman/mail/mailman join mailman"
mailman-leave: "|/var/lib/mailman/mail/mailman leave mailman"
mailman-owner: "|/var/lib/mailman/mail/mailman owner mailman"
mailman-request: "|/var/lib/mailman/mail/mailman request mailman"
mailman-subscribe: "|/var/lib/mailman/mail/mailman subscribe mailman"
mailman-unsubscribe: "|/var/lib/mailman/mail/mailman unsubscribe mailman"

newaliases
service mailman start
Now visit lists.example.com with a browser and your should see the mailman
interface.

We'll skip testing the setup for this piece of software for brevity.

However, it would require us to create a new list and subscribe more than one
address to it, and then to send a message to the list and see if it gets sent to
all members.

If you want to be able to manage lists on more than one subdomain, check out the
last link in the bibliography section: it has a section about configuring Mailman
for this purpose. It needs you to perform more operations before Mailman is
functional, but you won't need to manually add aliases to /etc/aliases every time
there is a new list.

Varia
DNS
Some of the software we've installed need to perform lots of DNS lookups, so in
order to speed up subsequent lookups to host names we've already seen, you might
consider setting up a DNS caching service: it can make something between a good and
a huge difference on performance. Here's a quick example of such a setup with
dnsmasq:

apt-get install dnsmasq


Edit /etc/dnsmasq.conf and uncomment and modify the lines #interface= and #bind-
interfaces so that they look like:

interface=lo
bind-interfaces
Now edit /etc/resolv.conf and add a nameserver line for 127.0.0.1 in the first
position (e.g. above all others):

nameserver 127.0.0.1
Finally, restart dnsmasq and then all services that process e-mails so that they
consider the new contents of the /etc/resolv.conf file.

Sieve / ManageSieve
Server-side filters have the advantage that once they are set up, users can use
whatever client and messages will get delivered to the right directory without the
email client application having to do anything. Also, users won't loose their
filters if they loose their laptop/desktop or if their desktop disk explodes.

It can also manage vacation messages for you, so it could be an interesting


replacement to the feature from postfixadmin we're using above which is pretty
clunky to setup.

However, sieve filters are not very user-friendly for most non-geek users. Users
basically need to learn a (simple -- but still...) programming language to be able
to write their filters. Roundcube and Squirrelmail (last updated in 2009!) have
plugins to interact with ManageSieve to manage your server-side filters. That's
something I'd need to explore. I just hope that some plugins for some clients do a
good job of making it easy to build filters. Thunderbird's "Sieve" add-on is not
very user-friendly for non-IT people. If you only want to use the vacation message
feature from sieve, then Thunderbird's "Sieve Out of Office" add-on might be more
interesting and easy to use.

Sieve is pretty easy to setup. Just install the following packages:

apt-get install dovecot-managesieved dovecot-sieve


then edit /etc/dovecot/15-lda.conf and uncomment the line that sets plugins and add
"sieve" to the list:

protocol lda {
# Space separated list of plugins to load (default is global mail_plugins).
mail_plugins = $mail_plugins sieve
}
Then restart dovecot:

service dovecot restart


Watch out! ManageSieve might accept unencrypted connections. This could be an easy
way to leak your users' passwords so you need to verify that this is not happening.
After following the above guide, dovecot's ManageSieve server should offer no
options for the "SASL" capability as long as you haven't initiated a TLS
transaction. If the "SASL" capability is empty and the "STARTTLS" capability is
visible, then your server is rejecting non-encrypted logins (which is what we
want):

$ telnet your.server 4190


Trying 1.2.3.4...
Connected to you.server.
Escape character is '^]'.
"IMPLEMENTATION" "Dovecot Pigeonhole"
"SIEVE" "fileinto reject envelope encoded-character vacation subaddress comparator-
i;ascii-numeric relational regex imap4flags copy include variables body enotify
environment mailbox date ihave"
"NOTIFY" "mailto"
"SASL" ""
"STARTTLS"
"VERSION" "1.0"
OK "Dovecot ready."
If you're seeing "STARTTLS" in the server's welcome message but the "SASL"
capability is not an empty list, then you need to correct this. This can be
enforced by setting the following in /etc/dovecot/conf.d/10-auth.conf:

disable_plaintext_auth = yes
For more info on troubleshooting ManageSieve, check out the last link in the
bibliography.

You might also like