Setting up mail accounts without real Linux users

Honest advice, use normal user accounts and let your Linux system authenticate the users. This is easy to manage and very secure. I don't want to say that other systems are insecure but I trust my Linux system when it comes to storing and authenticating passwords. I use these commands to create users manually. This way they can do no harm on my system.

useradd -d /home/username -g 515 -u 603 -s /sbin/nologin username
echo 12345678 | passwd user --stdin

-g 515 is your groupid for mail users
-u 603 needs to be incremeted by one for each user you create

This deletes the user

userdel -f username

Then append to the file /etc/postfix/virtual your users as

[email protected]    username

This is the part I use in master.cf

submission inet n       -       n       -       -       smtpd
  -o smtpd_helo_required=no
  -o smtpd_tls_wrappermode=no
  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
  -o smtpd_recipient_restrictions=reject_non_fqdn_recipient,permit_sasl_authenticated,reject
  -o milter_macro_daemon_name=ORIGINATING
  -o smtpd_sasl_type=dovecot
  -o smtpd_sasl_path=private/auth
  -o smtpd_sasl_security_options=noanonymous

Run the following commands after adding or removing a user

postmap /etc/postfix/virtual
service postfix restart

(The last command may be different on not RHEL clones, e.g. Ubuntu. Not sure, don't use it.). And have in your /etc/postfix/main.cf the following settings

virtual_alias_maps = hash:/etc/postfix/virtual

Don't forget to increase in dovecot the mail_max_userip_connections variable, see Dovecot ignoring maximum number of IMAP connections .


There is several ways to do this. The easiest one however is to have only one software do the authentication - in your case this would be Dovecot as postfix can be configured to use Dovecot SASL for authentication. It is also convenient to only have one software managing directories for emails, so I recommend to use Dovecot as LDA (local delivery agent aka "the software that puts files in directories") instead of letting postfix do this itself.

Below I will show you the relevant parts from my config, keep in mind thogh that those are in no way complete, working configurations. There is no point in posting my complete mail stack config though as your exact needs will likely differ from mine.

I use PostgreSQL as database, however MySQL should work just as well - just make sure to change the driver and also install an matching driver if your dovecot does not ship with one.

From postfix/main.cf

virtual_mailbox_domains          = $mydomain, pgsql:/etc/postfix/pgsql_domains.cf
virtual_alias_maps               = pgsql:/etc/postfix/pgsql_aliases.cf
virtual_mailbox_maps             = pgsql:/etc/postfix/pgsql_mailboxes.cf

######################
### Authentication ###
######################
# Basic
smtpd_sasl_type                  = dovecot
smtpd_sasl_path                  = private/dovecot-auth
smtpd_sasl_auth_enable           = yes
smtpd_sasl_local_domain          = $mydomain

 # Allowed Methods
smtpd_tls_auth_only              = yes
smtpd_sasl_security_options      = noanonymous
smtpd_sasl_tls_security_options  = noanonymous

########################
### Mailbox Settings ###
########################
mail_spool_directory             = /srv/mail/localhost/
virtual_mailbox_base             = /srv/mail/
mailbox_command                  = /usr/lib/dovecot/dovecot-lda -f "$SENDER" -a 
"$RECIPIENT" -d "$USER"
virtual_transport                = dovecot

Make sure to also set your client restrictions to include permit_sasl_authenticated but exclude other senders for outgoing email to not create an open relay.

content of /etc/postfix/pgsql_domains.cf

hosts   = /var/run/postgresql
user   = mail
dbname = mail
query  = SELECT DISTINCT 1 FROM users WHERE domain='%s';

contents of /etc/postfix/pgsql_aliases.cf

hosts = /var/run/postgresql
user   = mail
dbname = mail
query  = SELECT email||'@'||domain AS alias FROM users WHERE '%u'='users' AND domain='%d';

contents of /etc/postfix/pgsql_mailboxes.cf

hosts = /var/run/postgresql
user   = mail
dbname = mail
query  = SELECT 1 FROM email WHERE email='%u' AND domain='%d';

from postfix/master.cf

dovecot         unix    -       n       n       -       -       pipe
  flags=DRhu user=mail:mail argv=/usr/lib/dovecot/dovecot-lda -f ${sender} -a  ${recipient} -d ${user}@${nexthop}

From dovecot config (doesn't matter if you put it in a file that gets included somewhere or directly in the main config):

service auth {
 #-- Default Socket
  unix_listener auth-userdb {
    mode = 0666
    user = mail
    group = mail
  }
 #-- Socket for Postfix
  unix_listener /var/spool/postfix/private/dovecot-auth {
    mode = 0660
    user = postfix
    group = postfix
  }
}

######################
### Authentication ###
######################

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

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

#########################
### Location Settings ###
#########################
#   %u - username
#   %n - user part in user@domain, same as %u if there's no domain
#   %d - domain part in user@domain, empty if there's no domain
#   %h - home directory
mail_home             = /srv/mail/%d/%n
mail_location         = maildir:~/mai

Adjust /var/spool/postfix to wherever your postfix is chrooted to (if it is, but it should be)

Contents of /etc/dovecot/conf.d/sql-login.conf.ext referenced above:

driver              = pgsql
connect             = host=/var/run/postgresql/ dbname=mail user=mail
default_pass_scheme = SHA512
password_query      = SELECT email as username, domain, password FROM users WHERE email = '%n' AND domain = '%d';
user_query          = SELECT email as username, domain           FROM users WHERE email = '%n' AND domain = '%d';
iterate_query       = SELECT email as username, domain           FROM users;

(Make sure to adjust the connection string according to your database host, db name, user and possibly also password)

My database layout:

           Table "mail.users"
    Column     |  Type   |   Modifiers
---------------+---------+---------------
 email         | text    | not null
 domain        | text    | not null
 password      | text    |
Indexes:
    "users_pkey" PRIMARY KEY, btree (email, domain)

Keep in mind that those are taken literally from my mail config and might need adjustments and need to be integrated in your current config. This is especially true for dovecot, where your distribution might or might not already have some of the settings in files scattered around your config directory - it is common for dovecot distributions to use a lot of includes.

ALso make sure that inbox folders for users /the config above puts them in /srv/mail) get created and dovecot-lda can write and access all folders. The config above also delivers email of local email users to /srv/mail/localhost for consistency, this is fully optional though and you can deliver them wherever you already have them.

You can do a lot more once you have that setup - configure master users who can login as anybody, configure blocklists for temporarily disabled accounts, configure alias emails, and so on. But what is above should be sufficient to authenticate against a DB and deliver email to virtual user accounts.


[Edit]: I just realized that Postfix DOES need some lookups for email-relaying, specifically for virtual_domain, virtual_alias and virtual_mailbox configurations. I added the relevant parts.