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.
This tutorial is partially complete 2025-08-07
This is version 2 and everthing works up to and including Roundcube.
###############################
# INSTALL DOVECOT IMAP SERVER #
###############################
# If you have not install ports Update ports tree, ignore the Device busy, zfs needs to be unmounted to remove the
# actual directory, but we don't need to remove it.
rm -rf /usr/ports
rm: /usr/ports: Device busy
ls -la /usr/ports
drwxr-xr-x 2 root wheel 2 Aug 6 09:19 ./
drwxr-xr-x 15 root wheel 15 Jun 6 01:34 ../
pkg install portsnap
mkdir -p /var/db/portsnap
cd /usr/ports
portsnap fetch
portsnap extract
# For ports update use 'portsnap fetch update'.
# If you plan to use ARGON2I scheme compile as follows.
# Missing ARGONI
/usr/local/bin/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 SSHA256 MD5 PBKDF2 SHA256 CRAM-MD5 PLAIN-TRUNC SHA256-CRYPT SMD5
DIGEST-MD5 LDAP-MD5
# Clean the dovecot ports if previously compiled
cd /usr/ports/mail/dovecot-fts-flatcurve
make deinstall
make clean
make rmconfig
cd /usr/ports/mail/dovecot
make deinstall
make clean
make rmconfig
# Compile dovecot-flatcurve
cd /usr/ports/mail/dovecot-fts-flatcurve
make
# Choose these options
X DOCS
X EXAMPLES
X LIBSODIUM - you will need this for ARGON2I (postfixadmin)
X LIBWRAP
X LUA
X LZ4
X CDB
X LDAP
X MYSQL
ICU - NO IT FAILED EVERY TIME
X SOLR
X TEXTCAT
X GSSAPI-NONE
# There are a lot of dependencies and compiling will take some time. Several
# screens will popup with options to select, continue with default options
# already selected.
make install
libtool --finish /usr/local/lib/dovecot/doveadm
libtool --finish /usr/local/lib/dovecot
# Check if user and groups were created, if not create them.
grep dovecot /etc/passwd /etc/group
/etc/passwd:dovecot:*:143:143:Dovecot User:/var/empty:/usr/sbin/nologin
/etc/group:dovecot:*:143:
# Enable dovecot
sysrc dovecot_enable="YES"
# To avoid a risk of mailbox corruption, do not set the security.bsd.see_other_uids or
# .see_other_gids sysctls to 0 if Dovecot is storing mail for multiple concurrent users (PR
# 218392).
# Similarly, setting sysctls security.bsd.hardlink_check_uid or security.bsd.hardlink_check_gid
# to 1 might result in non-working mailboxes, depending on what mailbox locking mechanism is
# used (PR 242223).
# If you want to be able to search within attachments using the decode2text plugin, you'll need
# to install textproc/catdoc, and one of graphics/xpdf or graphics/poppler-utils.
# Both xpf and poppler-utils have security or dependency issues and fail to compile so use pkg.
pkg install catdoc
pkg install xpdf
pkg install poppler-utils
echo 'DEFAULT_VERSIONS+=ssl=openssl' >> /etc/make.conf
# Generate the dh.pem for Dovecot
openssl dhparam -out /usr/local/etc/dovecot/dh.pem 4096
# Copy example configuation files
cp -R /usr/local/etc/dovecot/example-config/* /usr/local/etc/dovecot
# Configure Dovecot, Dovecot won't start without the certs and vmail configured.
# Edit 10-ssl.conf
nano /usr/local/etc/dovecot/conf.d/10-ssl.conf
# ---
ssl = required
#ssl_cert = </etc/ssl/certs/dovecot.pem
#ssl_key = </etc/ssl/private/dovecot.pem
ssl_cert = </usr/local/etc/letsencrypt/live/mail.okbsd.com/fullchain.pem
ssl_key = </usr/local/etc/letsencrypt/live/mail.okbsd.com/privkey.pem
local_name mail.okbsd.com {
ssl_cert = </usr/local/etc/letsencrypt/live/mail.okbsd.com/fullchain.pem
ssl_key = </usr/local/etc/letsencrypt/live/mail.okbsd.com/privkey.pem
}
local_name imap.okbsd.com {
ssl_cert = </usr/local/etc/letsencrypt/live/mail.okbsd.com/fullchain.pem
ssl_key = </usr/local/etc/letsencrypt/live/mail.okbsd.com/privkey.pem
}
ssl_dh = </usr/local/etc/dovecot/dh.pem
ssl_min_protocol = TLSv1.2
ssl_prefer_server_ciphers = yes
# ---
# Check if vmail user and group exist.
grep vmail /etc/passwd /etc/group
# Add the vmail user and group
pw useradd -c "" -n vmail -s /usr/bin/nologin -d /nonexistent -u 2000
grep vmail /etc/passwd /etc/group
/etc/passwd:vmail:*:2000:2000::/nonexistent:/usr/bin/nologin
/etc/group:vmail:*:2000:
service dovecot start
service dovecot status
dovecot is running as pid 22413.
dovecot --version
2.3.21.1 (d492236fa0)
# Check for LIBSODIUM/ARGON2I support if you plan to use it.
/usr/local/bin/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
# Test ARGON2I
/usr/local/bin/doveadm pw -s ARGON2I -r 5 -p hello
{ARGON2I}$argon2i$v=19$m=32768,t=5,p=1$RyC0o8I14UBuFpYHC61HEg$i7BQp0F4 ... etc.
openssl version
OpenSSL 3.0.16 11 Feb 2025 (Library: OpenSSL 3.0.16 11 Feb 2025)
# Comment out the following in openssl, not compatible with dovecot lmtp
nano /etc/ssl/openssl.cnf
# ---
# providers = provider_sect
# Add dovecot user to mail group so it can read the maildir
pw groupmod mail -m dovecot
grep dovecot /etc/group
mail:*:6:postfix,dovecot
dovecot:*:143:
# Enable Submission in Postfix
# I modified for FreeBSD but shamelessly copied parts from linuxbabe.com. He
# deserves a coffee or 100 coffee's! His tutorial is for Debian and a little
# out of date but still a fantastic guide!
# Backup Postfix configs
cd /usr/local/etc
cp -R postfix postfix_backup
# Backup Dovecot configs
cd /usr/local/etc
cp -R dovecot dovecot_backup
# Paste the following
nano /usr/local/etc/postfix/master.cf
# ---
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
# If you want to compare what is configured between 2 machines useful commands
postconf | grep <value>
# Modify or add the following values
nano /usr/local/etc/postfix/main.cf
# ---
myhostname = smtp.okbsd.com
mydomain = okbsd.com
myorigin = $mydomain
inet_interfaces = all
# mydestination = $myhostname, localhost.$mydomain, localhost
mydestination = $mydomain, $myhostname, localhost.$mydomain, localhost
local_recipient_maps = unix:passwd.byname $alias_maps
#mynetworks_style = host
mynetworks_style = ${{$compatibility_level} <level {2} ? {subnet} : {host}}
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
relay_domains = ${{$compatibility_level} <level {2} ? {$mydestination} : {}}
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
home_mailbox = Maildir/
mail_spool_directory = /var/mail
smtpd_banner = $myhostname ESMTP
setgid_group = maildrop
inet_protocols = all
smtp_tls_CApath = /etc/ssl/certs
shlib_directory = /usr/local/lib/postfix
meta_directory = /usr/loc/libexec/postfix
mailbox_size_limit = 0
message_size_limit = 52428800
# Enable TLS Encryption when Postfix receives incoming emails
smtpd_tls_cert_file=/usr/local/etc/letsencrypt/live/mail.okbsd.com/fullchain.pem
smtpd_tls_key_file=/usr/local/etc/letsencrypt/live/mail.okbsd.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:/usr/local/etc/postfix/sni_maps
# Enable TLS Encryption when Postfix sends outgoing emails
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
# ---
# Create Postfix Server Name Indication SNI Maps
nano /usr/local/etc/postfix/sni_maps
# ---
mail.okbsd.com /usr/local/etc/letsencrypt/live/mail.okbsd.com/privkey.pem /usr/local/etc/letsencrypt/live/mail.okbsd.com/fullchain.pem
smtp.okbsd.com /usr/local/etc/letsencrypt/live/mail.okbsd.com/privkey.pem /usr/local/etc/letsencrypt/live/mail.okbsd.com/fullchain.pem
# ---
postmap -F /usr/local/etc/postfix/sni_maps
# Restart Postfix
service postfix restart
postfix/postfix-script: stopping the Postfix mail system
postfix/postfix-script: starting the Postfix mail system
# Check if postfix is running
service postfix status
postfix is running as pid 22606.
# Finish Configuring Dovecot
# To view Dovecot configuration
doveadm config
# Edit dovecot.conf to enable lmtp
nano /usr/local/etc/dovecot/dovecot.conf
# ---
protocols = imap lmtp
# ---
# To find the mail_spool_dir
postconf mail_spool_directory
mail_spool_directory = /var/mail
# Edit 10-mail.conf - Use <control>-w to search for values to change
nano /usr/local/etc/dovecot/conf.d/10-mail.conf
# ---
mail_location = maildir:~/Maildir
# later mail_home = /var/vmail/%d/%n
mail_privileged_group = mail
# ---
# Edit 10-master.conf
nano /usr/local/etc/dovecot/conf.d/10-master.conf
# ---
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
mode = 0600
user = postfix
group = postfix
}
# Create inet listener only if you can't use the above UNIX socket
#inet_listener lmtp {
# Avoid making LMTP visible for the entire internet
#address =
#port =
#}
}
service auth {
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
}
# ---
# Edit 20-lmtp.conf
nano /usr/local/etc/dovecot/conf.d/20-lmtp.conf
# ---
protocol lmtp {
# Space separated list of plugins to load (default is global mail_plugins).
mail_plugins = $mail_plugins
}
# ---
# Edit 10-auth.conf
nano /usr/local/etc/dovecot/conf.d/10-auth.conf
# ---
disable_plaintext_auth = yes
auth_default_realm = okbsd.com
auth_username_format = %n
auth_mechanisms = plain login
!include auth-system.conf.ext
# !include auth-sql.conf.ext
auth_debug = yes
auth_debug_passwords = yes
# ---
# Edit 15-mailboxes.conf
nano /usr/local/etc/dovecot/conf.d/15-mailboxes.conf
# ---
mailbox Drafts {
auto = create
special_use = \Drafts
}
mailbox Junk {
auto = create
special_use = \Junk
}
mailbox Trash {
auto = create
special_use = \Trash
}
# 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 = create
special_use = \Sent
}
mailbox "Sent Messages" {
special_use = \Sent
}
# ---
# Modify /usr/local/etc/postfix/main.cf
nano /usr/local/etc/postfix/main.cf
# --- add at end of file
mailbox_transport = lmtp:unix:private/dovecot-lmtp
smtputf8_enable = no
# ---
# Restart and Postfix
service dovecot restart
service dovecot status
dovecot is running as pid 22680
service postfix restart
service postfix status
dovecot is running as pid 22791
# Check if Dovecot is listening on ports
sockstat -l | grep dovecot | egrep -E "143|993"
root dovecot 22680 36 tcp4 *:143 *:*
root dovecot 22680 37 tcp6 *:143 *:*
root dovecot 22680 38 tcp4 *:993 *:*
root dovecot 22680 39 tcp6 *:993 *:*
# Autoconfig and Autodiscover
pkg install git
cd /tmp
git clone https://github.com/smartlyway/email-autoconfig-php
cd /tmp/email-autoconfig-php/mail
mkdir -p /usr/local/www/okbsd/mail
cp /tmp/email-autoconfig-php/mail/config-v1.1.xml /usr/local/www/okbsd/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 /usr/local/www/okbsd/mail/config-v1.1.xml
# ---
<?xml version="1.0"?>
<clientConfig version="1.1">
<emailProvider id="okbsd.com">
<domain>okbsd.com</domain>
<displayName>okbsd.com</displayName>
<displayShortName>okbsd.com</displayShortName>
<incomingServer type="imap">
<hostname>imap.okbsd.com</hostname>
<port>993</port>
<socketType>SSL</socketType>
<authentication>password-cleartext</authentication>
<username>%EMAILADDRESS%</username>
</incomingServer>
<outgoingServer type="smtp">
<hostname>smtp.okbsd.com</hostname>
<port>587</port>
<socketType>STARTTLS</socketType>
<username>%EMAILADDRESS%</username>
<authentication>password-cleartext</authentication>
</outgoingServer>
</emailProvider>
</clientConfig>
# ---
# Configure Autodiscover for Outlook clients.
cp -r /tmp/email-autoconfig-php/Autodiscover/Autodiscover.xml /usr/local/www/okbsd/mail
nano /usr/local/www/okbsd/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>OK Biz Mail</DisplayName>
</User>
<Account>
<AccountType>email</AccountType>
<Action>settings</Action>
<Protocol>
<Type>IMAP</Type>
<Server>imap.okbsd.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>smtp.okbsd.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 mail.okbsd.com
# Autoconfig needs the path http://autoconfig.okbsd.com/mail/config-v1.1.xml
nano /usr/local/etc/apache24/Includes/mail.okbsd.conf
# ---
ServerAlias autoconfig.okbsd.com
ServerAlias autodiscover.okbsd.com
# autoconfig
Alias /mail "/var/www/okbsd/mail"
<Directory /usr/local/www/okbsd/mail/>
Options FollowSymLinks
AllowOverride All
Require all granted
</Directory>
# ---
# Autodiscover uses the host the SRV record points to which is mail.okbsd.com and it
# already has a cert. Autodiscover needs path https://okbsd.com/Autodiscover/Autodiscover.xml.
nano /usr/local/etc/apache24/Includes/ssl-mail.okbsd.conf
# ---
<IfModule mod_ssl.c>
SSLStaplingCache shmcb:/var/run/apache2/stapling_cache(128000)
<VirtualHost *:443>
ServerName mail.okbsd.com
#ServerAlias smtp.okbsd.com
#ServerAlias imap.okbsd.com
#ServerAlias autoconfig.okbsd.com
#ServerAlias autodiscover.okbsd.com
ServerAdmin postmaster@okbsd.com
DirectoryIndex index.php index.html
DocumentRoot /usr/local/www/okbsd/html/
<Directory /usr/local/www/okbsd/html/>
Options FollowSymLinks
AllowOverride All
Require all granted
</Directory>
Alias /mail "/usr/local/www/okbsd/mail/"
Alias "/Autodiscover/Autodiscover.xml" "/usr/local/www/okbsd/mail/Autodiscover.xml/index.php"
<Directory /usr/local/www/okbsd/mail/>
DirectorySlash Off
# Options FollowSymLinks
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
Include /usr/local/etc/letsencrypt/options-ssl-apache.conf
Header always set Strict-Transport-Security "max-age=31536000"
SSLUseStapling on
SSLCertificateFile /usr/local/etc/letsencrypt/live/mail.okbsd.com/fullchain.pem
SSLCertificateKeyFile /usr/local/etc/letsencrypt/live/mail.okbsd.com/privkey.pem
</VirtualHost>
</IfModule>
# ---
apachectl restart
# Confirm these files can be accessed by http and https with a web browser and that they output xml.
http://mail.okbsd.com/mail/config-v1.1.xml
https://mail.okbsd.com/Autodiscover/Autodiscover.xml
# Setup Thunderbird email client - use advanced settings
# If you don't have thunderbird search download thunderbird mail with your web browser and install it.
Settings -> Account Settings -> Account Actions -> Add Mail Account
Incoming / IMAP
Full Name: Jack Pumpkin
Email address: jack@okbsd.com
Password: <secretpassword>
Click Configure Manually
Protocol: IMAP
Hostname: imap.okbsd.com
Port: 993
Security: SSL/TLS
Outgoing / SMTP
Username: jack@okbsd.com
Protocol: Outgoing
Hostname: smtp.okbsd.com
Port: 587
Security: STARTTLS
Username: jack@okbsd.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 check /var/log/maillog
cat /var/log/maillog
# If you can't find the error try clearing the log and tail it from one terminal
# while sending and recieving mail with the mail client.
# clear the log
echo '' > /var/log/maillog
# tail it so you can watch the output
tail -f -300 /var/log/maillog
# Troubleshooting
# 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.
# Test autoconfig by removing the account in Thunderbird and adding it back. If it is
# working properly it should configure quickly with imap.okbsd.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.
# If you get the following error in /var/log/maillog, you forgot postmap -F
# /usr/local/etc/postfix/sni_maps or the path in /usr/local/etc/postfix/main.cf is wrong.
warning: table hash:/usr/local/etc/postfix/sni_maps.db: key smtp.okbsd.com: malformed BASE64 value:
# Next we will install PostfixAdmin