NewHalo Edge 3 is here: HTTP/3 everywhere and 42 edge locations.Learn more
Docs / Email servers

Create virtual mailboxes for your domain

Email servers10 min readUbuntu 24.04 LTS

Creating a Linux user for every email address does not scale, and it gives every mailbox a shell account. Virtual mailboxes let Postfix and Dovecot host many addresses for your domain, with their passwords stored in a file and every message owned by one unprivileged system user.

Before you begin

  • Postfix and Dovecot installed and configured for mail.example.com (see the Postfix main.cf and Dovecot articles).
  • Your TLS certificate in place, so that password logins are encrypted.
  • A sudo user on the server. This guide creates alex@example.com as the first virtual address.
  • Some patience with configuration files. Each change is small, and each step ends with a check.

Step 1: Create a system user that owns all the mail

Every virtual mailbox is stored under one folder and owned by one unprivileged account, usually named vmail. It has no login shell and no home directory of its own. Using a fixed numeric ID (here 5000) keeps the ownership consistent across services.

sudo groupadd --gid 5000 vmail
sudo useradd --uid 5000 --gid vmail --system --home-dir /var/mail/vhosts --shell /usr/sbin/nologin vmail
sudo mkdir -p /var/mail/vhosts
sudo chown -R vmail:vmail /var/mail/vhosts

The last line gives the vmail user ownership of the mail folder. If you see "already exists" for the user or group, it was created in an earlier attempt and you can continue.

Step 2: Tell Postfix which domain and mailboxes are virtual

Postfix needs three things: the list of virtual domains, a map from each address to a folder, and the user that owns the delivered files. First, create the address map. Each line holds an address and a folder path relative to /var/mail/vhosts. The trailing slash marks a Maildir folder.

sudo nano /etc/postfix/vmailbox
# address                 folder (relative to /var/mail/vhosts)
alex@example.com          example.com/alex/Maildir/

Save the file, then turn it into the hashed lookup format Postfix uses, and set the Postfix options.

sudo postmap /etc/postfix/vmailbox
sudo postconf -e 'virtual_mailbox_domains = example.com'
sudo postconf -e 'virtual_mailbox_base = /var/mail/vhosts'
sudo postconf -e 'virtual_mailbox_maps = hash:/etc/postfix/vmailbox'
sudo postconf -e 'virtual_uid_maps = static:5000'
sudo postconf -e 'virtual_gid_maps = static:5000'
sudo postconf -e 'virtual_minimum_uid = 100'

The static:5000 settings make Postfix write every message as the vmail user. Create the folder structure now so delivery has somewhere to write:

sudo mkdir -p /var/mail/vhosts/example.com/alex/Maildir/{cur,new,tmp}
sudo chown -R vmail:vmail /var/mail/vhosts
Careful: a domain must not appear in both mydestination and virtual_mailbox_domains. Remove example.com from mydestination if it is there, using sudo postconf -e 'mydestination = $myhostname, localhost'. Otherwise Postfix delivers to a Linux account instead of the virtual mailbox.

Step 3: Store virtual passwords in a file

Dovecot can check passwords against a plain file instead of Linux accounts. Each line holds a full address and a password hash. Generate the hash with doveadm, which prompts for the password and never stores it in your shell history.

sudo doveadm pw -s SHA512-CRYPT

Copy the resulting string, which starts with {SHA512-CRYPT}$6$, into the password file:

sudo nano /etc/dovecot/users
alex@example.com:{SHA512-CRYPT}$6$your-generated-hash-goes-here

Restrict who can read the file, since it contains password hashes:

sudo chown root:dovecot /etc/dovecot/users
sudo chmod 640 /etc/dovecot/users

Step 4: Point Dovecot at the password file

Dovecot's default authentication uses Linux accounts. Switch it to the password file and tell it that every virtual user maps to the vmail account and their own folder. First, create the new authentication settings:

sudo nano /etc/dovecot/conf.d/auth-passwdfile.conf.ext
passdb {
  driver = passwd-file
  args = scheme=SHA512-CRYPT username_format=%u /etc/dovecot/users
}
userdb {
  driver = static
  args = uid=vmail gid=vmail home=/var/mail/vhosts/%d/%n
}

Next, switch the authentication include in 10-auth.conf. The first command turns off the system-account version, and the second turns on the password-file version.

sudo sed -i 's|^!include auth-system.conf.ext|#!include auth-system.conf.ext|; s|^#!include auth-passwdfile.conf.ext|!include auth-passwdfile.conf.ext|' /etc/dovecot/conf.d/10-auth.conf
sudo systemctl restart dovecot
sudo doveconf -n passdb

The %d and %n placeholders are the domain and the local part of the address. For alex@example.com, the home folder becomes /var/mail/vhosts/example.com/alex, which matches the Maildir path from Step 2.

Step 5: Test one mailbox end to end

Check each part on its own before you send mail. Then send a test message.

sudo postmap -q alex@example.com hash:/etc/postfix/vmailbox
sudo doveadm auth test alex@example.com
echo "Virtual mailbox test" | mail -s "Virtual test" alex@example.com
sudo ls /var/mail/vhosts/example.com/alex/Maildir/new

Expected output: the first command prints example.com/alex/Maildir/. The second prompts for the password and prints auth succeeded. The last command lists at least one file, which is the delivered message.

Tip: To add another mailbox, repeat Steps 2 and 3 with a new line in each file, run sudo postmap /etc/postfix/vmailbox, and reload with sudo systemctl reload postfix dovecot. No restart of the whole mail system is needed.

Troubleshooting

  • "User unknown in virtual mailbox table": the address is missing from /etc/postfix/vmailbox, or you forgot to run postmap after editing it.
  • Dovecot reports "passdb failed" or auth fails: the hash was copied incorrectly, or the line in /etc/dovecot/users has a stray space. Regenerate the hash and paste it again.
  • "Permission denied" when delivering: the folders are not owned by vmail. Run sudo chown -R vmail:vmail /var/mail/vhosts.
  • "Relay access denied" for your own domain: the domain is in mydestination too, or it is missing from virtual_mailbox_domains. Check both with sudo postconf mydestination virtual_mailbox_domains.

Next steps

You can now host as many addresses as you need on one domain without creating Linux accounts. If you run a DMARC report address, or other role addresses like postmaster, add them the same way. Next, consider the SPF, DKIM and DMARC articles so the mail you send is trusted by other servers.

Something not working? Chat or email our support team and we will help you get unstuck.

Contact support