Setup Email Server From Scratch On FreeBSD #2 - 04 Dovecot IMAP

03 Postfix SMTPD <- Intro -> 05 PostfixAdmin

We believe in data independence, and support others who want data independence.
Debian Email From Scratch version 2 finished 2025-07-30.

We are still adding to it but it all works!


###############################
# INSTALL DOVECOT IMAP SERVER #
###############################

Install Dovecot

apt install dovecot-core dovecot-imapd dovecot-mysql dovecot-lmtpd

If you plan to use ARGON2I check if it is supported.

root@okdeb.com:~# doveadm pw -l
SHA1 SSHA512 SCRAM-SHA-256 BLF-CRYPT PLAIN HMAC-MD5 OTP SHA512 SHA DES-CRYPT CRYPT SSHA
MD5-CRYPT PLAIN-MD4 PLAIN-MD5 SCRAM-SHA-1 SHA512-CRYPT CLEAR CLEARTEXT ARGON2I ARGON2ID
SSHA256 MD5 PBKDF2 SHA256 CRAM-MD5 PLAIN-TRUNC SHA256-CRYPT SMD5 DIGEST-MD5 LDAP-MD5

Make backups of original configuration and working postfix configuration. We are
going to make a lot of changes to these files so back up everything including
subdirectorieds so we can always roll back to a working configuration.

cd /etc
cp /etc/dovecot/dovecot.conf /etc/dovecot/dovecot.conf.bak
cp /etc/postfix/main.cf /etc/postfix/main.cf.bak
cp /etc/postfix/master.cf /etc/postfix/master.cf.bak
cp -R dovecot dovecot_bak
cp -R postfix postfix_bak

Configure Dovecot or confirm imap is enabled

nano /etc/dovecot/dovecot.conf
# Enable installed protocols protocols = imap !include_try /usr/share/dovecot/protocols.d/*.protocol

Check what protocols are in the protocols.d directory
ls /usr/share/dovecot/protocols.d/*
/usr/share/dovecot/protocols.d/imapd.protocol

Enable Submission service in Postfix - insert the following lines to master.cf

nano /etc/postfix/master.cf
#tlsproxy unix - - y - 0 tlsproxy submission inet n - y - - smtpd -o syslog_name=postfix/submission -o smtpd_tls_security_level=encrypt -o smtpd_tls_wrappermode=no -o smtpd_sasl_auth_enable=yes -o smtpd_relay_restrictions=permit_sasl_authenticated,reject -o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject -o smtpd_sasl_type=dovecot -o smtpd_sasl_path=private/auth smtps inet n - y - - smtpd -o syslog_name=postfix/smtps -o smtpd_tls_wrappermode=yes -o smtpd_sasl_auth_enable=yes -o smtpd_relay_restrictions=permit_sasl_authenticated,reject -o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject -o smtpd_sasl_type=dovecot -o smtpd_sasl_path=private/auth # Choose one: enable submission for loopback clients only, or for any client.

Configure Postfix

nano /etc/postfix/master.cf
--- Remove Debian from the banner ---
smtpd_banner = $myhostname ESMTP $mail_name # TLS parameters smtpd_tls_cert_file=/etc/letsencrypt/live/mx.okdeb.com/fullchain.pem smtpd_tls_key_file=/etc/letsencrypt/live/mx.okdeb.com/privkey.pem smtpd_tls_security_level=may smtpd_tls_loglevel = 1 smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache tls_server_sni_maps = hash:/etc/postfix/sni_maps smtp_tls_CApath=/etc/ssl/certs smtp_tls_security_level=may smtp_tls_loglevel = 1 smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache # Enforce TLSv1.3 or TLSv1.2 smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1 smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1 smtp_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1 smtp_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1

Setup our SNI maps in case we want multiple domains

nano /etc/postfix/sni_maps
mx.okdeb.com /etc/letsencrypt/live/mx.okdeb.com/privkey.pem /etc/letsencrypt/live/mx.okdeb.com/fullchain.pem mail.okdeb.com /etc/letsencrypt/live/mx.okdeb.com/privkey.pem /etc/letsencrypt/live/mx.okdeb.com/fullchain.pem

postmap /etc/postfix/sni_maps

systemctl restart postfix
systemctl status postfix

Check mailbox location
postconf mail_spool_directory
mail_spool_directory = /var/mail

Reconfigure mailbox location

nano /etc/dovecot/conf.d/10-mail.conf
mail_location = maildir:~/Maildir

Set automatic mailbox creation and subscriptions (viewed on client).

nano /etc/dovecot/conf.d/15-mailboxes.conf
--- set auto = subscribe ---
namespace inbox { # These mailboxes are widely used and could perhaps be created automatically: mailbox Drafts { auto = subscribe special_use = \Drafts } mailbox Junk { auto = subscribe special_use = \Junk autoexpunge = 30d } mailbox Trash { auto = subscribe special_use = \Trash autoexpunge = 30d } # For \Sent mailboxes there are two widely used names. We'll mark both of # them as \Sent. User typically deletes one of them if duplicates are created. mailbox Sent { auto = subscribe special_use = \Sent } mailbox "Sent Messages" { special_use = \Sent } ... }

Add user dovecot to mail group

adduser dovecot mail

Install and configure lmtp protocol

apt install dovecot-lmtpd

nano /etc/dovecot/dovecot.conf
protocols = imap lmtp

nano /etc/dovecot/conf.d/10-master.conf
service lmtp { unix_listener /var/spool/postfix/private/dovecot-lmtp { mode = 0600 user = postfix group = postfix } }

Add lmtp to end of main.cf file

nano /etc/postfix/main.cf
mailbox_transport = lmtp:unix:private/dovecot-lmtp smtputf8_enable = no

Change dovecot authentication

nano /etc/dovecot/conf.d/10-auth.conf
disable_plaintext_auth = yes auth_username_format = %n auth_mechanisms = plain login

Configure Dovecot SSL for multiple domains with SNI maps - this is generally
the better configuration since it adds flexibility and reduces number of certs
per domain.

nano /etc/dovecot/conf.d/10-ssl.conf
# Default ssl_cert = </etc/letsencrypt/live/mx.okdeb.com/fullchain.pem ssl_key = </etc/letsencrypt/live/mx.okdeb.com/privkey.pem local_name mx.okdeb.com { ssl_cert = </etc/letsencrypt/live/mx.okdeb.com/fullchain.pem ssl_key = </etc/letsencrypt/live/mx.okdeb.com/privkey.pem } local_name mail.okdeb.com { ssl_cert = </etc/letsencrypt/live/mx.okdeb.com/fullchain.pem ssl_key = </etc/letsencrypt/live/mx.okdeb.com/privkey.pem }

Configure SASL Authentication

nano /etc/dovecot/conf.d/10-master.conf
service auth { # auth_socket_path points to this userdb socket by default. It's typically # used by dovecot-lda, doveadm, possibly imap process, etc. Users that have # full permissions to this socket are able to get a list of all usernames and # get the results of everyone's userdb lookups. # # The default 0666 mode allows anyone to connect to the socket, but the # userdb lookups will succeed only if the userdb returns an "uid" field that # matches the caller process's UID. Also if caller's uid or gid matches the # socket's uid or gid the lookup succeeds. Anything else causes a failure. # # To give the caller full permissions to lookup all users, set the mode to # something else than 0666 and Dovecot lets the kernel enforce the # permissions (e.g. 0777 allows everyone full permissions). #unix_listener auth-userdb { #mode = 0666 #user = #group = #} # Postfix smtp-auth unix_listener /var/spool/postfix/private/auth { mode = 0660 user = postfix group = postfix } # Auth process is run as this user. #user = $default_internal_user }

Check 15-mailboxes.conf

nano /usr/local/etc/dovecot/conf.d/15-mailboxes.conf
... # These mailboxes are widely used and could perhaps be created automatically: mailbox Drafts { auto = subscribe special_use = \Drafts } mailbox Junk { auto = subscribe special_use = \Junk autoexpunge = 30d } mailbox Trash { auto = subscribe special_use = \Trash autoexpunge = 30d } # For \Sent mailboxes there are two widely used names. We'll mark both of # them as \Sent. User typically deletes one of them if duplicates are created. mailbox Sent { auto = subscribe special_use = \Sent } mailbox "Sent Messages" { special_use = \Sent } ...

systemctl restart postfix dovecot
systemctl status dovecot

Check if dovecot is listening
root@okdeb.com:/etc/dovecot# ss -lnpt | grep dovecot
LISTEN 0 100 0.0.0.0:143 0.0.0.0:* users:(("dovecot",pid=7563,fd=36))
LISTEN 0 100 0.0.0.0:993 0.0.0.0:* users:(("dovecot",pid=7563,fd=38))
LISTEN 0 100 [::]:143 [::]:* users:(("dovecot",pid=7563,fd=37))
LISTEN 0 100 [::]:993 [::]:* users:(("dovecot",pid=7563,fd=39))

Setup Thunderbird email client - use advanced settings
Add Mail Account
Incoming / IMAP
Full Name: Jack Pumpkin
Email address: jack@okdeb.com
Password: <secretpassword>
Click Configure Manually
Protocol: IMAP
Hostname: mx.okdeb.com
Port: 993
Security: SSL/TLS

Outgoing / SMTP
Username: jack@okdeb.com
Protocol: Outgoing
Hostname: mx.okdeb.com
Port: 587
Security: STARTTLS
Username: jack@okdeb.com
<Re-test>

Thunderbird Errors

If you encounter the following Thunderbird error when sending mail change
SSL/TLS to STARTTLS for the Outgoing Server.

Sending of the message failed. The message could not be sent because the connection to Outgoing server (SMTP) mx.coragarden.com
was lost in the middle of the transaction. Try again.

This seems to occur when Thunderbird caches bad autoconfig data from the server and
doesn't set the encryption method properly.

Go to Account Settings / Outgoing Server and delete the relevant smtp server
entries. Then delete the account(s). Then go to Tools / Clear Recent History /
Delete Everything. Restart Thunderbird. Run a fresh test.

I tried SNI, server name indication wasn't working.

Sending of the message failed. An error occurred while sending mail: Outgoing
server (SMTP) error. The server responded: TLS not available due to local
problem.

SNI configuration requires default certs in both Postfix and Dovecot. After
SNI was fixed it was necessary to stop and restart Thunderbird to test if it
was fixed.

At first I could not authenticate because I used auth_username_format = %u. At
this stage in the setup use auth_username_format = %n, and switch to %u later on.

To troubleshoot use ...
systemctl status dovecot
journalctl -eu dovecot

Make dovecot restart if killed

mkdir -p /etc/systemd/system/dovecot.service.d/

nano /etc/systemd/system/dovecot.service.d/restart.conf
[Service] Restart=always RestartSec=5s

systemctl daemon-reload

Test it
systemctl status dovecot
pkill dovecot
systemctl status dovecot
<wait 10 seconds>
systemctl status dovecot

Autoconfig and Autodiscover

Autoconfig and Autodiscover help mail clients find the settings for your mail server.
https://github.com/smartlyway/email-autoconfig-php. I had some difficulty later on
with Thunderbird because port 587 is defined with SSL in config-v1.1.xml. This
result got cached in Thunderbird and removing the account didn't remove the cached
data.

apt install git
cd /tmp
git clone https://github.com/smartlyway/email-autoconfig-php
cd email-autoconfig-php/mail
mkdir -p /var/www/okdeb/mail
cp /tmp/email-autoconfig-php/mail/config-v1.1.xml /var/www/okdeb/mail

Edit these files and change to suit your needs, this is tested and works with
Thunderbird. Make sure change the SMTP settings to 587 with STARTTLS in
config-v1.1.xml.

nano /var/www/okdeb/mail/config-v1.1.xml
<?xml version="1.0"?> <clientConfig version="1.1"> <emailProvider id="okdeb.com"> <domain>okdeb.com</domain> <displayName>okdeb.com</displayName> <displayShortName>okdeb.com</displayShortName> <incomingServer type="imap"> <hostname>mx.okdeb.com</hostname> <port>993</port> <socketType>SSL</socketType> <authentication>password-cleartext</authentication> <username>%EMAILADDRESS%</username> </incomingServer> <outgoingServer type="smtp"> <hostname>mx.okdeb.com</hostname> <port>587</port> <socketType>STARTTLS</socketType> <username>%EMAILADDRESS%</username> <authentication>password-cleartext</authentication> </outgoingServer> </emailProvider> </clientConfig>

Do the same for Outlook clients, this is untested ...

cd ~/email-autoconfig-php
cp -r /tmp/email-autoconfig-php/Autodiscover/Autodiscover.xml /var/www/okdeb/mail

nano /var/www/okdeb/mail/Autodiscover.xml/index.php
<?php $raw = file_get_contents('php://input'); $matches = array(); preg_match('/<EMailAddress>(.*)<\/EMailAddress>/', $raw, $matches); header('Content-Type: application/xml'); ?> <Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/responseschema/2006"> <Response xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a"> <User> <DisplayName>okdeb.com</DisplayName> </User> <Account> <AccountType>email</AccountType> <Action>settings</Action> <Protocol> <Type>IMAP</Type> <Server>mx.okdeb.com</Server> <Port>993</Port> <DomainRequired>off</DomainRequired> <SPA>off</SPA> <SSL>on</SSL> <AuthRequired>on</AuthRequired> <LoginName><?php echo $matches[1]; ?></LoginName> </Protocol> <Protocol> <Type>SMTP</Type> <Server>mx.okdeb.com</Server> <Port>587</Port> <DomainRequired>off</DomainRequired> <SPA>off</SPA> <SSL>on</SSL> <AuthRequired>on</AuthRequired> <LoginName><?php echo $matches[1]; ?></LoginName> </Protocol> </Account> </Response> </Autodiscover>

You will need to add a SV records for Autodiscover for NameCheap I added ...
Namecheap Domain List -> DNS -> Advanced DNS

Type Service Protocol Priority Weight Port Target
SRV Record _autodiscover _tcp 5 0 443 mx.okdeb.com

Autoconfig needs the path http://autoconfig.okdeb.com/mail/config-v1.1.xml

/etc/apache2/sites-available/mx.okdeb.conf
ServerAlias autoconfig.okdeb.com ServerAlias autodiscover.okdeb.com # autoconfig Alias /mail "/var/www/okdeb/mail"

I generated a new cert for autoconfig and autodiscover but this isn't
necessary because autoconfig doesn't use https and autodiscover uses the
domain to points to, mx.okdeb.com which already has a cert. Autodiscover needs
the path https://okdeb.com/Autodiscover/Autodiscover.xml.

nano /etc/apache2/sites-available/ssl-mx.okdeb.conf
# probably don't need the ServerAlias and if needed we'd need to update the cert # ServerAlias autodiscover.okdeb.com Alias /mail "/var/www/okdeb/mail" Alias "/Autodiscover/Autodiscover.xml" "/var/www/okdeb/mail/Autodiscover.xml/index.php" <Directory /var/www/okdeb/mail/> DirectorySlash Off Options -Indexes +FollowSymLinks AllowOverride All Require all granted </Directory>

apachectl restart

Confirm these files can be accessed by http and https and output xml.

http://mx.okdeb.com/mail/config-v1.1.xml
https://mx.okdeb.com/Autodiscover/Autodiscover.xml

Test it by removing the account in Thunderbird and adding it back. If it is
working properly it should configure quickly with mx.okdeb.com. If
Thunderbird said it is testing well known server names, takes a while, and
comes up with mail.okdeb.com then autoconfig is not working properly and check
your apache configuration and paths. See the readme in /tmp/email-autoconfig-php.

Caution! Thunderbird caches data! When testing, delete the relevant outgoing
server(s), delete the relevant mail account(s) in Thunderbired, go to Tools ->
Clear Recent History and delete everything, close and restart Thunderbird.

Then add the account(s) back as new to test again.

Next we will install PostfixAdmin

03 Postfix SMTPD <- Intro -> 05 PostfixAdmin