[PLUG] Mailbox Size Monitoring

D. Cooper Stevenson cstevens at gencom.us
Thu Jan 15 21:15:03 UTC 2004


All, 

I wish to warn my users when their mbox is nearly full. I found the
script below to be almost what I am looking for.

The trouble is that 1) I deliver the mail to the mbox file under the
user's home directory, not /var/mail/spool and 2) I don't have a
/etc/postfix/virtual file.

Would anyone quickly adapt the script below to work with my environment?

$25.00 bounty to the first person who does this successfully under the
terms of the GPL...

#------------------------- Begin Script --------------------------
#! /usr/bin/perl

# postmmon - POSTfix Mailbox MONitor
# Program to monitor Postfix mailbox sizes
#
#    Copyright (C) <2003>  <Ricardo Malafaia/Eduardo Mendes>

#   This program is free software; you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation; either version 2 of the License, or
#   (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
#   the GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with this program; if not, write to the Free Software
#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
02111-1307  USA

#   More info: http://www.gnu.org or http://www.gnu.org/licenses/gpl.txt

# Program to monitor Postfix mailbox sizes
# NOTE: The program MUST run under CRON, otherwise it won't
# be all that helpful

# Nova Prestech.Net http://www.prestech.net
# Developed and coded by Ricardo Malafaia (ricardo at prestech.net)
# Original idea and blames by Eduardo Mendes (mendes at prestech.net) :)
# V 0.0.6 / 17/jul/2003 (gotta get the habit of using CVS...)

# Project's Homepage: http://www.prestech.net/projetos/postmmon

# Look out for the following parameters when configuring postmmon
# for your system.  Don't be afraid to change them, they are meant
# to.  However, just for precaution, get the habit of comenting
# the original lines rather than overwriting them.  It'll do you
# nothing but good... ;)

# Some configurable parameters and their meaning:

# $upperlimit   => mailbox size limit (read from postfix config file)

# $astepaway  => really close to a full mailbox

# $root     => administrative email account.  Will receive notifications
#              from the program about mailboxes going astray

# $warndayslim =>   limit of days between one warning and another.
#                   For users with mailboxes above 50% and below
$astepaway

# $alertdayslim => limit of days between one alert and another.
#                  For users with mailboxes getting close to the limit.
#                  Should be higher than 50%

# In order to test, once more i advise that you comment out
# the lines rather than overwriting them.

# Comment out the following line as well, during tests.

#use warning;


# A global structure for internal administrative accounting.
# It's in charge of keeping track of the number of days
# a user with mbox > 50% was last alerted
# DON'T TOUCH IT UNLESS YOU'RE REWRITING THE CODE!
my %accounts;

# Many initializations
#BEGIN {

$version="0.0.6";

print "<<<<<<<<<<<<<<<Initializing postmmon
v.$version>>>>>>>>>>>>>>\n\n";

# Some size units
$kb=1024;         #kilobyte
$mb=$kb*1024;        #megabyte

$uni=$kb;       #standard unit ($mb, default)

# Mailbox size limit
#$upperlimit=2*$kb;  # this line very obviously for test purposes only

# Automatically reads in the limit from Postfix config file
$upperlimit=`cat /etc/postfix/main.cf | grep -i mailbox_size_limit`;
# extract the numeric field from the line read
if ($upperlimit =~ /\d+/) { $upperlimit = int($&); }

# Just a step away to $upperlimit: time to alert the administrative
# account that some accounts are almost without space.  In the hopes
# that system administrators yells are more effective than irritating
# mail messages. :)
$astepaway = 6*$mb;

# 50% of mbox limit
$half=int($upperlimit/2);

# almost there...
$almosthere=int($upperlimit*85/100);

print "Mailboxes size limit: $upperlimit bytes\n";

# Number of times a day CRON (or any other scheduler) will run it:
$cron=3;

# Limit of days between one warning and another
# for a user with mbox size above $half
$warndayslim = 7; # 7 days

print "Limit of days between notifications for mailboxes above $half%:
$warndayslim\n";

# this will make sense during administrative accounting
# Yes, its ugly.  Ill try to fix that sometime...
$warndayslim = 7*$cron;

# Limit of days between one alert and another
# for users with mbox above $almosthere
$alertdayslim = 2;

print "Limit of days between notifications for mailboxes closer to the
limit ($almosthere bytes): $alertdayslim\n\n";
# sorry, again
$alertdayslim = 2*$cron;

# mail codes to be executed when mailbox above some limits
# mailto later
$code1='mail -s "Warning: Mailbox above $half%"';
$code2='mail -s "Alert: Mailbox getting closer to the limit."';

#    print "Utilized mail codes: \n";
#    print "$code1\n";
#    print "$code2\n\n";

# Mailbox spool directory
# Normally, /var/spool/mail
$dir="/var/spool/mail/";

print "Mailbox Spool: $dir\n";

# Get the names of users from the names of mailboxes
# from $dir through pipe
open(DIR, "ls -l $dir|");

# Name of the file connecting user names to email accounts
$usermail="/etc/postfix/virtual";

print "File holding username/mail accounts connections: $usermail\n";

# An internal usage file to store accountability information
# about mailboxes above $half
$accountbility='/etc/postfix/accountbility';

# the format of said file will be something in the lines of:
# email at domain    126047932    5
# emai2 at domain    32754235     2
# where:
# column 1 is the infringing user email whose mbox is above $half
# column 2 is the mailbox file size since the previous verification
(bytes)
# column 3 is the number of days (fixed unit, damn! thats why we had to
multiply by $cron, remember?) since the user was last warned or alerted

# If there already exists an accountability file, read entries from it
if (open(ACC, $accountbility)){
print "\nReading from previous administrative entries from
$accountbility\n";
  while(<ACC>){
    my($eml, $tm, $dias) = split(/\s+/);
    $accounts{$eml} = [ int($tm), int($dias) ];
print "Email: $eml, Tamanho: $accounts{$eml}->[0], Dias:
$accounts{$eml}->[1]\n";
  }
  close(ACC);
print "Closing administrative accountability file: $accountbility\n\n";
}


# The lines returned by $usermail through pipe will be
# decomposed in fields
# Three of these are:

our $owner=2; # the username of the mbox owner, while not getting used
our $mboxsize=4;  # the fourth field representing the mbox file size
our $mboxfname=8; # the eightieth field as returned by the pipe is the
mbox file name

# Read from pipe the email accounts from users
print "Reading the email accounts from $usermail\n";

open(ARQ, "cat $usermail | sort |");
while(<ARQ>){
    my($email, @user) = split(/[\s+|,+]+/);
    $email{$user[0]} = $email if $#user == 0; # if an user has more than
one email account, only the first one found will get notifications from
the other mboxes
    print "Email do usuario $user[0]: $email{$user[0]}\n" if $#user ==
0;
}
close ARQ; #print "All email accounts accounted\n\n";


# Text file containing the standard notification message
# to infringing mboxes.  Change it to the file you prefer
$msg="/etc/postfix/mboxfull";

# Administrative email account in charge of all others
$root='ricardo at iprestech.net';
#$root='your_email at your_domain';

print "<<<<<<<<<<<<<<<End of initialization section>>>>>>>>>>>>>>>\n\n";
#} # end of inits



# <<<<<<<<<<<<<<< Operational routine >>>>>>>>>>>>>>>>>

print "Getting mailboxes from $dir\n";

while(<DIR>){

# A structure holding the line fields from the line read.
# Comment out, in case you use perl -an (which i was,
# but was getting problems with var scoping inside those
# BEGIN and END blocks)
local (@F) = split;

# Goes to next line, if mbox doesnt have a related email account.
# Mere precaution
next if not defined $email{$F[$mboxfname]};

print "Email being analized: $email{$F[$mboxfname]}\n";

# if mailbox between $half and $almosthere, duh
if ((int($F[$mboxsize]) >= $half) and (int($F[$mboxsize]) <
$almosthere)) {
print "$email{$F[$mboxfname]} mailbox above half of mbox limit\n";

    $com=qq($code1 $email{$F[$mboxfname]} < $msg);

    # first, search $accountbility for any previous entry
    # in the accountbility file
print "Searching for any previous entry for $email{$F[$mboxfname]}. ";
  if (defined %accounts) {

    # if there already exists an entry for this email
    # and the mbox file size changed
    if ((defined $accounts{$email{$F[$mboxfname]}})
and ($accounts{$email{$F[$mboxfname]}}->[0] != $F[$mboxsize])){
      # if days gone since last notification > $warndayslim, send
another
      if ($accounts{$email{$F[$mboxfname]}}->[1] > $warndayslim){
`$com`;
$accounts{$email{$F[$mboxfname]}}->[1] = 0;
      } # else, update accountbility: one more day
      else { $accounts{$email{$F[$mboxfname]}}->[1] += 1; }
    }

    # if there still isn't an entry for this user...
    else {
print "No previous entry found.  Generating one. \n";
      # Send notification...
      `$com`;
      # ... and updates accountbility
      $accounts{$email{$F[$mboxfname]}} = [ $F[$mboxsize], 0];
    }
  } # defined %accounts

  # accountbility still empty, let's fill it and send notification
  else {
print "Administrative accounts undefined: defining now: ";
    $accounts{$email{$F[$mboxfname]}} = [ $F[$mboxsize], 0];
    `$com`;
print "$email{$F[$mboxfname]}\t\t$F[$mboxsize]\t\t0\n";
  } # fim

}

# else, if larger than $almosthere and below the mbox limit
elsif ((int($F[$mboxsize]) >= $almosthere) and (int($F[$mboxsize]) <
$upperlimit)) {
print "$email{$F[$mboxfname]} mailbox getting close to the limit\n";

    $com=qq($code2 $email{$F[$mboxfname]} < $msg);

print "Looking for any previous entry for $email{$F[$mboxfname]}. ";
  if (defined %accounts) {

    # if there already is an entry for that user and mbox file changed
    if ((defined $accounts{$email{$F[$mboxfname]}})
and ($accounts{$email{$F[$mboxfname]}}->[0] != $F[$mboxsize])){
      # if days gone by since last notification > $alertdayslim, send
another
      if ($accounts{$email{$F[$mboxfname]}}->[1] > $alertdayslim){
`$com`;
$accounts{$email{$F[$mboxfname]}}->[1] = 0;
      }
      #print "else, update accountbility";
      else { $accounts{$email{$F[$mboxfname]}}->[1] += 1; }
    } #print "if there still isn't an entry for this user...";
    else {
print "No previous entry found.  Generating one. \n";
      # send notification...
      `$com`;
      # ... and update accountbility
      $accounts{$email{$F[$mboxfname]}} = [ $F[$mboxsize], 0];
    }
  }

  # accountbility still empty, let's fill it
  else {
print "Accounts undefined: defining now!\n";
    $accounts{$email{$F[$mboxfname]}} = [ $F[$mboxsize], 0];
    `$com`;
print "$email{$F[$mboxfname]}\t\t$F[$mboxsize]\t\t0";
  } # fim

}

# lastly, if mailbox is about to get to the limit,
# mail $root about it and expect for the best... :)
if (int($F[$mboxsize]) > ($upperlimit - $astepaway)) {
    $com=qq(mail -s "$email{$F[$mboxfname]} ($F[$mboxfname]) a step away
from mbox limit: Mailbox utilizing $F[$mboxsize] bytes!" $root < $msg);
    `$com`;
    if (not defined $accounts{$email{$F[$mboxfname]}}){
print "Accounts undefined: defining now!\n";
      $accounts{$email{$F[$mboxfname]}} = [ $F[$mboxsize], 0 ];
  }
} #elsif
} #while DIR
close DIR;


# Some last details

#END {
print "\n<<<<<<<<<<<Finalizing>>>>>>>>>>\n";
print "Updating the accountbility administrative file\n";

#print "Undefined administrative structure\n" if not defined %accounts;

  open(ACCOUNTS, ">$accountbility");
  foreach my $k (keys %accounts) {
    print ACCOUNTS "$k\t\t$accounts{$k}->[0]\t$accounts{$k}->[1]\n";
    print "$k\t\t$accounts{$k}->[0]\t$accounts{$k}->[1]\n";
  }
  close(ACCOUNTS);

print "Closing the accountbility administrative file\n";
print "<<<<<<<<<<<The End>>>>>>>>>>\n";
#}

#---------------------- End Script --------------------------

Best,
-- 
--------------------------------------------------------------
| Cooper Stevenson        | Em:  cooper at gencom.us            |
| General Computer        | Ph:  541.924.9434                |
| "Open For Business"     | Www: http://www.gencom.us        |
--------------------------------------------------------------





More information about the PLUG mailing list