James supports Virtual User Tables described by either XML or JDBC. See config.xml for an example.


Before I go into explaining how to set up one of the mapping mailets, I want to explain how they will work. Basically, all that a "virtual user table" does is forward emails. THAT'S it. If you think about it this way, it will be very easy to understand it. All we do is forward emails from one address to another. For instance:

That's all there is to it. Now the trick is that this simple function allows us to do powerful things, such as having virutal domains.

Say, we're hosting 2 domains, cars.com and boats.com. Now the owners of both domains want to have "support@" email accounts. Normally, if we created an account "support", both support@cars.com and support@boats.com would be the same email account - and that would be unacceptable. So instead, we can set up the following forwards:

Obviously, we have to create two local accounts: "support..cars.com" and "support..boats.com". So, now when you send a support email to cars.com, it would go into a local account "support..cars.com". When you send an email to support@boats.com, the email would go into a local account "support..boats.com".

Now the whole "support..domain.com" thing is called a naming policy. It is important to keep and follow a strict policy, otherwise you'll have nightmare trying to manage your email accounts.

This is really how easy it is to set up virtual domains. There is however, one problem, which I hope will soon be addressed: even though we have separate accounts for support@ email address, the following addresses would still be valid:

They're valid since they're still treated as normal local email accounts. So this is a TODO and I hope it's addressed soon. It's not really crucial and nobody probably would ever know about it except for the admin, but it still gives me a sense of insecurity.


Now that you understand the theory, in technical terms it's just as simple as the theory. Currently, there are two implementations of this that I know of - XML (XMLVirtualUserTable) and JDBC (JDBCVirtualUserTable) - both come packaged with james 2.2.

Both work exactly the same way, except XML gets its entries from the config file, and JDBC gets them from (you guessed) a database. I highly recommend that you use JDBC over XML if you're planning to have more than 10 different email accounts. If you use XML, every time you want to make a change or add something, you'd have to restart the server.

The entries that both of these mailets accept are:


Compare this with our theory:

user@domain -> target_address

And that's pretty much all there is to it. If we want to have support@cars.com and support@boats.com, assuming that we use "account..domain.com" naming policy, we would have the following entries:

While it seems a bit complicated, in more simple language, the above entries are:

And this is all there is to it.


First of all, you should READ the following: http://james.apache.org/FAQ.html#7 <-Link no longer works

Just read it, but don't do anything about it just yet. I'll walk you through the proccess to the best of my abilities.

Setting Up Database

  1. Well first you need a database. I use MySQL (www.MySQL.com), but you can use whatever you want, as long as they have a JDBC driver. So get and install a database (I'm not going to walk you through this - they have entire books written on the subject; I assume if you're an admin, you should know how to install a database).
  2. After installing the database, create a db named "mail" or whatever you want to call it:

create database mail default charset utf8
  1. Now you want to create a user with privileges on database "mail". I don't create users via raw SQL, I use MySQLCC, so I don't really know what the SQL for that is

  2. Now we want to add the table for mappings:

CREATE TABLE VirtualUserTable
  user varchar(64) NOT NULL default '',
  domain varchar(255) NOT NULL default '',
  target_address varchar(255) NOT NULL default '',
  PRIMARY KEY (user,domain)

Ok we're half way there.

Configuring XML

So now we just need to add that mailet in your xml configuration.

  1. Go to your james home directory (it's inside of whatever your installation folder was, /apps/james/), and go to SAR-INF, and open file "config.xml" (I suggest making a backup copy before editing).
  2. First of all you want to make sure that inside your "<servernames>" you have an entry "<servername>localhost</servername>". It's not really required since you can forward to any local address, but it's good practice.

  3. Now let's tell JAMES where our database is. Scroll all the way down to "<database-connections>". There are a couple examples in there that you could use. Here's my setup:

         <data-source name="maildb" class="org.apache.james.util.dbcp.JdbcDataSource">
            <dburl>jdbc:mysql://;useUnicode=true&amp;characterEncoding=UTF-8</dburl> <!-- "mail" is the database name; change it if you used something different -->
            <user>mail</user> <!-- Whatever the DB user is -->

Now notice there's a "driver" setting, which in my case is MySQL's JConnector driver, which you can find here: http://dev.mysql.com/downloads/connector/j/3.1.html

Download the driver, and stick the .jar file inside your $INSTALL_DIRECTORY/lib. If you use a different database or have a reason to use a different driver, don't forget to change the "<driver>" setting and put the driver itself on the classpath.

  1. Notice that the "<data-source>" tag had a "name" attribute. This doesn't have to be "maildb", it can be anything. But stick to maildb as a standard.

  2. Now let's insert the mailet itself. Scroll up to "<spoolmanager>" and find "<proccessor name="root">". A couple lines below that you should have comments explaining how to set up an "XMLVirtualUserTable" mailet. Right after the "RelayLimit=30" mailet, insert the following:

        <mailet match="All" class="JDBCVirtualUserTable">

Note that you can change the "maildb" if your data source had a different name; or VirtualUserTable, if the table you created earlier has a different name. We're almost done.


  1. Restart the server by running $INSTALL_DIR/bin/phoenix.sh restart
  2. Let's assume that we have two users named "bob" and "jen", and bob owns "domain1.com" and jen owns "domain2.com". Both want their own name account and "sales@" account for their domains pointing to their names.
  3. Start by editing your database either by hand or through a GUI client (my pref), and insert a couple entries:
    • user: bob domain: yourdomain1.com target_address: bob..yourdomain1.com@localhost

    • user: jen domain: yourdomain2.com target_address: jen..yourdomain2.com@localhost

    • user: sales domain: yourdomain1.com target_address: bob..yourdomain1.com@localhost

    • user: sales domain: yourdomain2.com target_address: jen..yourdomain2.com@localhost

  4. Create two users:

telnet localhost 4555
adduser bob..yourdomain1.com bobsPassword
adduser jen..yourdomain2.com jensPassword
  1. TADA! Now you should have two users:  bob@yourdomain1.com  and  jen@yourdomain1.com . Emails sent to "jen@yourdomain1.com" will get a user not found message (unless of course you have another mapping for that domain name or a local user named simply "jen", which would break our naming policy).

Also, emails sent to sales@yourdomain1.com will go to bob's email; all sent to sales@yourdomain2.com will go to jen's email.

  1. I should note that when giving Bob his login information, you should say the following:

Your email address is "bob@yourdomain1.com"
Your username is "bob..yourdomain1.com" (same as your email address, but with two dots instead of "at")
Your password is bobsPassword
  1. By now you should be finished. It is now fairly easy to create a web-based management system for the accounts.


  1. Don't forget that besides virtual domains, you use the same approach to forward to outside domains. For instance, if jen from our previous example wanted all emails sent to "CEO@yourdomain2.com" to go to the US president, you would have to add the following entry in the VirtualUserTable table:

  2. The reason I mentioned that you should have a nameserver "localhost" in the very beginning is because I had some hard times figuring out why the virtual table wasn't working. The problem was my target_address entries - I'd specify them as simply "bob..yourdomain1.com". Turns out that JDBCVirtualUserTable automatically appends "@localhost" to target_addresses that don't have a domain part. And I didn't have the "localhost" in my servernames, and as a result the message couldn't be delivered.


  1. The only advice I have here is: read your logs. So far that helped me fix most of the problems.
  2. Also, don't be afraid to ask questions in the JAMES mail list



I am not qualified to write this since I haven't used it myself. However, if you read the Theory and More Technical sections, you should have no problem whatsoever setting it up. Besides, there are comments in the config.xml that pretty much give you an example.

VirtualUserTable (last edited 2010-11-19 15:09:04 by 69ob)