Virtual Users And Domains With Postfix, Courier, MySQL And SquirrelMail (CentOS 6.3 x86_64) - Page 5

13 Install Razor, Pyzor And DCC And Configure SpamAssassin

Razor, Pyzor and DCC are spamfilters that use a collaborative filtering network. To install Razor and Pyzor, run

yum install perl-Razor-Agent pyzor

Then initialize both services:

chmod -R a+rX /usr/share/doc/pyzor-0.5.0 /usr/bin/pyzor /usr/bin/pyzord
chmod -R a+rX /usr/lib/python2.6/site-packages/pyzor
su -m amavis -c 'pyzor --homedir /var/spool/amavisd discover'
su -m amavis -c 'razor-admin -home=/var/spool/amavisd -create'
su -m amavis -c 'razor-admin -home=/var/spool/amavisd -register'

Then we install DCC as follows:

cd /tmp
tar xzvf dcc-dccproc.tar.Z
cd dcc-dccproc-1.3.144
./configure --with-uid=amavis
make install
chown -R amavis:amavis /var/dcc
ln -s /var/dcc/libexec/dccifd /usr/local/bin/dccifd

Now we have to tell SpamAssassin to use these three programs. Edit /etc/mail/spamassassin/ so that it looks like this:

vi /etc/mail/spamassassin/

# These values can be overridden by editing ~/.spamassassin/
# (see spamassassin(1) for details)

# These should be safe assumptions and allow for simple visual sifting
# without risking lost emails.

#required_hits 5
#report_safe 0
#rewrite_header Subject [SPAM]

# dcc
use_dcc 1
dcc_path /usr/local/bin/dccproc

use_pyzor 1
pyzor_path /usr/bin/pyzor

use_razor2 1
razor_config /var/spool/amavisd/razor-agent.conf

use_bayes 1
use_bayes_rules 1
bayes_auto_learn 1

Then we must enable the DCC plugin in SpamAssassin. Open /etc/mail/spamassassin/v310.pre and uncomment the loadplugin Mail::SpamAssassin::Plugin::DCC line:

vi /etc/mail/spamassassin/v310.pre

# DCC - perform DCC message checks.
# DCC is disabled here because it is not open source. See the DCC
# license for more details.
loadplugin Mail::SpamAssassin::Plugin::DCC

You can check your SpamAssassin configuration by executing:

spamassassin --lint

It shouldn't show any errors.


/etc/init.d/amavisd restart


Now we update our SpamAssassin rulesets as follows:

sa-update --no-gpg

We create a cron job so that the rulesets will be updated regularly. Run

crontab -e

to open the cron job editor. Create the following cron job:

23 4 */2 * * /usr/bin/sa-update --no-gpg &> /dev/null

This will update the rulesets every second day at 4.23h.


14 Quota Exceedance Notifications

If you want to get notifications about all the email accounts that are over quota, then create the file /usr/local/sbin/quota_notify:

cd /usr/local/sbin/
vi quota_notify

#!/usr/bin/perl -w

# Author <>
# This script assumes that virtual_mailbox_base in defined
# in postfix's file. This directory is assumed to contain
# directories which themselves contain your virtual user's maildirs.
# For example:
# -----------/
#            |
#            |
#    home/vmail/domains/
#        |          |
#        |          |
#                   |
#                   |
#           -----------------
#           |       |       |
#           |       |       |
#         user1/   user2/  user3/
#                           |
#                           |
#                        maildirsize

use strict;

my $POSTFIX_CF = "/etc/postfix/";
my $MAILPROG = "/usr/sbin/sendmail -t";
my @POSTMASTERS = ('postmaster@domain.tld');
my $CONAME = 'My Company';
my $COADDR = 'postmaster@domain.tld';
my $SUADDR = 'postmaster@domain.tld';
my $MAIL_REPORT = 1;

#get virtual mailbox base from postfix config
open(PCF, "< $POSTFIX_CF") or die $!;
my $mboxBase;
while (<PCF>) {
   next unless /virtual_mailbox_base\s*=\s*(.*)\s*/;
   $mboxBase = $1;

#assume one level of subdirectories for domain names
my @domains;
opendir(DIR, $mboxBase) or die $!;
while (defined(my $name = readdir(DIR))) {
   next if $name =~ /^\.\.?$/;        #skip '.' and '..'
   next unless (-d "$mboxBase/$name");
   push(@domains, $name);
#iterate through domains for username/maildirsize files
my @users;
foreach my $domain (@domains) {
        opendir(DIR, $domain) or die $!;
        while (defined(my $name = readdir(DIR))) {
           next if $name =~ /^\.\.?$/;        #skip '.' and '..'
           next unless (-d "$domain/$name");
      push(@users, {"$name\@$domain" => "$mboxBase/$domain/$name"});

#get user quotas and percent used
my (%lusers, $report);
foreach my $href (@users) {
   foreach my $user (keys %$href) {
      my $quotafile = "$href->{$user}/maildirsize";
      next unless (-f $quotafile);
      open(QF, "< $quotafile") or die $!;
      my ($firstln, $quota, $used);
      while (<QF>) {
         my $line = $_;
              if (! $firstln) {
                 $firstln = 1;
                 die "Error: corrupt quotafile $quotafile"
                    unless ($line =~ /^(\d+)S/);
                 $quota = $1;
            last if (! $quota);
         die "Error: corrupt quotafile $quotafile"
            unless ($line =~ /\s*(-?\d+)/);
         $used += $1;
      next if (! $used);
      my $percent = int($used / $quota * 100);
      $lusers{$user} = $percent unless not $percent;

#send a report to the postmasters
   open(MAIL, "| $MAILPROG");
   map {print "To: $_\n"} @POSTMASTERS;
   print "From: $COADDR\n";
   print "Subject: Daily Quota Report.\n";
   print "DAILY QUOTA REPORT:\n\n";
   print "----------------------------------------------\n";
   print "| % USAGE |            ACCOUNT NAME          |\n";
   print "----------------------------------------------\n";
   foreach my $luser ( sort { $lusers{$b} <=> $lusers{$a} } keys %lusers ) {
      printf("|   %3d   | %32s |\n", $lusers{$luser}, $luser);
      print "---------------------------------------------\n";
        print "\n--\n";
        print "$CONAME\n";

#email a warning to people over quota
        foreach my $luser (keys (%lusers)) {
           next unless $lusers{$luser} >= $WARNPERCENT;       # skip those under quota
           open(MAIL, "| $MAILPROG");
           print "To: $luser\n";
      map {print "BCC: $_\n"} @POSTMASTERS;
           print "From: $SUADDR\n";
           print "Subject: WARNING: Your mailbox is $lusers{$luser}% full.\n";
           print "Reply-to: $SUADDR\n";
           print "Your mailbox: $luser is $lusers{$luser}% full.\n\n";
           print "Once your e-mail box has exceeded your monthly storage quota\n";
      print "your monthly billing will be automatically adjusted.\n";
      print "Please consider deleting e-mail and emptying your trash folder to clear some space.\n\n";
           print "Contact <$SUADDR> for further assistance.\n\n";
           print "Thank You.\n\n";
           print "--\n";
           print "$CONAME\n";

Make sure that you adjust the variables at the top (especially the postmaster@domain.tld email address).

We must make the file executable:

chmod 755 quota_notify


crontab -e

to create a cron job for that script:

0 0 * * * /usr/local/sbin/quota_notify &> /dev/null


15 Test Postfix

To see if Postfix is ready for SMTP-AUTH and TLS, run

telnet localhost 25

After you have established the connection to your Postfix mail server type

ehlo localhost

If you see the lines




everything is fine.

[root@server1 sbin]# telnet localhost 25
Trying ::1...
Connected to localhost.
Escape character is '^]'.
220 ESMTP Postfix

<-- ehlo localhost
250-SIZE 10240000
250 DSN

<-- quit
221 2.0.0 Bye
Connection closed by foreign host.
[root@server1 sbin]#



to return to the system's shell.


16 Populate The Database And Test

To populate the database you can use the MySQL shell:

mysql -u root -p

USE mail;

At least you have to create entries in the tables domains and users:

INSERT INTO `domains` (`domain`) VALUES ('');
INSERT INTO `users` (`email`, `password`, `quota`) VALUES ('', ENCRYPT('secret'), 10485760);

(Please take care you use the ENCRYPT syntax in the second INSERT statement in order to encrypt the password!)

If you want to make entries in the other two tables, that would look like this:

INSERT INTO `forwardings` (`source`, `destination`) VALUES ('', '');
INSERT INTO `transport` (`domain`, `transport`) VALUES ('', '');

To leave the MySQL shell, type


For most people it is easier if they have a graphical front-end to MySQL; therefore you can also use phpMyAdmin (in this example under or to administrate the mail database. Again, when you create a user, go sure that you use the ENCRYPT function to encrypt the password:

I do not think I have to explain the domains and users table further.

The forwardings table can have entries like the following:

source destination Redirects emails for to Creates a Catch-All account for All emails to will arrive at, except those that exist in the users table (i.e., if exists in the users table, mails to will still arrive at @anotherdomain.tld This redirects all emails to to the same user at anotherdomain.tld. E.g., emails to will be forwarded to thomas@anotherdomain.tld., billing@anotherdomain.tld Forward emails for to two or more email addresses. All listed email addresses under destination receive a copy of the email.

The transport table can have entries like these:

domain transport : Delivers emails for locally. This is as if this record would not exist in this table at all. smtp:mail.anotherdomain.tld Delivers all emails for via smtp to the server smtp:mail.anotherdomain.tld:2025 Delivers all emails for via smtp to the server, but on port 2025, not 25 which is the default port for smtp.


The square brackets prevent Postfix from doing lookups of the MX DNS record for the address in square brackets. Makes sense for IP addresses. smtp:mail.anotherdomain.tld Mail for any subdomain of is delivered to mail.anotherdomain.tld.
* smtp:mail.anotherdomain.tld All emails are delivered to mail.anotherdomain.tld. smtp:mail.anotherdomain.tld Emails for are delivered to mail.anotherdomain.tld.


man transport

for more details.

Please keep in mind that the order of entries in the transport table is important! The entries will be followed from the top to the bottom.

Important: Postfix uses a caching mechanism for the transports, therefore it might take a while until you changes in the transport table take effect. If you want them to take effect immediately, run

postfix reload

after you have made your changes in the transport table.


17 Send A Welcome Email For Creating Maildir

When you create a new email account and try to fetch emails from it (with POP3/IMAP) you will probably get error messages saying that the Maildir doesn't exist. The Maildir is created automatically when the first email arrives for the new account. Therefore it's a good idea to send a welcome email to a new account.

First, we install the mailx package:

yum install mailx

To send a welcome email to, we do this:


You will be prompted for the subject. Type in the subject (e.g. Welcome), then press ENTER, and in the next line type your message. When the message is finished, press ENTER again so that you are in a new line, then press CTRL+D:

[root@server1 ~]# mailx
Subject: Welcome
Welcome! Have fun with your new mail account. <-- ENTER
<-- CTRL+D
[root@server1 ~]#

Share this page:

12 Comment(s)

Add comment


From: pepo at: 2013-04-05 21:26:12

I had some problems to send email though the server. Checking the maillogs I found these errors:

Apr  5 22:46:06 pepomail postfix/smtpd[23884]: connect from ******.nl[]
Apr  5 22:46:06 pepomail postfix/smtpd[23884]: warning: SASL authentication failure: cannot connect to Courier authdaemond: No such file or directory
Apr  5 22:46:06 pepomail postfix/smtpd[23884]: warning: SASL authentication failure: Password verification failed
Apr  5 22:46:06 pepomail postfix/smtpd[23884]: warning: *****.nl[]: SASL PLAIN authentication failed: generic failure

After a little Googleling I found that the jail of postfix causes this problem. You can solve this by adding a simlink to the authdaemon socket file inside of the chroot:

cd /var/spool/postfix
ln /var/spool/authdaemon/socket courier-authdaemon-socket

Then change the authdaemond_path in your smtpd.conf to just ‘courier-authdaemon-socket’. Restart postfix and it should work

Check for details.

Happy mailing!


From: Roneil Balbarino at: 2013-04-23 20:49:51


What if my mailbox directory looks like in below table.?

Another thing is I am using vquota in where I set the quotas per mail addresses.

 virtual_mailbox_limit_maps = hash:/etc/postfix/vquota

What should the script looks like? I was having trouble making the script works. Would really appreciate if someone could help me. Thanks! 

#            |
#            |
#        home/vmail
#            |
#            |
#    -----------------
#    |       |       |
#    |       |       |
# user1/   user2/  user3/
#                    |
#                    |
#                maildirsize

From: Lokendra at: 2013-07-30 10:18:32

Hi there,

I have successfully integrated Vadmin plugin in to squirrelmail.

Using vadmin I am able to create users, but when I try to login using new user credentials, I get "ERROR: Connection dropped by IMAP server."

and when I send welcome message using mailx command and try to login again, it logs-in successfully.


My question is can we send welcome mail to new users using vadmin plugin or some other way.


Please reply back as soon as possible..


Also there is no sql table structure defined required by vadmin , i have to improvise and created tables and columns by looking its queries.

Can you please help me locate table structure required by vadmin.


Thank you in advance..!


From: ggajic at: 2013-11-23 16:30:22

Hi, package cyrus-sasl-plain is missing. When  I tried:

]# telnet localhost 25
Trying ::1...
Connected to localhost.
Escape character is '^]'.

Connection closed by foreign host.
this is what I got in /var/log/maillog:

Nov 23 17:20:40 mail postfix/smtpd[13580]: connect from localhost[::1]
Nov 23 17:20:40 mail postfix/smtpd[13580]: warning: xsasl_cyrus_server_get_mechanism_list: no applicable SASL mechanisms
Nov 23 17:20:40 mail postfix/smtpd[13580]: fatal: no SASL authentication mechanisms
Nov 23 17:20:41 mail postfix/master[8319]: warning: process /usr/libexec/postfix/smtpd pid 13580 exit status 1
Nov 23 17:20:41 mail postfix/master[8319]: warning: /usr/libexec/postfix/smtpd: bad command startup -- throttling

  yum install cyrus-sasl-plain

solves problem

From: Samuel Vera at: 2013-05-29 22:03:36


los log del mailog

chdir No such file or directory

May 29 11:49:47 server1 imapd: No such file or directory

ERROR: Connection dropped by IMAP server



pliss help

From: at: 2013-06-01 20:24:31

error squirrelmail Submitted by Samuel Vera (not registered) on Wed, 2013-05-29 23:03. error los log del mailog chdir No such file or directory May 29 11:49:47 server1 imapd: No such file or directory ERROR: Connection dropped by IMAP server pliss help

From: Anonymous at: 2013-06-06 04:20:57

hi, i have the same issue with your email server Connection drop by IMAP server, how's your email server, did you solve the problem? how can i fix it? thanks

From: deny yulianto at: 2013-09-23 18:43:23

If you had an error like ERROR: Connection dropped by IMAP server when you log into you squirrelmail and you check on your email log you found something like this>>>> chdir No such file or directory server1 imapd: No such file or directory. DONT DO THIS >>> INSERT INTO `transport` (`domain`, `transport`) VALUES ('', ''); If you do that, your email will loopback by sending your email into your linux system user that used mailx for send the message. Your mail will be delivered to /var/spool/mail/your_user_name. try to vi /var/spool/mail/your_user_name to check your mail that was looped back. The solution is DROP your 'transport' table values on your mail database. Then your mail server should be okay.

From: Anonymous at: 2013-12-08 05:12:47

hi all, I followed all the tutorial regarding this postfix mail server configuration. Everything was going fine. But at last when i logged into the squirrelmail page, previously there was error like "Error: Connection Drop by IMAP server" so, i drop the 'transport' table values. But now, when i logged into the squirrelmail, a blank page appear with no data. Please guys help me. I cannot find the solution.

From: Anonymous at: 2013-12-08 05:29:37

hi all, I have following this tutorial for mail server configuration. Everything was working fine.But finally when i logged in to the squirrel mail, previously there was error like "Error: Connection Drop by IMAP server" and i drop the 'transport' table values and again try to logged in to the squirrel, the IMAP error message is gone but there is no data on squirrel mail page. Guys please help.

the log message when i logged into the squirrel mail home page is following:

tail -f /var/log/maillog

Dec 5 11:23:26 mail imapd: Connection, ip=[::ffff:] Dec 5 11:23:26 mail imapd: LOGIN,, ip=[::ffff:], port=[33857], protocol=IMAP

Dec 5 11:23:26 mail imapd: LOGOUT,, ip=[::ffff:], headers=0, body=0, rcvd=30, sent=238, time=0 Dec 5 11:23:46 mail clamd[1839]: SelfCheck: Database status OK.

From: Hadi at: 2014-11-27 16:02:48

Any one will follow this tutorial will have a problem: Connection dropped by IMAP

 The Solution ( if you have the user : admin @ )

create the directory in "/home/vmail"

 then create the user admin mailbox:

 maildirmake  /home/vmail/

 chown vmail.vmail -R /home/vmail/


From: admin at: 2014-11-28 07:21:59

The Mailbox gets xreated automatically by postfix when the first email arrives. Thats why the guide contains instructions to send a mail to the Mailbox first before you use it.