---
title: "Dovecot"
lastUpdated: 2025-11-01
slug: ispmail-trixie/dovecot
sidebar:
  order: 165
---

import { Aside } from "@astrojs/starlight/components";
import StepListReceive from "../../../components/StepListReceive.astro";

<StepListReceive currentStep={4} />

In this chapter we will configure Dovecot so that it knows how to deliver incoming emails.

## Setting up the vmail directory

On your disk all the mailboxes will live in the directory `/var/vmail`. To separate the mailboxes from the rest of your
system, let's create a new user and group that will own the mailboxes:

```sh title="Run this on your server"
groupadd --system vmail
useradd --system --gid vmail vmail
mkdir -p /var/vmail
chown -R vmail:vmail /var/vmail
chmod u=rwx,g=rx,o= /var/vmail
```

## Dovecot configuration

The configuration files for Dovecot are found in `/etc/dovecot/conf.d`. All these files are loaded by Dovecot. This is
done by this magical line at the end of the `/etc/dovecot/dovecot.conf` file:

```
!include conf.d/*.conf
```

It loads all files in `/etc/dovecot/conf.d/` that end in “.conf" in alphanumerical order. Let's edit a couple of files
for our purpose.

### 10-auth.conf

The `/etc/dovecot/conf.d/10-auth.conf` file is dealing with authentication. At the end of this file you will find a list
of authentication backends that Dovecot ships with. By default it will use _system users_ (those from /etc/passwd). But
we want to use the MariaDB database backend. Please comment out all include statements:

```text title="Edit your /etc/dovecot/conf.d/10-auth.conf"
#!include auth-system.conf.ext
#!include auth-sql.conf.ext
#!include auth-ldap.conf.ext
#!include auth-passwdfile.conf.ext
#!include auth-checkpassword.conf.ext
#!include auth-static.conf.ext
```

Every line starting with `#` is disabled. Only lines starting with `!` are considered.

### 10-mail.conf / 99-ispmail-mail.conf

The file at `/etc/dovecot/conf.d/10-mail.conf` contains many settings regarding mailboxes, like where they are located,
who owns them and what is their layout? Create a new file `/etc/dovecot/conf.d/99-ispmail-mail.conf` that overrides
these defaults:

```sh title="Run this on your server"
cat > /etc/dovecot/conf.d/99-ispmail-mail.conf << EOF
mail_driver = maildir
mail_home = /var/vmail/%{user | domain}/%{user | username}
mail_path = ~/Maildir
mail_uid = vmail
mail_gid = vmail
mail_inbox_path = ~/Maildir/
EOF
```

This looks more sophisticated than with versions of Dovecot before 2.4. What it means:

- **mail_driver**: Mailboxes are stored in
  [maildir](https://doc.dovecot.org/2.4.1/core/config/mailbox_formats/maildir.html#maildir-mailbox-format) format.
- **mail_home**: Every mail user gets their own _home_ directory in `/var/vmail/DOMAIN/USER`. The `user` variable
  contains the email address like `john@example.org`. The expression `user | domain` splits off the _domain_ part from
  the email address. Similarly `user | username` takes the part before the `@` sign.
- **mail_path**: Within the _home_ directory the actual mailbox will live in a subdirectory called `Maildir`. The reason
  is that we will store other data in the user's _home_ directory as well that should not conflict with the mailbox
  directory.
- **mail_uid**/**mail_gid**: All mailboxes will be owned be the user and group `vmail`.
- **mail_inbox_path**: A user's main inbox consists of the directories `cur` and `new` inside the Maildir directory. We
  used that schema in previous guides and make sure you can migrate your mailboxes from other mail servers. This
  overrides the setting in in `10-mail.conf`.

### 10-master.conf / 99-ispmail-master.conf

This configuration file at `/etc/dovecot/conf.d/10-master.conf` deals with Dovecot's _services_. A _service_ is a part
of Dovecot that listens on a TCP port or a UNIX socket so that other parts of your system can use it. We want Postfix to
use Dovecot for authentication. So we need to change the `service auth` section:

```sh title="Run this on your server"
cat > /etc/dovecot/conf.d/99-ispmail-master.conf << EOF
service auth {
  unix_listener /var/spool/postfix/private/dovecot-auth {
    mode = 0660
    user = postfix
    group = postfix
  }
}
EOF
```

That way Dovecot will put a communication socket into `/var/spool/postfix/private/dovecot-auth`. It will allow Postfix
to authenticate your users which is relevant later when we set up _relaying_.

### 10-ssl.conf / 99-ispmail-ssl.conf

Earlier in this guide you created both a key and a certificate file to encrypt the communication with IMAPS and HTTPS
between the users and your mail server. You need to tell Dovecot where to find these files. Also set
[ssl=required](https://doc.dovecot.org/2.4.1/core/config/ssl.html#how-to-specify-when-ssl-tls-is-required) to prevent
that someone sends their password without encryption. Again we will create a new file `99-ispmail-ssl.conf` to override
the defaults.

<Aside type="danger" title="Important">

Please replace `mail.example.org` by the FQDN you chose.

</Aside>

```sh title="Run this on your server"
cat > /etc/dovecot/conf.d/99-ispmail-ssl.conf << EOF
ssl = required
ssl_server_cert_file = /etc/letsencrypt/live/mail.example.org/fullchain.pem
ssl_server_key_file = /etc/letsencrypt/live/mail.example.org/privkey.pem
EOF
```

### 20-lmtp.conf / 99-ispmail-lmtp.conf

There is one setting in the `/etc/dovecot/conf.d/20-lmtp.conf` that will mess up the recipient's email address in our
setup: `auth_username_format`. So let's override it:

```sh title="Run this on your server"
cat > /etc/dovecot/conf.d/99-ispmail-lmtp-username-format.conf << EOF
protocol lmtp {
  auth_username_format =
}
EOF
```

### 99-ispmail-sql.conf

Let's tell Dovecot where to find information on an valid users (_userdb_) and their passwords (_passdb_). There are
suggestions in the `auth-sql.conf.ext` file but we will add our own file:

```sh title="Run this on your server"
cat > /etc/dovecot/conf.d/99-ispmail-sql.conf << EOF
sql_driver = mysql

mysql /var/run/mysqld/mysqld.sock {
  user = mailserver
  password = 'MAILSERVER-PASSWORD-HERE'
  dbname = mailserver
  host = 127.0.0.1
}

userdb sql {
  query = SELECT email as user, \
	  IF(quota > 0, CONCAT(quota, 'B'), NULL) AS quota_storage_size \
	  FROM virtual_users WHERE email='%{user}'
  iterate_query = SELECT email as user FROM virtual_users
}

passdb sql {
  query = SELECT password FROM virtual_users where email='%{user}'
}
EOF

# fix permissions
chown root:root /etc/dovecot/conf.d/99-ispmail-sql.conf
chmod go= /etc/dovecot/conf.d/99-ispmail-sql.conf
```

That configuration file defines how to get a user's data from the database. The two lookups are:

- `userdb sql`: get information on the user; e.g. if the user exists and what the _quota_ is
- `passdb sql`: authenticate the user / validate the password

The _quota_ logic is explained and used later in this guide. _Quota_ is the amount of space that a user can use to store
their emails. If the quota is reached then further incoming emails will get rejected until the user removes mails to
make some space.

Dovecot can also read the path to a user's home directory and the user-ID and group-ID from the database. Our setup has
a fixed schema for the home directory (`/var/vmail/DOMAIN/USER`) (as defined by `mail_home`) and the user and group are
always `vmail` and `vmail`.

### 99-ispmail-managesieve.conf

Later, we will implement server-side automation using **Sieve** rules. By default, Dovecot exposes two TCP ports to the
internet: 2000 and 4190. Port 2000 is deprecated anyway and can be safely disabled, while port 4190 is the one we will
use. However, unless you have a compelling reason, it is recommended not to make this port publicly accessible. So let
us restrict it to the _localhost_ interface:

```sh title="Run this on your server"
cat > /etc/dovecot/conf.d/99-ispmail-managesieve.conf << EOF
service managesieve-login {
  # Listen only on localhost
  inet_listener sieve {
    listen= 127.0.0.1
    port = 4190
  }

  # Disable the deprecated listener
  inet_listener sieve_deprecated {
    port = 0
  }
}
EOF
```

_(Thanks to Thomas Gauweiler for spotting that.)_

## Restart and test

Restart Dovecot from the shell:

```sh title="Run this on your server"
systemctl restart dovecot
```

Check your logs:

```sh title="Run this on your server"
journalctl -fu dovecot
```

You should see:

```
dovecot[13309]: master: Dovecot v2.4.1-4 (7d8c0e5759) starting up for imap, lmtp, sieve (core dumps disabled)
systemd[1]: Started dovecot.service - Dovecot IMAP/POP3 email server.
```

If you get any error messages please double-check your configuration files.

<Aside type="tip" title="Why there is no /var/log/mail.log?">

In previous guides we used to check the log output from Postfix and Dovecot in a file called `/var/log/mail.log`.
However in the age of _systemd_ the output of the processes is written to systemd's _journal_ instead.

To read the complete logs of Dovecot, run (u=unit):

```sh title="Run this on your server"
journalctl -u dovecot
```

To `tail -f` the logs (f=follow):

```sh title="Run this on your server"
journalctl -fu dovecot
```

However on a busy server it will show the entire journal and then follow any changes. You may want to limit the output
to the last 10 lines:

```sh title="Run this on your server"
journalctl -n 10 -fu dovecot
```

If you prefer the old way of having log files, just install the `rsyslog` package.

</Aside>

<Aside icon="approve-check-circle" title="Test it">

To test the `userdb` query:

```sh title="Run this on your server"
doveadm user john@example.org
```

That should give you:

```
field     value
uid       vmail
gid       vmail
home	    /var/vmail/example.org/john
mail_path	/var/vmail/example.org/john/Maildir
```

To test the `iterate` query that gets a list of all users:

```sh title="Run this on your server"
doveadm user '*'
```

As there is currently only one user the output should be:

```
john@example.org
```

</Aside>
