Check Disk Quota Usage By Parsing Maildirsize

In the previous article, I have explained how to check the quota usage by using perl scripts. maildir quota checking is done by using File::Find function which seems a bit slow and too much consuming I/O process. same as the find function on bash script. find function in perl perform disk usage by determining the size of all files and directories recursively. all sizes of files and directories then accumulated.

find(sub{ -f and ( $size += -s ) }, $diruser );

actually, examination of maildir quota usage is also done by imap server which is written into a file called maildirsize.  So, rather than wasting resources on the server. we can directly read the specified quota and usage on maildirsize file.

Maildir quota usage using File::Find

sub checksize {
        my $diruser = $_[0];
        trim($diruser);
        my $size;
        find(sub{ -f and ( $size += -s ) }, $diruser );
        if (defined $size) {
                $size = sprintf("%u",$size);
                return $size;
        }
        return undef;
}

Postfix Checking Maildir Disk Usage / Quota On The Fly

Postfix does not have built-in quota inspection feature. i’ve seen people on mailing list asking how to check maildir usage on the fly. Add-ons such as VDA , vda inspect quota after email was accepted. When someone over quota, they will bounce mail, Just imagine, when bad guys sent lots of email to overdrawn account with fake return address/sender envelope, on purpose. Our mail server will be backscatter source. spamming undelivered message to innocent people.

Maildrop and Dovecot can handle quota better, but still they’re all inspect maildir usage after accepting the mail. And likely they will bounce email after the first inspect overquota maildir. Ideally, sender should be rejected at smtp conversation time. RCPT TO stage will perfect place for inspecting recipient maildir usage. Before postfix introducing tcp_table, the best solutions was creating map for overquota user. this can be done by using script by querying user quota constant specified in database, then compared to usage in maildirsize file or maildir disk usage.

I wrote this simple perl script, has functions to inspect user quota specified in database, and maildir disk usage. it runs as daemon. it’s not perfect. the script lack of ability when dealing with email address alias or email address extension. Just keep in mind tcp_table connection is not protected and the server is not authenticated.

There are two main functions which are used in this script. checksqlsize and checksize.

checksqlsize is used to check user quota specified in the database. you can adjust parameters in the script as needed,

sub checksqlsize {
        my $user = $_[0];
        my $sqlresult;
        trim($user);
        my $dbh = DBI->connect('DBI:mysql:postfixdb:localhost', 'user', 'password', { RaiseError => 1 });
        my $sth = $dbh->prepare(qq{SELECT quota FROM mailbox WHERE username='$user'});
        $sth->execute();
        while (my @row = $sth->fetchrow_array) {
                $sqlresult = $row[0];
        }
        $sth->finish();
        $dbh->disconnect;
        if ($sqlresult >= 0 ) {
                return $sqlresult;
        } else {
                return undef;
        }
}

Maildroprc Automatically Delete quotawarn File in Maildir

This is the Ugly workaround

Postfix master.cf setting

maildrop  unix  -       n       n       -       -       pipe
  flags=ODRhu user=vmail argv=/usr/bin/maildrop -w 90 -d ${recipient} ${user} ${domain}

With this setting maildrop wil warn user if their Maildir reach 90% of quota and send warning to user

The problem is, even if user emptying their maildir, users wil always get warning because quotawarn is still in Maildir

[vchkpw] quotawarn question

#
MAILHOME="/var/data/postfix"
DOMAIN="$2"
USER="$1"

QUOTA=`echo "$MAILDIRQUOTA" | cut -f 1 -d S`
USAGE=`du -sb "$MAILHOME/$DOMAIN/$USER/" | awk '{print $1}'`
PERCENT=`echo "$QUOTA * 90/100" | bc`

if ( "$USAGE" < "$PERCENT" )
{
        `/bin/rm -f "$MAILHOME/$DOMAIN/$USER/quotawarn"`
}