Procmail – rebuild mailquota for virtual domains

Technical
December 14, 2011 12:24 pm

Hello

If you use Postfix for your mail server, but deliver the actual mail through Procmail, you might notice that quotas stop working properly.

This is because if you use Procmail then Postfix itself is no longer responsible for creating the actual directories on the filesystem, nor is it responsible for keeping track of how many emails are on the server. Therefore, by default, quotas will not be recorded.

You can manually recreate the quotas using the following command on your mail server:

maildirmake -q -10024S /home/vmail/$DOMAIN/$USER/

But it would be impossible to manually run that command for each user every time a new email is received. It would be nice to automate this process, but the problem is that we need to know the size of the mailbox, and that value is kept in the database. Therefore, we need to run a script with procmail that will go in to the database, find a given user’s quota and regenerate the maildir.

Here is a script I wrote many years ago; it’s in PHP, because back then that’s all I knew, but it still holds its own and can easily be done in a better script language.

<?php
    $config = array(
    'dbname' => '-',                 # Database name
    'dbhost' => '-',                 # Database host
    'dbuser' => '-',                 # Database user
    'dbpass' => '-',                 # Database password
    'quota_field' =>'quota',            # Field containing quota
    'email_field' => 'username',            # Field containing email
    'user_table' => 'mailbox',             # Field containing mail users
    );

    $dsn = 'mysql:dbname=%s;host=%s';
    $dsn = sprintf($dsn, $config['dbname'], $config['dbhost']);
    try
    { 
        $dbh = new PDO($dsn, $config['dbuser'], $config['dbpass']);
    }
    catch (PDOException $e)
    {
        die('Connection fail: ' . $e->getMessage());
    }

    $email = sprintf('%s@%s', $argv[1], $argv[2]);

    $sql = 'SELECT `' . $config['quota_field'] . '` FROM `' . $config['user_table']. '` WHERE `' . $config['email_field']  . "` = '$email'";   
    $stmt = $dbh->prepare($sql);
    $stmt->execute();

    $command = 'maildirmake -q %dS /home/vmail/%s/%s/';
    $chown = 'chown vmail:vmail /home/vmail/%s/%s/maildirsize';
    while ($row = $stmt->fetch())
    {
        exec(sprintf($command, $row['quota'], $argv[2], $argv[1]));
        exec(sprintf($chown, $argv[2], $argv[1]));
    }

Create it somewhere on your server, ensure it is owned by vmail, executable and only vmail can read your passwords from it. Then, at the end of your existing procmail script (probably /usr/local/bin/procmailed) add

#!/bin/sh
#/usr/bin/procmail -m /etc/procmailrc
...
/usr/bin/procmail -p -m /etc/procmailrc $DOMAIN $USER
php /usr/local/bin/procmailed-quotas $USER $DOMAIN # ADD THIS LINE
This article was written by on Wednesday, December 14, 2011 at 12:24 pm. You can follow any responses to this entry through the RSS feed. You can leave a response, or trackback from your own site. Tags:

Leave a Reply


XCOM: Enemy Unknown

October 21, 2012
XCOM: Enemy Unknown

XCOM: Enemy Unknown is the latest modernisation of a classic game developed by Firaxis and published by 2k. Although the franchise has a colourful history of cancelled games and relatively unheard of releases, it’s heyday was back in the mid-nineties with the original Enemy Unknown and the sequel, Terror from the Deep, being the titles that most gamers will be familiar with. Their premise was as simple then as it is now. Aliens have started invading a near future earth [...]

Continue Reading →

Asking for forgivness, not permission

July 19, 2012

Sometimes in life it’s easier to be forgiven for something than it is to get permission. It’s an approach I’ve been trying to adopt in my programming lately in a way that sometimes feels a little counter intuitive. If, for example, you need to ensure something going in to a database needs to be unique you may do something like this: def generate_slug(self): if not self.slug: self.slug = slugify(self.title) try: Page.objects.get(slug=self.slug) self.slug = self.slug + "_" self.generate_slug() except Page.DoesNotExist: self.save() [...]

Continue Reading →

Eurogamer Expo 2012

October 1, 2012
Eurogamer Expo 2012

2012 was my second year at Eurogamer, the first being last year, but it was no less spectacular second time round. I only went on the Saturday this year, mostly because I booked my ticket too late, but also because I wasn’t so interested in the games on offer this year. There were tonnes of triple A titles on show, as well as the usual mix of merchandise, retro gaming, t-shirts and the like. But if I’m honest, the games [...]

Continue Reading →

The Beat-Herder Festival – 2012

April 15, 2012
The Beat-Herder Festival – 2012

Starting to get quite excited about this year’s Beat-Herder Festival! 6 or so friends have confirmed, and I have my ticket + parking pass. More of the lineup has been trickling out  over the last few weeks and I’m most exited to be seeing Slamboree, Lee Scratch Perry and Parov Stelar. There’s also loads of stuff on that I’ve never heard of, so hopefully I’ll bring home some new names to listen to afterwards. Anyone who has not heard of [...]

Continue Reading →