Setup Email Server From Scratch On FreeBSD - 04 Dovecot IMAP

03 Postfix SMTPD <- Intro -> 05 PostfixAdmin

This tutorial is partially complete 2025-05-14
Postfix, Dovecot, & PostfixAdmin work with MySQL and virtual accounts
can be created with PostfixAdmin and used with an email client. Incoming SPF
milter and outgoing OpenDKIM milter signing tested and working.

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

If you plan to use ARGON2I scheme please compile as follows. I had a lot of difficulty
setting up postfix admin due to several issues but this was one of them 
please check ARGON2I after installing dovecot.

# 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

Initially I installed dovecot but didn't include the LIBSODIUM or any FTS 
options. The mail client worked but wanted to use ARGON2I, so went and moved 
/usr/local/etc/dovecot to /usr/local/etc/dovecot_bak and recompiled with 
dovecot-fts-flatcurve.

cd /usr/local/etc
mv dovecot dovecot_bak
cd /usr/ports/mail/dovecot
make deinstall
make clean
make rmconfig

cd /usr/ports/mail/dovecot-fts-flatcurve
make deinstall
make clean
make rmconfig

make
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

make install

# Make install output
Installing dovecot-2.3.21.1_1...
===> Creating groups
 Creating group 'dovecot' with gid '143'
Creating group 'dovenull' with gid '144'
===> Creating users
Creating user 'dovecot' with uid '143'
Creating user 'dovenull' with uid '144'
 You must create the configuration files yourself. Copy them over
 to /usr/local/etc/dovecot and edit them as desired:

        cp -R /usr/local/etc/dovecot/example-config/* \
                /usr/local/etc/dovecot

 The default configuration includes IMAP and POP3 services, will
 authenticate users agains the system's passwd file, and will use
 the default /var/mail/$USER mbox files.

 Next, enable dovecot in /etc/rc.conf:

        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.

...

https://www.dovecot.org/

#
# Follow the above instructions
#

# Make symlink for convenience
cd /etc
ln -s /usr/local/etc/dovecot

libtool --finish /usr/local/lib/dovecot
sysrc dovecot_enable="YES"

# Copy the example config files.
cp -R /usr/local/etc/dovecot/example-config/* /usr/local/etc/dovecot

# Generate the dh.pem
openssl dhparam -out /usr/local/etc/dovecot/dh.pem 4096

# Dovecot won't start without the certs and vmail configured

cd /usr/local/etc/dovecot/conf.d

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/mx.okbsd.com/fullchain.pem
ssl_key = </usr/local/etc/letsencrypt/live/mx.okbsd.com/privkey.pem
ssl_dh = </usr/local/etc/dovecot/dh.pem
ssl_min_protocol = TLSv1.2
ssl_prefer_server_ciphers = yes

# <save>

# Add the vmail user and group
pw group add vmail -g 2000
grep vmail /etc/group
vmail:*:2000:

adduser
user: vmail
uid: 2000
homedir: /nonexistent
shell: nologin
lockout after creation: yes

chsh vmail
- remove the full name if you wish

grep vmail /etc/passwd
vmail:*:2000:2000::/nonexistent:/usr/sbin/nologin

service dovecot start
service dovecot status
dovecot is running as pid 12903

dovecot --version 
2.3.21.1 (d492236fa0)

# MISC - you might be able to skip this until MISC END
# I got Thunderbird mail client working without installing any of this.
# I installed dovecot without any FTS options but there is a decode2text script. 
# Intructions: https://doc.dovecot.org/2.3/settings/plugin/fts-plugin/#plugin-fts
# https://doc.dovecot.org/2.3/configuration_manual/fts/
# Script: /usr/local/libexec/dovecot/decode2text.sh

# Install these dependencies just in case we need them. These take a long time
# to compile, I gave up on xpdf and just used pkg instead.

pkg install catdoc
pkg install xpdf
pkg install poppler-utils
# MISC END

# 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

pw -s ARGON2I -r 5 -p hello 
{ARGON2I}$argon2i$v=19$m=32768,t=5,p=1$RyC0o8I14UBuFpYHC61HEg$i7BQp0F4 ... etc.

# Comment out the following in openssl, not compatible with dovecot lmtp

openssl version
OpenSSL 3.0.15 3 Sep 2024 (Library: OpenSSL 3.0.15 3 Sep 2024)

nano /etc/ssl/openssl.cnf
# ---
# providers = provider_sect

# Add dovecot user to mail group so it can read the maildir
pw group mod 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 /etc
cp -R postfix postfix_backup

# Backup Dovecot configs
cd /usr/local/etc
cp -R dovecot dovecot_backup

# Paste the following
nano /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 /etc/postfix/main.cf
# ---
myhostname = mx.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 = ${{$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 $mail_name
inet_protocols = all
setgid_group = maildrop
# Debian setgid_group = postdrop
smtp_tls_CApath = /etc/ssl/certs
shlib_directory = /usr/lib/postfix
meta_directory = /usr/libexec/postfix
message_size_limit = 536870912
mailbox_size_limit = 0

#Enable TLS Encryption when Postfix receives incoming emails
smtpd_tls_cert_file=/usr/local/etc/letsencrypt/live/mx.okbsd.com/fullchain.pem
smtpd_tls_key_file=/usr/local/etc/letsencrypt/live/mx.okbsd.com/privkey.pem
smtpd_tls_security_level=may
smtpd_tls_loglevel = 1
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache

#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

# 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 13570.

# Finish Configuring Dovecot

# A useful command
doveadm config

# Edit dovecot.conf to enable lmtp

cd /usr/local/etc/dovecot
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

cd /usr/local/etc/dovecot/conf.d
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
# later mail_plugins = quota

# Edit 10-master.conf

cd /usr/local/etc/dovecot/conf.d
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
}

# Modify /etc/postfix/main.cf

cd /etc/postfix
nano /etc/postfix/main.cf
# --- add at end of file

mailbox_transport = lmtp:unix:private/dovecot-lmtp
smtputf8_enable = no

# Edit 10-auth.conf

cd /usr/local/etc/dovecot/conf.d
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

# Double check 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/mx.okbsd.com/fullchain.pem
ssl_key = </usr/local/etc/letsencrypt/live/mx.okbsd.com/privkey.pem
ssl_min_protocol = TLSv1.2
#ssl_prefer_server_ciphers = no
ssl_prefer_server_ciphers = 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
  }

# restart
service dovecot restart
service dovecot status
dovecot is running as pid 13915

service postfix restart
service postfix status
dovecot is running as pid 13916

# Configure thunderbird mail client and test send and recieve. If there are any 
# problems 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

# And test send and recieve again ...

03 Postfix SMTPD <- Intro -> 05 PostfixAdmin