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

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:

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.

Comments

multiple users in /var/vmail/<domain>

Hi,

first of all: This tutorial is great!

But I have a problem: I just added one user called "james". So I expected one directory in /var/vmail/<domain> called "james". Obviously the mails for my user accounts are forwarded to this destination as well:

blubb:/var/vmail/<domain># ls -l
total 16
drwx------ 3 vmail vmail 4096 Feb 14 21:18 amavis
drwx------ 4 vmail vmail 4096 Feb 11 18:03 james
drwx------ 3 vmail vmail 4096 Feb 14 21:16 postmaster
drwx------ 3 vmail vmail 4096 Feb 14 06:33 root

Any ideas?

Logs?

Glad you liked the tutorial. Regarding your problem... so you have created one virtual user "james" in your domain. And email for any other user in that domain (e.g. "tina@yourdomain") gets forwarded to james? Did you accidentally set up a catchall account? Show us a few lines from your mail.log so we may see what's going on.

No, mails to tine@<domain>

No, mails to tine@<domain> are rejected correctly like this:

<myip>_does_not_like_recipient./Remote_host_said:_550_5.1.1 <tine@<domain>>:_Recipient_address_rejected:_User_unknown_in_virtual_mailbox_table/Giving_up_on_<myip>./

 

The problem is that the users of my lenny system (root, amavis and postmaster). For example the cron demon sent an out of memory mail which has been redirected to /var/vmail/<domain>/root/

There is not virtual alias called root@<domain>

Mixup?

Sounds like you have a mixup in your domain configuration. What is your system domain? (hostname -d)

If your system sending as a domain (see "myorigin" in your main.cf) that you use as a virtual domain?

You are right, the hostnamen

You are right, the hostnamen differ:

hostname -d returns vps-center.de, the domain of my isp.

myorrigin pints to /etc/mailname. This files contains <domain>

So, do I have to redirect my hostname to /etc/mailname using hostname -F /etc/mailname?

Depends

Depends on what you want to do. "myorigin" is what gets added to unqualified email addresses. So if you send mail to "root" then Postfix will add that domain. If you want to receive such email locally (which is the most common case) then set "mydestination" to that domain, too, because that's your local domain.