[ On Saturday, August 7, 2004 at 10:22:35 (+0900), Nathan Ollerenshaw wrote: ]
> Subject: [Exim] checking quota before accepting the message
>
> right now I have a lot of messages sitting in queues, being deferred
> for local delivery because the mailbox they are trying to delivery to
> is over quota.
>
> Is there any way to check to see if the message is over quota before
> its 250 OK'd, and fail it? I don't want to generate a bounce if
> possible.
I run the following little script from cron on a short interval (as
short as possible) to regularly re-generate an alias table that routes
the over-quota mailbox addresses to a custom failure address so that
they get rejected at SMTP time instead of having to bounce or defer
them.
I'm pretty sure Exim offers a similar way to "fail" an address (i.e. at
the time the RCPT TO: command is sent to it).
Note this is specific to Cyrus IMAP, but it should be very easy to adapt
to any other quota system. It may be more necessary with Cyrus though
because it's not easy or inexpensive to query Cyrus in any other way to
find out the quota usage on every delivery -- that would be insane! ;-)
#! /bin/sh
#
# mkcyrusoqlist - update the Cyrus Over-Quota list
#
# This script should be run periodically as root from cron (as often
# as you can afford to run it -- Cyrus "quota" is a bit heavy).
umask 022
PATH="/sbin:/bin:/usr/sbin:/usr/bin"; export PATH
argv0=$(basename $0)
# don't use any world-writable directory here!!!
#
# /var/run alone would be OK, but a private directory is better
#
MYTMPDIR="/var/run/$argv0"
if [ ! -d ${MYTMPDIR} ] ; then
if mkdir ${MYTMPDIR} ; then
chmod 700 ${MYTMPDIR}
else
echo "$argv0: ${MYTMPDIR} may exist as a file!" 1>&2
exit 1
fi
fi
if cd $MYTMPDIR ; then
: # OK
else
echo "$argv0: ERROR: Oops! What's up with ${MYTMPDIR}!" 1>&2
exit 1
fi
CYRUS_USER="cyrus"
CYRUS_BIN="/usr/cyrus/bin"
# WARNING: this script could fail to interlock properly if it can be
# invoked simultaneously with more than one name! Don't do that!
#
PIDFILE=${MYTMPDIR}/${argv0}.pid
if [ -s ${PIDFILE} ] ; then
if kill -0 `cat ${PIDFILE}` > /dev/null 2>&1 ; then
: # still running... error reported below...
else
# system probably rebooted while checkerr was running...
rm ${PIDFILE}
rmdir ${LOCKDIR}
fi
fi
if [ -e ${LOCKDIR} ] ; then
echo "It appears there's already an instance of ${argv0} running..." 1>&2
exit 1
fi
if mkdir ${LOCKDIR} ; then
: # got it!
else
echo "$argv0: ERROR: Oops, just missed grabbing ${LOCKDIR}!" 1>&2
exit 1
fi
echo $$ > ${PIDFILE}
rm -f /etc/mail/cyrus_over_quota.tmp
cat <<__EOF__ > /etc/mail/cyrus_over_quota.tmp
#
# # # ###
# # # # ## ##### # # # # # #### ###
# # # # # # # # ## # # ## # # # ###
# # # # # # # # # # # # # # # # #
# # # # ###### ##### # # # # # # # # ###
# # # # # # # # # ## # # ## # # ###
# ## ## # # # # # # # # # #### ###
#
# This file is automatcialy maintained by '$argv0'
#
# Last updated: $(date)
#
__EOF__
# the current implementation only selects mailboxes over 99%
# utilization, generates regular expressions that should match every
# sub-mailbox of the over-quota mailbox root, and aliases them to
# ":fail:" so that they are permanently rejected (i.e. it is assumed
# the default user_with_mbox director is being used).
#
# It might be wise to use >98% instead of >99%.
#
# It might sometimes be desirable to use :defer: for temporary
# rejection, especially if you do not set lmtp_overquota_perm_failure
# to "yes" in your Cyrus imapd.conf, though you really should always
# trigger an immediate and permanent reject for over-quota failures so
# that the sender will know right away what's going on.
#
su -m "${CYRUS_USER}" -c ${CYRUS_BIN}/quota | awk '
$2 > 99 {
# unixhierarchysep: no
sub(/^user\./, "", $4);
# unixhierarchysep: yes
sub(/^user\//, "", $4);
printf("\"%s([-+].*)?\": :fail:\"This mailbox has exceeded its allotted storage quota.\"\n", $4);
}' >> /etc/mail/cyrus_over_quota.tmp
exitvalue=$?
if [ $exitvalue -ne 0 ]; then
echo "$argv0: ERROR: Problems creating /etc/mail/cyrus_over_quota.tmp" 1>&2
else
mv /etc/mail/cyrus_over_quota.tmp /etc/mail/cyrus_over_quota.list
fi
rm -f ${PIDFILE}
exit $exitvalue
--
Greg A. Woods
+1 416 218-0098 VE3TCP RoboHack <woods@???>
Planix, Inc. <woods@???> Secrets of the Weird <woods@???>