Skip to content

Postfix and Dovecot

The following text describes how to set up Postfix and Dovecot using LMTP transport to receive e-mail and maintaining the mailboxes in a MariaDB/MySQL database table.

uml diagram

Prerequisites

  1. There must be a user vmail with group vmail without shell acccess (e.g. with shell /bin/false). This user has to be created if needed.
  2. The mail storage is expected to be in the path /var/vmail/mydomain with user vmail and group vmail as owner.
  3. Postfix uses user postfix and group postfix (this is the usually the default when installing Postfix as package in Debian).
  4. Instead of mydomain use the real domain, this is just an example.
  5. MariaDB/MySQL with a database containing table mailboxes with the following fields: email, password - this table defines the list of available mailboxes with their email address and password for mailbox access.

Postfix

The following options in /etc/postfix/main.cf are used to allow Postfix to receive e-mail for the external domain and send all outgoing e-mail to other domains to a smarthost named relayserver.example via SMTP. If you don't need a smarthost, you can also omit this option. Then Postfix will try to send the e-mail directly to the respective MX of the outgoing mail.

Keep in mind to set myhostname to the correct FQDN and if needed, add all other domains for which Postfix should accept incoming e-mail to mydestination.

In addition, there are virtual mailboxes based on a database table. All incoming e-mails will be forwarded via LMTP to a Dovecot instance on the same server.

smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU)
biff = no

append_dot_mydomain = no

readme_directory = no

compatibility_level = 2

smtpd_use_tls=no

smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination

# My own FQDN
myhostname = mydomain.local

smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/smtp_auth
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
myorigin = /etc/mailname

# My own domains for which I accept incoming e-mail
mydestination = $myhostname, localhost

# Optional: send all outgoing mail to a specific relay host
# relayhost = relayserver.example

# Networks from where we accept mail without authentication (relay)
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128

mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all
inet_protocols = all

# Integration of the user mailboxes
virtual_mailbox_maps = mysql:/etc/postfix/virtual_mailbox_maps.cf

# LMTP transport for incoming mail
virtual_transport = lmtp:unix:private/dovecot-lmtp
virtual_uid_maps = static:998
virtual_gid_maps = static:998

home_mailbox = Maildir/
local_transport = lmtp:unix:private/dovecot-lmtp
local_recipient_maps = $virtual_mailbox_maps

The file /etc/postfix/virtual_mailbox_maps.cf contains the configuration to look up virtual mailboxes from the application database. The values for DBUSER, DBUSER, DBUSER and DBHOST have to be the credentials for the application database. The SQL query has to be used as it is.

user=DBUSER
dbname=DBNAME
password=DBPASSWORD
hosts=DBHOST
query=SELECT email FROM mailboxes WHERE email='%s'

Dovecot

Dovecot will provide the mail storage and can be accessed via IMAP to access the mailboxes and LMTP to receive e-mail via Postfix. Dovecot will automatically create a new local mail folder when needed.

The file /etc/dovecot/conf.d/10-master.conf contains the service configuration for LMTP - we provide a local unix socket for Postfix to receive e-mail. The socket is owned by the user and group which is used by Postfix:

service lmtp {
  unix_listener /var/spool/postfix/private/dovecot-lmtp {
    user = postfix
    group = postfix
    mode = 0660
  }
}

In /etc/dovecot/conf.d/10-mail.conf the user and group for the mail storage is configured, user vmail with group vmail:

# For postfix lmtp and virtual users

mail_uid = vmail
mail_gid = vmail

The file /etc/dovecot/conf.d/10-auth.conf defines how user logins are looked up:

# Authentication and local mailboxes

auth_mechanisms = plain

!include auth-sql.conf.ext

The file /etc/dovecot/conf.d/auth-sql.conf.ext defines the list of configuration files for the database access:

# Authentication for SQL users. Included from 10-auth.conf.
#
# <doc/wiki/AuthDatabase.SQL.txt>

passdb {
  driver = sql
  args = /etc/dovecot/dovecot-sql.conf.ext
}

userdb {
  driver = sql
  args = /etc/dovecot/dovecot-sql.conf.ext
}

And finally in /etc/dovecot/dovecot-sql.conf.ext the database connection and queries for user enumeration and authentication are defined. The values for DBUSER, DBUSER, DBUSER and DBHOST have to be the credentials for the application database. The SQL queries have to be used as they are.

driver = mysql
connect = host=DBHOST dbname=DBNAME user=DBUSER password=DBPASSWORD
default_pass_scheme = PLAIN
password_query = select email AS user, password AS password from mailboxes where email = '%u';
user_query = select email AS userid, password AS password, concat('/var/vmail/mydomain/', email) as home, concat(concat('maildir:/var/vmail/mydomain/', email), '/Maildir') as mail from mailboxes where email = '%u';
iterate_query = select email as user from mailboxes where email is not null and email <> '';

Folders for "special use"

Some folders can be marked for "special use". These folders will then automatically be used by the clients for storing sent e-mails etc..

This can be achieved by adding the following section to the Dovecot configuration. This was successfully teste with Mozilla Thunderbird and K9 Mail. You may need to change the mailbox names if they differ in your local setup, but leave the values for special_use as they are:

namespace inbox {
  inbox = yes
  mailbox Archive {
    special_use = \Archive
  }
  mailbox Drafts {
    special_use = \Drafts
  }
  mailbox Junk {
    special_use = \Junk
  }
  mailbox Sent {
    special_use = \Sent
  }
  mailbox Trash {
    special_use = \Trash
  }
}