Let us start with some basic theory on email domains that Postfix can handle. Postfix distinguishes between three kinds of domains. This is a very important concept that you need to understand. Probably half of the support request of desperate readers is caused by misunderstandings here. So please do not skip this section but take your time understanding the matter.
This page is just for explaining the concept – there is nothing to be done on your server yet. For even more confusing information see also the documentation on virtual domains on the Postfix website. 🙂
Postfix is the software component that speaks SMTP and sends and receives emails from the internet. Typically Postfix knows about local domains and local users. A local user is just a normal system user – one that is listed in the /etc/passwd file. This means that all system users will get emails for any local domain. The “mydestination” configuration setting lists all local domains. Example:
mydestination = example.org, example.com, example.net
Let’s say you created a system user “johndoe” (e.g. using the “adduser” command). This simple setup will make Postfix receive emails for
Postfix automatically receives emails for these users and saves them under /var/mail/johndoe. The limitation is that you can’t make johndoe’s account just work in one of these 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. Is it still a good idea to set up at least one local domain in case of configuration or operation problems with other types of domains. If you don’t feel creative and do not really need a local domain then “mydestination = localhost” is a safe choice.
Virtual mailbox domains
This type of domains is the most important type in this tutorial. A virtual mailbox domain is also a domain used to receive email. But you do not use system users (/etc/passwd) to specify valid email addresses in that domain. Instead you explicitly tell Postfix which addresses are valid. A simple way to configure such domains and users is using text files. Consider the following mapping of recipient email addresses to mailboxes on the disk:
|Virtual user||Virtual mailbox location on disk|
You have two domains: example.org and example.com. So first you will have to tell Postfix about these domains. This is done by setting
virtual_mailbox_domains = example.org example.com
in your Postfix configuration. Next you need to tell Postfix which email addresses you are ready to receive email for and where to store the received emails on disk. The respective text file could be stored in /etc/postfix/virtual_mailbox_users and would look like this:
As you can see the valid email addresses are specified in the left column. And the place on disk where the emails for each recipient address are stored is specified in the right column. In Postfix documentation you may also find the acronym LHS for “left hand side” – this means the left column. Equally the RHS is the “right hand side” – the right column. Such a table with two columns is also called a mapping or hash table.
In the above example I have just hardcoded the virtual domains in the Postfix configuration file (“virtual_mailbox_domains = example.org example.com”). Obviously with many domains this is not feasable. That is why you can also use a mapping file to configure the domains. Let’s assume you created such a file /etc/postfix/virtual_mailbox_domains and it looks like this:
You may wonder why we can’ t just list the domains one-per-line in this file. The reason is that a mapping file always has two columns. In such a “one-dimensional” mapping (list of domains) Postfix does not care about your second column. It does not even have to be “OK” – it can be anything.
If you decided that such text files are okay for you then you will still have to compile these files by running the “postmap” command on them. Example:
postmap will create create additional files based on the above file names but with a “.db” suffix. Postfix will not do that automatically – this is a common caveat. And Postfix will only obey the *.db files. So do not forget to run postmap after you changed a mapping file. To make these mappings known to Postfix you would add these lines to your main.cf configuration file:
virtual_mailbox_domains = hash:/etc/postfix/virtual_mailbox_domains
virtual_mailbox_maps = hash:/etc/postfix/virtual_mailbox_users
Now you have the tools you need to set up thousands of domains and email accounts in two text files. That’s nice. But actually I promised that we will store such data in a MySQL database. Fortunately this is not much harder than using the text files. Remember: a mapping is simply a way to assign one value to another . So all you have to do is tell Postfix how to access the two columns of a mapping from a database table. This is done using ‘.cf’ configuration files (see also http://www.postfix.org/MYSQL_README.html or run “man 5 mysql_table” in the shell).
Example virtual_mailbox_maps.cf 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 MySQL server
dbname = mailserver
# The SQL query string
query = SELECT mailbox_path FROM virtual_users WHERE email_address=’%s’
Imagine that you have a database table for virtual users with two columns. The left-hand side is the “email_address” column in that table. And the right-hand side is the “mailbox_path” column in that table. So this SQL query gets the right-hand side (mailbox path) for a given email address (email_address). The “%s” is the placeholder for the left-hand side and is filled by Postfix on every lookup.
Note that a lookup here must only return just one row from the database. Postfix must uniquely know where the mailbox path for a given user is. There are other mappings though where it’s allowed to have multiple right-hand side items for one left-hand side item – for example in virtual aliases as shown in the next section.
To use the above configuration file you have to configure it in Postfix’s main.cf file:
virtual_mailbox_maps = mysql:virtual_mailbox_maps.cf
If later you find that this mapping is not doing what you intended then the “postmap -q” command can be used to ask Postfix what the right-hand side value for a given left-side value would be. Say that you are interested in the mailbox_path for the email_address “email@example.com”:
postmap -q firstname.lastname@example.org mysql:virtual_mailbox_maps.cf
Postfix will then run the above SQL query with your “email@example.com” argument:
SELECT mailbox_path FROM virtual_users WHERE email_address=’firstname.lastname@example.org’
The result should be:
(Note: In this tutorial we will not let Postfix deliver the email directly. Rather it hands over incoming email to Dovecot. So we won’t use the above virtual_mailbox_maps in this tutorial. It is still important to understand how Postfix deals with virtual users.)
Virtual alias domains
Virtual alias domains are used for forwarding email from an email address to one or more other email addresses. Virtual alias domains can’t receive email though and save them to disk on your server. They only forward mail somewhere else. The virtual_alias_maps mapping contains forwardings (source, destination) of users or domains to other email addresses or entire domains. Incidentally virtual_alias_maps are obeyed for any received email. So in most cases you do not really need virtual alias domains as you can declare all domains as virtual mailbox domains and use virtual alias maps for forwarding purposes. Technically defining a domain as a virtual alias domain makes Postfix accept email for that domain but you still need an entry in the virtual_alias_maps mapping to tell Postfix where to forward the email.
A note on the virtual_alias_maps: they can return multiple right-hand side destinations (to forward to) for one left-hand side source (the original recipient). You can use that to forward copies of an email to several recipients.
Example 1: forward all email for email@example.com to firstname.lastname@example.org
This one is simple example. You have the source (email@example.com) and the destination (firstname.lastname@example.org) of the forwarding. John will never get the email.
Example 2: forward all email for email@example.com to firstname.lastname@example.org but also receive a copy
This is a bit trickier. If Postfix queries this mapping for email@example.com it will get two results. (Postfix is smart enough not to create a loop but to understand that you want to get a copy of the emaill.) This is the same as one row with the recipients seperated by commas:
firstname.lastname@example.org email@example.com, firstname.lastname@example.org
Example 3: forward all email for any user in the example.org domain to email@example.com
This is called a catch-all alias. It will accept email for any user in the example.org domain and forward it to firstname.lastname@example.org. If email@example.com would not be an explicitly defined virtual user then her email would be caught by the catch-all alias and forwarded to firstname.lastname@example.org.
Beware: Catch-all aliases catch spam. Lots of spam. They may look comfortable because they forward all email to one person without the need for creating aliases. But spammers often try to guess email addresses at a known domain. And with a catch-all alias you will receive spam for any of those guessed email addresses. Avoid them and rather define the existing email addresses. Even if it is more work.