The Basics: Virtual Domains in a Database

Before going into detail about virtual domains let's first understand the concept of...

Local domains

Postfix is the component that receives emails from the internet. Typically Postfix knows about local domains (configured in the "mydestination" setting) and local users (those who can log into the system and are listed in the /etc/passwd file). This means that all system users will get emails for any local domain. As an example you may have set...

mydestination = example1.com, example2.com, example3.com

Let's say you created a system user "johndoe" (e.g. using the "adduser" command). This simple setup will make Postfix receive emails for

  • johndoe@example1.com
  • johndoe@example2.com
  • johndoe@example3.com

You can't make johndoe's account just work in one domain. So this is not feasible for different users in different domains. Neither will it work well with many users as you had to create system accounts for each of them.

Virtual domains

Instead of defining your email domains in a text file and creating many system accounts there is a better choice for non-trivial Postfix-based mail servers. Domain names and user accounts can be stored in a directory like LDAP or a database like MySQL or PostgreSQL. Postfix will just need to know how to access the database to get this control information. In such a configuration email domains that Postfix will be responsible for are called virtual domains. Similarly the user accounts are called virtual users. They just live in a database.

There are two basic types of virtual domains that Postfix knows. "Virtual alias domains" can be used for forwarding ("aliasing") email from an email address to another email address (or multiple addresses). Virtual alias domains do not receive email for any users. They only forward mail somewhere else. The virtual_alias_maps mapping contains forwardings (source, destination) of users or domains to other email addresses or whole domains. Incidentally virtual_alias_maps also works for local email addresses, too. So you do not really need virtual alias domains as you can declare all domains as virtual mailbox domains and use virtual alias maps for aliases.

The other type of virtual domains are "virtual mailbox domains" which are more important here. They define domains which are used to actually receive emails.

 

All this starts to sound fancy? Don't panic. Let's see an example of such a database table that tells which user accounts can receive emails and where those should be stored on your system:

Example for virtual_mailbox_maps
Virtual user Virtual mailbox location
john@doe.org /var/mail/doe.org/john/Maildir
jack@doe.org /var/mail/doe.org/jack/Maildir
jeff@foo.org /var/mail/foo.org/jeff/Maildir

The above is a perfectly valid example for what Postfix expects as a mapping called "virtual_mailbox_maps".

Although you may argue that the above table contains all necessary information there is one more thing that Postfix expects: a list of (virtual) domains. In the above example that list would consist of doe.org and foo.org. That mapping table would be used as "virtual_mailbox_domains" and looked like this:

Example for virtual_mailbox_domains
Virtual domain Just some dummy string
doe.org banana daiquiri
foo.org tequila sunrise

You will probably wonder why there is a second column with seemingly useless data. The reason is that Postfix always expects two columns in a mapping. The left column (or "left-hand side"=LHS) is usually the key and contains what Postfix is looking for. The right column (or "right-hand side"=RHS) is what tells Postfix what to do. For the list of virtual domains Postfix just looks for any non-empty result in a line where the domain is listed on the left. Some people just write "OK" in there - it doesn't matter.

You have now seen that a mapping assigns one value to another. If you query a database you need to tell Postfix which two columns you mean. This is done through '.cf' configuration files as documented at http://www.postfix.org/MYSQL_README.html or through "man 5 mysql_table".

Example file:

# Information on how to connect to your MySQL server
user = someone
password = some_password
hosts = 127.0.0.1

# The database name on the servers.
dbname = mailserver

# The SQL query template.
query = SELECT destination FROM virtual_aliases WHERE source='%s'

This file defines the way that Postfix can get data from your database. It would be suitable for a virtual_alias_maps mapping (it is used for email forwarding - we will get to that later). Imagine you saved the above lines into a configration file /etc/postfix/mysql-virtual-alias-maps.cf. Then the following line in your /etc/postfix/main.cf would make Postfix query the database:

virtual_alias_maps = mysql:/etc/postfix/mysql-virtual_alias_maps.cf

How does this work? Imagine that Postfix is about to send an email to john@doe.net and wants to check the virtual alias map. Postfix then opens up a connection to the MySQL server at the IP address 127.0.0.1 and authenticates to the MySQL server with the username someone and the password some_password. It selects the database mailserver and finally runs a query replacing '%s' by what it's looking for:

SELECT destination FROM virtual_aliases WHERE source='john@doe.net'

Assume this query returned these rows:

  • jack@example.com
  • jeff@example.com
  • kerstin@example.com

That would be as if you had a text file with an alias like this:

john@doe.net -> jack@example.com, jeff@example.com, kerstin@example.com

So much for a quick introduction on how mappings are used with databases.