UPDATE: A new version of Mailboy is in the works, it's even getting it's own micro-site at It's not completely ready yet, I'm working on that with the little time I have these days. I'll update this notice when Mailboy will be considered "ready".


Latest: version 0.5

New ACL white/blacklisting
Added template "purplehaze"
minor stuffs like regex comments and stuff i may have forgot to update before.. .oops : ]
fixed bug: can modify aliases to become catchall. added link titles to funky tandy theme
corrected the link to this page in one of the templates because Jan was going to bug me about this forever.. : ]
fixed bug where a server admin could delete the main server admin's domain and hence account

I wrote Mailboy with the intent of this to be a complete web interface for administrating email accounts. It uses a setup with Postfix, Dovecot and Amavis based on the great ISP style tutorial. This web administration interface can work if you have the Etch setup or the Lenny setup (instructions included below).

Mailboy features:

  • Server admin users - users that are "admin" may do anything
  • Per domain admins - a user may be admin for just one or more specific domains
  • Users may change their password and Amavis policy
  • Manage relay domains - so you can become backup MX for others
  • Easy to theme - The appearance can be completely taken care of, 3 themes are included
  • Released under GNU General Public License

The modifications I made to the Workaround tutorial setup:

  • Database: entries must be unique (aliases, domains)
  • Database (lenny): I brought back the "views" because I prefer that
  • Database: foreign keys are all over the place to make things easier to maintain
  • Database: added tables for Relay domains, per user amavis settings and quota
  • Database: create mailadmin user
  • Database: other changes made for the admin interface to work
  • Postfix: Mysql queries in configuration needs to be changed
  • Postfix: Add Mysql file and configuration for Relay domains (optional)
  • Dovecot: Mysql queries in configuration needs to be changed
  • Dovecot: Modify configuration to add per user quota (optional)
  • Amavis: Add option to change subject for spam (applies when user policy says "modify subject Y)
  • Amavis: Edit configuration file to enable per user scan policies

Why so many changes ?

One reason is that the database layout on Etch edition used to please me, now for performance reasons Christoph Haas decided to go without using views, I'm sure that makes a huge difference on big setups but for me it means that the data can possibly be incoherent. That also goes for the domain and alias tables, they have unique keys to ensure there are no duplicate entries. All this means the database scheme is a bit different and so the programs need to query Mysql in a tiny bit different way, it's not that complicated.

Another reason was to enable per user Amavis scanning, meaning you can setup a few policies and users may chose which one they want. This includes settings such as Tag levels, or bypassing certain tests. Users should be able to chose to not have their emails scanned or not have certain checks performed, it can be useful when a user is trying to receive a particular email with an attachment, users can deactivate file checks by him/her-self.

Modifying a server based on the Workaround tutorial does not take long, if you include careful reading and creating backup files as you go this should take less than 30 minutes.

What does this look like ?

A few screenshots will better describe this:

Mailboy - list and edit domains
Mailboy - account details
Mailboy - relay domains
Mailboy - Amavis policies
Mailboy - wow, a clean theme

Ok, lets do it !!

PLEASE TRY THIS ON A TEST SERVER FIRST, you can try it out using a test server be it a real one or via something like VirtualBox. You should always do this when installing any software on a production server. This means that you can possibly break your email server if you do not know what you are doing and are not patient. So take your time in a test environment.. If you are working on an email server I assume you know what you are doing anyways. :]

First thing

You will need a mail server that should be based on the ISP style email tutorial (Don't worry if you are still using the Etch version, it'll in fact be even easier). If you have not installed your mail server than follow the tutorial, it's a good document in that the instructions are precise yet complete, it doesn't lack explanations (so you can actually learn what's going on) and mostly it works just fine. You can for sure manage to use Mailboy in other situations but for that you are on your own (unless you hire me). :]

This page contains information for upgrading from Etch tutorial and Lenny tutorial, all steps are for both systems unless they are color coded as follows:

This is only for Etch tutorial
This is only for Lenny tutorial

Everything else is for both

DB operations

We need to change the way the database looks and add new tables, the simplest way is to (you should know how to do this):

  1. Export/backup the required data (virtual_domains, virtual_users, virtual_aliases)
  2. Drop all the tables on database 'mailserver'
  3. Create new database scheme

    For this there is an included file called database.sql which basically can be copy pasted to PhpMyAdmin or to Mysql shell...

  4. Insert old data
    The data from Etch tutorial should be compliant with the new database structure unless there are double entries.
    On Lenny tutorial user is called "email", we'll need to replace email by user. like this: INSERT INTO `virtual_users` (`id`, `domain_id`, `password`, `email`) VALUES should become: INSERT INTO `virtual_users` (`id`, `domain_id`, `password`, `user`) VALUES We also need to replace things like user@domain.tld to just user. With a text editor you can find and replace, using vim you can use: :%s/@.*'/'/

    The same issue occurs with the table virtual_aliases, the source field should be without the "@domain.tld" part, use the vim trick to get rid of that stuff

  5. Add mailadmin user.

    This user can read/write/delete from the mailserver database, it is needed by Mailboy. From within mysql you may simply type (replace password of course!)

  6. IMPORTANT NOTE: If you get an error like ""constraint exists blah blah" it is probably just because the data is not inserted in the correct order (and so an email cannot exist unless the domain it's referenced to by domain_id exists). Just insert data in this order:
    1. virtual_domains
    2. virtual_users
    3. virtual_aliases

Postfix configuration

Lenny needs a few minor changes, basically we'll need to change the query lines in the following files:
  1. /etc/postfix/ query = SELECT 1 FROM view_users WHERE email='%s'
  2. /etc/postfix/ SELECT destination FROM view_aliases WHERE email='%s'
  3. /etc/postfix/ SELECT email FROM view_users WHERE email='%s'

To add the Relay domain functionality add the new file /etc/postfix/ and inside write:

user = mailuser password = mailuser_password hosts = dbname = mailserver query = SELECT domain FROM relay_domains WHERE domain like '%s'

change permissions

chown root:postfix /etc/postfix/ chmod 640 /etc/postfix/

configure Postfix to use the new file

postconf -e relay_domains=mysql:/etc/postfix/ postconf -e relay_recipient_maps=

If you want to scan aliases addressed to accounts on this server according to the destination account's Amavis settings we should remove the no_address_mappings from, and add it to

comment or delete from

# receive_override_options = no_address_mappings

add in

-o receive_override_options=no_header_body_checks,no_unknown_recipient_checks,no_address_mappings

NEW (0.5): We need to add a couple more files and edit again to use the new ACL settings. This will allow the admin to block or unblock IPs and/or email addresses.

NOTE: If you are upgrading from 0.4.X please read the included "UPGRADE" file for instructions on updating Mailboy's config and database (easy).

Edit /etc/postfix/

user = mailuser password = mailuser_password hosts = dbname = mailserver query = SELECT state FROM domain_access WHERE domain = '%s'

Edit /etc/postfix/

user = mailuser password = mailuser_password hosts = dbname = mailserver query = SELECT state FROM ip_access WHERE ip = '%s'

Change permissions:

chmod 640 /etc/postfix/ chmod 640 /etc/postfix/ chown root:postfix /etc/postfix/ chown root:postfix /etc/postfix/

Edit /etc/postfix/, add at the bottom:

# you should normally uncomment the following line #smtpd_helo_required = yes smtpd_helo_restrictions = permit_mynetworks, check_client_access mysql:/etc/postfix/, reject_non_fqdn_helo_hostname, reject_invalid_helo_hostname # check twice because otherwise allowed IPs may not pass the second test smtpd_client_restrictions = permit_mynetworks, check_client_access mysql:/etc/postfix/, reject_unknown_client_hostname smtpd_sender_restrictions = mysql:/etc/postfix/

Because we modified some things you might want to restart Postfix

/etc/init.d/postfix restart


On Lenny edition edit /etc/dovecot/dovecot-sql.conf and change the password_query line to:

password_query = SELECT email as user, password FROM view_users WHERE email='%u';

If you want to use per user quota settings (optional) you should add just under the previous line (this assumes you store the emails in /var/vmail, otherwise change that):

user_query = SELECT CONCAT('/var/vmail/',CONCAT(SUBSTRING_INDEX(email,'@',-1),'/',SUBSTRING_INDEX(email,'@',1))) AS home, 5000 AS uid, 5000 AS gid, CONCAT('maildir:storage=',quota_kb,':messages=',quota_messages) AS quota FROM view_users WHERE email='%u';

(optional)To enable per user quota settings we need to just add the user_query line to /etc/dovecot/dovecot-sql.conf (this assumes mails are stored in /home/vmail, otherwise change this part)

user_query = SELECT CONCAT('/home/vmail/',CONCAT(SUBSTRING_INDEX(email,'@',-1),'/',SUBSTRING_INDEX(email,'@',1))) AS home, 5000 AS uid, 5000 AS gid, CONCAT('maildir:storage=',quota_kb,':messages=',quota_messages) AS quota FROM view_users WHERE email='%u';

To enable per user quota we also need to edit /etc/dovecot/dovecot.conf. We need to search for the sections protocol imap { and add:

mail_plugins = quota imap_quota

and protocol pop3 { mail_plugins = quota

and protocol lda { mail_plugins = cmusieve quota

If you are using the Etch tutorial you may still be using the Lenny version Debian. However I'm not sure the quota stuff will work on Dovecot on Debian Etch

You may now restart Dovecot

/etc/init.d/dovecot restart


This is where we tell Amavis to actually use the policy table in the database, if you don't do this part everything should still work but users may not change their scan policies

So let's edit /etc/amavis/conf.d/50-user and change or add a few things (if the setting is not in the file then you may add it)

  1. change #$sa_spam_subject_tag = undef; to: $sa_spam_subject_tag = 'SPAM:';
  2. change the $sql_select_policy to $sql_select_policy = 'SELECT * FROM view_users_policies WHERE email IN (%k)';
  3. change or add $sql_select_white_black_list, it should be: $sql_select_white_black_list = undef;

We can finally install Mailboy

At this point your server should be working as usual, so make sure that it works before continuing.

Now you'll need to download Mailboy, for that you may click here. Unpack it where you wish to use it (you should be fluent with this kind of thing).

Copy the example database configuration file db_config.php.example to db_config.php

  1. $db_user: in this case should be "mailadmin"
  2. $db_pass: the crazy secure password
  3. $db_host: in most cases "localhost" should work
  4. $db_database: unless you changed something: mailserver
  5. $super_dooper_user: this sould be set to the id of the master user. This prevents other server admins from modifying this account or managing server admins.

Then copy the example configuration file config.php.example to config.php and change a few things:

  • $mailboy_root: this is the path to the Mailboy install, if you installed Mailboy at the root of your web directory then this should be empty ("")

Other options are:

  • $template: yes, it's completely templatabel :]
  • $privacy_level: 0 is secure, however if you want to allow others to list/add/edit/delete certain things you can change this setting (more info in the config file)

Any user can already log into Mailboy and change their passwords, however there are no admins yet, you should start by manually adding yourself as admin. You can do this via phpMyAdmin or via Mysql (in this case the target user id is 42:

UPDATE virtual_users SET `admin` =1 WHERE id = 42;

Now the user with the id 42 may log in as server admin, the user may now define per domain admins, policies etc etc etc..

I worked quite a while on this after getting some positive feedback on the Bash script that serves this same purpose, so any comments are welcome (via the comment form or the "contact" page).. I hope this project is useful to others. : ]



First of all, a big "thank you" for the bash-script. it works good for me.
And this interface is the next I will check out, the feature-list is impressive.



From me also a BIG thank you !!
I installed the web interface on my Server (needed only two attempts) ;)
so far its working very good.
I’m a little bit new in this Email Server thing... can you give me a hint
what this policies are all about ?
Virus lover, Spam lover, Banned files lover, Bad header lover
and Spam quarantine to.
Thank you again for this nice interface.



Thank you for your feedback : ]

Boris, an Amavis policy determines the configuration of Amavis for a specific user, normally these settings ("spam_lover", "bypass_spam_checks", etc) are in the Amavis config files, however they are overridden by this. Meaning, if a user has no policy set it should default to whatever is in the config files.

As for the meaning of each configuration it's a bit weird but should (Amavis docs!!!) mean what it says:
"spam_lover = Y" means you love spam, means you don't mind recieving it.
"bypass_spam_checks = Y" should mean, "Don't do spam checks on my email"
'spam_tag2_level" When this score is obtained the email is considered (and tagged) as spam.
"spam_modifies_subject = Y" means it will change the subject of emails that are scanned as spam. If it's set to "N" it will still modify headers and add "X-Spam-Flag: YES".
etc, etc... .

You should make a general setting with "N" everywhere (means do all the scans, bypass nothing) and "Y" for subject rewrite.. then create a test account and test new policies on that account to see what happens. The main goal was to allow users to deactivate scanning themselves (temporarily or not), to chose between different levels of spam tagging.. . (spam_tag2_level)..


please help me about fetchmail with mailboy



I have installed and tested your interface. Perhaps,
Important to say, not to use to set up the first user ;-).
I think, the etch-script will work. Right?
One realy wired thing, I can not access the interface via icedove/firefox, it allways want to download a PHTML-file, which is index.php. Konqueror works very well.
Do you have an idea?



Hey Heiko,

Thanks for trying out Mailboy. :]

The beas scripts work strictly with the workaround tutorials whereas Mailboy can be seen as a fork (Database changed with added fields, tables etc). I was thinking about doing a Beas "Mailboy" edition but I'd have to make some time for that.. We shall see.

As for the other problem I'm not sure because I haven't had that issue, If you want me to take a quick look at your install, email me a simple user account and url.



Sorry I can't send you any emails because your provider uses's some fascist blacklist. So if you are reading this, I don't understand what you want to do between Fetchmail and Mailboy, could you explain ?

heiko -

The browser-problem vanished and so I am able to use mailboy.

First impression: very dark :-), I canged to curlybracket.

At the first look a little bit paranoied with the "are you shure check-box, but in the end...
I think, it's not a bad idea, particularly if you leave the account managemend to other people.

The spam-setting page is very impressive and ...
I tested mail-manager, you find the link at as well, and even if this looks cleaner I like mailboy more cause of
* quotas
* spamsetting


Claire Obscure

Hey Manu,

I was thinking of implementing a "new version" checker, like the one in Wordpress, telling users that there is a new version available.

I have not at all checked how they do it but it's probably quite simple, just comparing the existing version with a distant file/RSS or whatever for example. You could also give people the possibility to switch this lookup off, if they feel that this is not secure (as you would have all the URLs using mailboy in your apache logs).

What do you think?

Marnix -

I had to change:

$sql_select_policy = 'SELECT * FROM view_users_policies WHERE email IN (%k)';


$sql_select_policy = 'SELECT *,email FROM view_users_policies WHERE email IN (%k)';

to make spamfiltering work, don't know if it is a flaw on my side or an error in the documentation.




I double checked and it seems to work everywhere using the sql query that i wrote in the documentation. It should actually be the same result as "'SELECT *, email..'" except that in your case you will have the email field come up twice in the result, the second time at the end.

There could be something else going on maybe ? Or maybe a PEBKAC ? (could still be me)
: ]

marnix -

Hi Manu,

You were right, moved it back to the original one and it works. I must have missed something before.

It looks great!

How do you enter a catch-all to a domain? looks like it doesn't accept that?




Marnix, that is correct, there is no way for now to add a catchall from within Mailboy. It seems to do that one would have to add an empty alias (not permitted within the interface). You can do this directly from a MySQL shell or PhpMyadmin. Check the Workaround tutorial if you need the syntax.

I'm not sure this will be added to Mailboy, unless there is some real demand for it as a catchall is not really a great thing these days (unless you want to make a spam honeypot maybe)..

Thanks for confirming that all works as it should..
: ]

Marnix -

Hi Manu,

I must say, quick responses on the questions! thank you very much.

We need the catch-all for some customers that use multiple domains and want all mail go to the same mailboxes. The solution of going into the database works fine, but I like the solution to work through the interface also.

There for I changed ./inc/account_details.php and commented the following lines:

if ($_POST[mod_alias]) {
if (am_i_admin_of($domain_id)) {
# if (!empty($_POST[source])) {
$new_source = strtolower($_POST[source]);
/* check if source contains illegal crap */
if (preg_match("$reg_account", $new_source, $matches)) {
$content[errors][] = "Alias source contains unauthorized characters";
# } else {
# $content[errors][] = "Alias source is empty";
# }
if (!empty($_POST[destination])) {

Which makes it possible to save an empty source field. This solutions works for us and maybe in the future this will be included in mailboy.

We are very pleased with your product and will be testing it the coming weeks.




Hey Marnix,

It's not a good idea to not verify the characters that go into the database, with your modification one can create an alias with chars like: £ ù% * ! and anything else that the keyboard allows.

I changed (for you :] ) :

} else { $content[errors][] = "Alias source is empty";
} else { $content[status][] = "WARNING: Source is empty - This means this is a Catchall alias";

You can download the latest 4.5.1 (link on top of the article), it contains the change, including the templates which say "leave empty if you want a catchall alias"..


BTW Claire Obscure,

I did read your comment and I do think it's a great idea. I'll just say it's not on top of my todo list but I'll try to get to that some day.

Joydeep -

I am already a user of beas script. I could imagine that mailboy will also work great as the beas. As web-admin tool I am using GRSoft and find some security leak ( like user can change their account name ). Is there any doc for Mailboy which can simply configure it with the existing GRSoft settings ?

Keep the good work continue,
with my best wishes


Hello Joydeep,

Nice to hear from you again : ]

I'm afraid to say that Mailboy requires a few changes to the Workaround tutorial, this means it won't work with Beas as Beas sticks to the Workaround database scheme.

You should first try this on a test server to see if this works for you.

In all cases I can confirm, users cannot change their email address and they cannot add/modify aliases either. They can only change their passwords and filtering settings.


"Foreign Keys all over the place"
Just a short test:

domain xyz, account jan
add test -> jan
add test23 -> test
delete test .. test23 still exists

Second "Bug":
Add account Jan2
add alias myAlias -> Jan2
delete account Jan2
Alias still exist.

I'd like to have a warning on delete (and additional be marked in red) for aliases that will fail (because local account/Alias is gone)

Otherwise worse thing is the color scheme ;-)


Thank you Jan for your remarks, however it is not a bug it's a feature.

The source is local, however the destination is not. It is therefore impossible to verify the existence of the destination. Even for destinations that are local, it could concern a domain for which the current admin does not have any permissions. In short the destination of an alias is not the problem of the "current" domain.

As for the color scheme, it seems to be not so popular, good thing there is an included other theme provided by "curlybracket" that's alot cleaner. : ]


You can add a destination for an alias which has no domain part
domain xyz, 1 account jan

add alias
test -> jan

I believe this should forward to the account jan@xyz (not tested) but implies that i have the rights for this destination (domain). Deleting Account jan leaves the test -> jan intact. Or do you always have to supply a complete email as destination (in which case a destination without @Domainpart should not be possible)

A feature request regarding quotas:
1. Is it possible to create a domain quota, that specifys the maximum accumulated quota for a domain (e.g. Quoate 1 GB means: 10 accounts with 100MB or 100 accounts with 10MB?)

2. Can i enforce a quota? I set default domain quota to 1000, but a domain admin can change that to e.g. 10000 and set the quota for users to unlimited (0). But i want the users to
a) always have quotas (do not allow unlimited)
b) the (customer) domain admin not be able to change my maximum limit.

Layout: used curley brackets and tweaked the colors of
.errors, .status

now it is pretty usable.. ;-)

Small Bug:
Link under "Mailboy" in the Footer links to but that gives a 403



For the destination you always need to provide an address your server can handle, if you do not supply anything with an "@" sign then postfix will generally resolve that part to "myhostname". Again the destination is NOT the problem of the local/present domain. If you disagree you are free to hack the code to make it work as you would like.

As for your feature requests, the short answer is "no unless you are willing to pay". This would mostly concern No.2 because No.1 is more of a dovecot thing, although this can be worked around in other ways.

I'm glad you managed to figure out a way to change the css to make it look closer to what you like...

As for the curlybracket template bug, I will correct the link.. . I did create the subdomain mailboy with the intent of giving the project it's own site should it grow... .

Jan is dead/forbidden (from here). So just recreate (configure) the subdomain to point to - problem solved.


nah. I made an update just so you will stop complaining about this.
: ]

marnix -

Hi Manu,

It took me some time before I could continue with mailboy,sorry for the delay. Your update looks indeed better. Though I would expect the changed code also when you are updating an alias (now it only works for the creation of an alias) So I changed that locally on our server.


Marnix, indeed !! I will try to figure out some time and fix this as this is a real bug unlike some other requests. : ]


actually Marnix, it's done \o/


I am unable to login to the web interface after making myself an admin:

* Bad username and/or password



Eddie, that is strange, how did you make yourself an admin ? via mysql or via the Mailboy ?


wow, it is fine!

thank you!


I get a lot of Notices!
Notice: Undefined index: logout in /var/www/mailboy/inc/functions.php on line 143

Notice: Undefined index: login in /var/www/mailboy/config.php on line 47

Notice: Use of undefined constant page - assumed 'page' in /var/www/mailboy/index.php on line 39

Notice: Undefined index: page in /var/www/mailboy/index.php on line 39

Notice: Undefined index: login in /var/www/mailboy/inc/functions.php on line 34

Notice: Undefined index: login in /var/www/mailboy/inc/functions.php on line 34

Notice: Undefined index: login in /var/www/mailboy/inc/functions.php on line 51

Notice: Undefined index: login in /var/www/mailboy/inc/functions.php on line 51

Notice: Use of undefined constant forms - assumed 'forms' in /var/www/mailboy/inc/login.php on line 27

Notice: Use of undefined constant login - assumed 'login' in /var/www/mailboy/inc/login.php on line 27

... and so on.
and i cant login either (because of the tons of notices)

i have a debian server, running lighttpd and PHP 5.3.2 suhosin


Those "Notices" can be suppressed, it's probably your php.ini that likes to be verbose (and I guess I could make the Php code alot more cleaner etc, but still those seem to be simple "notices").

Try adding this to index.php (somewhere towards the top, maybe after the session stuff:
error_reporting (E_ALL ^ E_NOTICE);

Let me know if this helps..



Yepp, works :)


coool \o/



where do I have to change any regex or sth else to get the postfix "address_delimiter" option enabled? I've set this to '+' in postfix, but I can't enter an alias with a plus sign in the source field.
Tried to change the $reg_email regex already, but that didn't solve... ;-)

And, another point, how can I set up an alias which is being delivered to several email addresses? Tried comma and blank between destination email addresses, but neither worked.

Any advice is highly appreciated.




hello, it is indeed a reg but not that one; it should be:
$reg_account = "#[^a-z0-9\\+\\-\\._]#"; I think this is a bit my bad for not having enough comments in the config, i'll fix that. reg_email is actually for verifying complete email addresses like in the destination of the alias, so change this also to be able to send to destinations containing a plus sign (or of course add your own regex to better suit your thingies).

As for adding an alias with multiple destinations:

- add an alias: group@domain => somwhere@anotherdomain
- add a new alias (same "source"): group@domain => somwhereELSE@yetanotherdomain



Cool, that worked like a charm :)

I've used Tequila until now, and there's an alias/list form that's slightly more comfortabel (you may add multiple dest addresses at once), see

Maybe it's a little effort for you to add this, and if so, it really would be a nice-to-have. I'm of little help on this aspect as I don't know PHP at all. ;-(

No matter, Mailboy is relly great work, it completes my long search for a way to switch from CyrusIMAP/Postfix to Dovecot/Postfix! Thanks a lot!




warning: mysql query failed: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''' at line 1

when user not exist in my system



What do you mean. Do not be shy with helpful information, otherwise I will be shy at being helpful.
Leave a comment
You may use the following HTML tags: <p> <a> <strong> <b> <em> <i> <cite> <blockquote> <code> <pre>

Your comments WILL NOT be submitted to any third party (not even for anti spam verification).