I went the database route:
- Install Postfix
- Install and configure MySQL
- (optional for PostfixAdmin) Install the rest of the LAMP stack
create user named “vmail”
adduser vmail -u 5000 -d /var/mail/vhosts -s /sbin/nologin
mkdir -p /var/mail/vhosts
chown -R vmail:vmail /var/mail/vhosts
edit /etc/postfix/main.cf
below “mynetworks”:
virtual_mailbox_domains = mysql:/etc/postfix/mysql-domains.cf
virtual_mailbox_maps = mysql:/etc/postfix/mysql-users.cf
virtual_alias_maps = mysql:/etc/postfix/mysql-aliases.cf
virtual_mailbox_base = /var/mail/vhosts
virtual_minimum_uid = 5000
virtual_uid_maps = static:5000
virtual_gid_maps = static:5000
in /etc/postfix/mysql-domains.cf:
hosts = 127.0.0.1
user = DB_USER_GOES_HERE
password = DB_PASSWORD_GOES_HERE
dbname = DB_NAME_GOES_HERE
table = domain
select_field = domain
where_field = domain
additional_conditions = and backupmx = '0' and active = '1'
#query = select domain from domain where domain = '%s' and active = 1
in /etc/postfix/mysql-users.cf:
hosts = 127.0.0.1
user = DB_USER_GOES_HERE
password = DB_PASSWORD_GOES_HERE
dbname = DB_NAME_GOES_HERE
table = mailbox
select_field = maildir
#where_field = username
#additional_conditions = and active = '1'
query = select maildir from mailbox where username = '%s' and active = 1
result_format = %sMaildir/
in /etc/postfix/mysql-aliases.cf:
hosts = 127.0.0.1
user = DB_USER_GOES_HERE
password = DB_PASSWORD_GOES_HERE
dbname = DB_NAME_GOES_HERE
table = alias
select_field = goto
where_field = address
additional_conditions = and active = '1'
the schema for the database:
--
-- Table structure for table `admin`
--
DROP TABLE IF EXISTS `admin`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `admin` (
`username` varchar(255) NOT NULL,
`password` varchar(255) NOT NULL,
`created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`modified` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`active` tinyint(1) NOT NULL DEFAULT '1',
PRIMARY KEY (`username`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='Postfix Admin - Virtual Admins';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `alias`
--
DROP TABLE IF EXISTS `alias`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `alias` (
`address` varchar(255) NOT NULL,
`goto` text NOT NULL,
`domain` varchar(255) NOT NULL,
`created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`modified` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`active` tinyint(1) NOT NULL DEFAULT '1',
PRIMARY KEY (`address`),
KEY `domain` (`domain`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='Postfix Admin - Virtual Aliases';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `alias_domain`
--
DROP TABLE IF EXISTS `alias_domain`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `alias_domain` (
`alias_domain` varchar(255) NOT NULL,
`target_domain` varchar(255) NOT NULL,
`created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`modified` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`active` tinyint(1) NOT NULL DEFAULT '1',
PRIMARY KEY (`alias_domain`),
KEY `active` (`active`),
KEY `target_domain` (`target_domain`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='Postfix Admin - Domain Aliases';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `config`
--
DROP TABLE IF EXISTS `config`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `config` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL DEFAULT '',
`value` varchar(20) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=latin1 COMMENT='PostfixAdmin settings';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `domain`
--
DROP TABLE IF EXISTS `domain`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `domain` (
`domain` varchar(255) NOT NULL,
`description` varchar(255) CHARACTER SET utf8 NOT NULL,
`aliases` int(10) NOT NULL DEFAULT '0',
`mailboxes` int(10) NOT NULL DEFAULT '0',
`maxquota` bigint(20) NOT NULL DEFAULT '0',
`quota` bigint(20) NOT NULL DEFAULT '0',
`transport` varchar(255) NOT NULL,
`backupmx` tinyint(1) NOT NULL DEFAULT '0',
`created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`modified` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`active` tinyint(1) NOT NULL DEFAULT '1',
PRIMARY KEY (`domain`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='Postfix Admin - Virtual Domains';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `domain_admins`
--
DROP TABLE IF EXISTS `domain_admins`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `domain_admins` (
`username` varchar(255) NOT NULL,
`domain` varchar(255) NOT NULL,
`created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`active` tinyint(1) NOT NULL DEFAULT '1',
KEY `username` (`username`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='Postfix Admin - Domain Admins';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `domains`
--
DROP TABLE IF EXISTS `domains`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `domains` (
`domain` varchar(50) NOT NULL,
PRIMARY KEY (`domain`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `fetchmail`
--
DROP TABLE IF EXISTS `fetchmail`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `fetchmail` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`mailbox` varchar(255) NOT NULL,
`src_server` varchar(255) NOT NULL,
`src_auth` enum('password','kerberos_v5','kerberos','kerberos_v4','gssapi','cram-md5','otp','ntlm','msn','ssh','any') DEFAULT NULL,
`src_user` varchar(255) NOT NULL,
`src_password` varchar(255) NOT NULL,
`src_folder` varchar(255) NOT NULL,
`poll_time` int(11) unsigned NOT NULL DEFAULT '10',
`fetchall` tinyint(1) unsigned NOT NULL DEFAULT '0',
`keep` tinyint(1) unsigned NOT NULL DEFAULT '0',
`protocol` enum('POP3','IMAP','POP2','ETRN','AUTO') DEFAULT NULL,
`usessl` tinyint(1) unsigned NOT NULL DEFAULT '0',
`extra_options` text,
`returned_text` text,
`mda` varchar(255) NOT NULL,
`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `forwardings`
--
DROP TABLE IF EXISTS `forwardings`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `forwardings` (
`source` varchar(80) NOT NULL,
`destination` text NOT NULL,
PRIMARY KEY (`source`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `log`
--
DROP TABLE IF EXISTS `log`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `log` (
`timestamp` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`username` varchar(255) NOT NULL,
`domain` varchar(255) NOT NULL,
`action` varchar(255) NOT NULL,
`data` text NOT NULL,
KEY `timestamp` (`timestamp`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='Postfix Admin - Log';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `mailbox`
--
DROP TABLE IF EXISTS `mailbox`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `mailbox` (
`username` varchar(255) NOT NULL,
`password` varchar(255) NOT NULL,
`name` varchar(255) CHARACTER SET utf8 NOT NULL,
`maildir` varchar(255) NOT NULL,
`quota` bigint(20) NOT NULL DEFAULT '0',
`local_part` varchar(255) NOT NULL,
`domain` varchar(255) NOT NULL,
`created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`modified` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`active` tinyint(1) NOT NULL DEFAULT '1',
PRIMARY KEY (`username`),
KEY `domain` (`domain`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='Postfix Admin - Virtual Mailboxes';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `quota`
--
DROP TABLE IF EXISTS `quota`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `quota` (
`username` varchar(255) NOT NULL,
`path` varchar(100) NOT NULL,
`current` bigint(20) DEFAULT NULL,
PRIMARY KEY (`username`,`path`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `quota2`
--
DROP TABLE IF EXISTS `quota2`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `quota2` (
`username` varchar(100) NOT NULL,
`bytes` bigint(20) NOT NULL DEFAULT '0',
`messages` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`username`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `transport`
--
DROP TABLE IF EXISTS `transport`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `transport` (
`domain` varchar(128) NOT NULL DEFAULT '',
`transport` varchar(128) NOT NULL DEFAULT '',
UNIQUE KEY `domain` (`domain`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `users`
--
DROP TABLE IF EXISTS `users`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `users` (
`email` varchar(80) NOT NULL,
`password` varchar(20) NOT NULL,
PRIMARY KEY (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `vacation`
--
DROP TABLE IF EXISTS `vacation`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `vacation` (
`email` varchar(255) NOT NULL,
`subject` varchar(255) CHARACTER SET utf8 NOT NULL,
`body` text CHARACTER SET utf8 NOT NULL,
`cache` text NOT NULL,
`domain` varchar(255) NOT NULL,
`created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`active` tinyint(1) NOT NULL DEFAULT '1',
PRIMARY KEY (`email`),
KEY `email` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COMMENT='Postfix Admin - Virtual Vacation';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `vacation_notification`
--
DROP TABLE IF EXISTS `vacation_notification`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `vacation_notification` (
`on_vacation` varchar(255) CHARACTER SET latin1 NOT NULL,
`notified` varchar(255) CHARACTER SET latin1 NOT NULL,
`notified_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`on_vacation`,`notified`),
CONSTRAINT `vacation_notification_pkey` FOREIGN KEY (`on_vacation`) REFERENCES `vacation` (`email`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Postfix Admin - Virtual Vacation Notifications';
/*!40101 SET character_set_client = @saved_cs_client */;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
finally, to easily manage it, install PostFixAdmin (PFA):
http://postfixadmin.sourceforge.net/