Dovecot
Dovecot handles storage of mail as well as providing IMAP access to emails on the kasad.com mail server.
Installation
Dovecot is broken into several Debian packages. We need dovecot-imapd
and dovecot-sieve
, which both require dovecot-core
:
# apt install dovecot-{core,imapd,sieve}
Enabling the service
The dovecot-core
package comes with a systemd service for Dovecot which we will enable:
# systemctl enable dovecot.service
Note: Enabling dovecot.socket
is not enough, as that will not trigger when Postfix tries to use Dovecot for SASL, leading to broken authentication in Postfix until the IMAP server is accessed.
Configuration
Typically, Dovecot is configured using multiple drop-in configuration files in /etc/dovecot/conf.d
.
However, for smaller setups like ours, it's much easier to put all of the configuration in /etc/dovecot/dovecot.conf
and ignore the drop-in files.
Below are the contents of dovecot.conf
.
The comments in the file explain briefly what each section does, but they are documented in more detail in the following sections.
# /etc/dovecot/dovecot.conf
# Note that in the dovecot conf, you can use:
# %u for username
# %n for the name in name@domain.tld
# %d for the domain
# %h the user's home directory
# SSL should be set to required.
ssl = required
ssl_cert = </etc/letsencrypt/live/kasad.com/fullchain.pem
ssl_key = </etc/letsencrypt/live/kasad.com/privkey.pem
# Plaintext login. This is safe and easy thanks to SSL.
auth_mechanisms = plain login
protocols = $protocols imap sieve
# Search for valid users in /etc/passwd
userdb {
driver = passwd
}
#Fallback: Use plain old PAM to find user passwords
passdb {
driver = pam
}
# Our mail for each user will be in ~/.mail, and the inbox will be ~/.mail/Inbox
# The LAYOUT option is also important because otherwise, the boxes will be `.Sent` instead of `Sent`.
mail_location = maildir:~/.mail:INBOX=~/.mail/Inbox:LAYOUT=fs
namespace inbox {
inbox = yes
mailbox Drafts {
special_use = \Drafts
auto = subscribe
}
mailbox Junk {
special_use = \Junk
auto = subscribe
autoexpunge = 30d
}
mailbox Spam {
special_use = \Junk
auto = no
autoexpunge = 30d
}
mailbox Sent {
special_use = \Sent
auto = subscribe
}
mailbox Trash {
special_use = \Trash
auto = subscribe
}
mailbox Archive {
special_use = \Archive
}
mailbox Archives {
special_use = \Archive
}
}
# Here we let Postfix use Dovecot's authetication system.
service auth {
unix_listener /var/spool/postfix/private/auth {
mode = 0660
user = postfix
group = postfix
}
}
mail_plugins = $mail_plugins zlib
plugin {
zlib_save = zstd
}
protocol lda {
mail_plugins = $mail_plugins sieve
}
protocol lmtp {
mail_plugins = $mail_plugins sieve
}
plugin {
sieve = file:~/.sieve;active=~/.dovecot.sieve
sieve_default = /etc/dovecot/sieve/default.sieve
sieve_global = file:/var/lib/dovecot/sieve
recipient_delimiter = +
}
TLS settings
We want to enable and enforce TLS for connections. Unlike Postfix, Dovecot's ports are only accessed by our own users, so we don't need to worry about compatibility issues with other mail servers.
ssl = required
ssl_cert = </etc/letsencrypt/live/kasad.com/fullchain.pem
ssl_key = </etc/letsencrypt/live/kasad.com/privkey.pem
SASL authentication mechanisms
SASL supports multiple methods, called mechanisms, for the user to transmit their password to the server. Since all connections to Dovecot will use TLS, we can enable plaintext mechanisms. They also happen to be the only ones supported by the PAM authentication backend.
auth_mechanisms = plain login
disable_plaintext_auth = yes
The second option above disables plaintext mechanisms for unencrypted connections. This doesn't matter since we require TLS, but it's a nice security fallback if the TLS settings are accidentally changed.
Protocols
We need to tell Dovecot which protocols we want to enable. In our case, this is IMAP and Sieve. Sieve is a scripting language which allows users to create rules to automatically filter or categorize incoming mail.
protocols = imap sieve
User & password databases
We want to use standard UNIX users as the user database for our mail system. We can easily do this in Dovecot. Authentication is broken down into two databases, a user database and a password database. The password database handles authentication of the user when they log in. The user database provides information on the user's UID, GID, and home directory after they've authenticated.
PAM password database
We want to use PAM as the password database.
It is possible to use the /etc/shadow
file, but PAM provides more customization options.
passdb {
driver = pam
}
We also want to restrict access to users in the mail
group, as we don't want all UNIX users to be able to receive/send mail.
We can accomplish this by adding the following line at the end of the auth
stack in the /etc/pam.d/dovecot
file:
auth required pam_succeed_if.so user ingroup mail
This will cause authentication attempts for users not in the mail
group to fail, the same way as if they provided an invalid password.
Passwd file user database
After a user has authenticated, we can look up their UID, GID, and home directory in the /etc/passwd
file:
userdb {
driver = passwd
}
Mail storage location
We need to tell Dovecot where we want it to store mail. We'll use the Maildir format for storing emails, as it's the easiest to work with:
mail_location = maildir:~/.mail:INBOX=~/.mail/Inbox:LAYOUT=fs
-
LAYOUT=fs
: Use heirarchical directories for IMAP folders -
INBOX=~/.mail/Inbox
: Creates a distinctInbox
folder rather than putting the inbox emails in the Maildir root
Inbox namespace
Dovecot supports IMAP namespaces.
So far, we only define one namespace, which is the default inbox
namespace.
This namespace also contains default mailbox definitions.
namespace inbox {
inbox = yes
mailbox Drafts {
special_use = \Drafts
auto = subscribe
}
mailbox Junk {
special_use = \Junk
auto = subscribe
autoexpunge = 30d
}
mailbox Sent {
special_use = \Sent
auto = subscribe
}
mailbox Trash {
special_use = \Trash
auto = subscribe
}
mailbox Archives {
special_use = \Archive
}
}
The inbox = true
setting for the namespace tells Dovecot that this is the namespace which contains the inbox folder where new mail should be delivered to.
The mailbox definitions tell Dovecot about some default mailboxes. Users can create additional mailboxes on top of these. Each mailbox has some options which are explained below.
The auto
option controls whether Dovecot will automatically create the mailbox folder. The no
value means it will not. The create
value means it will automaticaaly create the mailbox, and the subscribe
value means it will both create the mailbox and subscribe the user to it.
The special_use
option assigns an IMAP special use flag to the mailbox.
This essentially tells IMAP clients which mailboxes (folders) are used for special purposes, like storing drafts or spam email.
The autoexpunge
option will automatically expunge, or permanently delete, messages in the specified mailbox when they are older than the time given by the value. For instance, the Junk
folder is set to automatically delete emails inside it that are older than one month.
Postfix SASL connector
We have configured Postfix to use Dovecot as its SASL provider. For this to work, we need to configure Dovecot to provide a SASL listener socket to Postfix:
service auth {
unix_listener /var/spool/postfix/private/auth {
mode = 0660
user = postfix
group = postfix
}
}
The path for the socket must be /var/spool/postfix/$smtpd_sasl_path
as specified in Postfix's main.cf
configuration file.
Compressed mail storage
We want to enable compressed mail storage, as it'll help us save some disk space.
To do this, we use the zlib
plugin:
mail_plugins = $mail_plugins zlib
We can then configure the zlib plugin:
plugin {
zlib_save = zstd
}
This option configures Dovecot to compress new emails with the Zstandard compression algorithm.
Sieve filtering
We want to enable users to create filters in the form of Sieve scripts.
To do this, we will enable the sieve
plugin for the LDA and LMTP protocols in Dovecot:
protocol lda {
mail_plugins = $mail_plugins sieve
}
protocol lmtp {
mail_plugins = $mail_plugins sieve
}
Make sure to place these two blocks after setting the mail_plugins
option globally.
If you modify mail_plugins
later in the file, the protocol block will not be updated.
We also need to configure the Sieve plugin:
plugin {
sieve = file:~/.sieve;active=~/.dovecot.sieve
sieve_default = /etc/dovecot/sieve/default.sieve
sieve_global = file:/var/lib/dovecot/sieve
recipient_delimiter = +
}
The first option, sieve
defines where sieve scripts will be stored.
We set it to store Sieve scripts in ~/.sieve
.
This is also where scripts included in other scripts will be loaded from.
Only one Sieve script can be active at a time.
This active script is symlinked to from ~/.dovecot.sieve
.
The second option, sieve_default
, specifies the default Sieve script to use if the user has not provided their own.
The third option, sieve_global
, specifies the directory where global scripts will be stored.
This also controls where scripts that are included in other global Sieve scripts will be loaded from.
Finally, we set the recipient_delimiter
character to match what we've configured in Postfix, which is the +
plus character.
Default Sieve script
We've defined the default Sieve script location as /etc/dovecot/sieve/default.sieve
.
The contents of this file are:
require ["fileinto", "mailbox"];
if header :contains "X-Spam-Flag" "YES"
{
fileinto "Junk";
}
This script will file emails that have been flagged as spam by SpamAssassin into the Junk
folder.
No Comments