. mombe.org
home of the mad cow
  Not A Blog
noop :: systems :: cyrusquota
 

Thursday, October 13, 2005

Cyrus, Exim and over-quota messages

We run Exim as our mail transport agent delivering into mailboxes run by the Cyrus IMAP server. We're making use of LMTP to deliver mail from Exim to Cyrus.

One of my little bug-bears about this setup is the way it handles users who're over quota. The typical Cyrus response is to (rightly) refuse to deliver the message, which results in Exim bouncing the message "local delivery failed". There are two problems here — we're immediately bouncing mail for what's likely to be an transient problem, and we're sending it back with an essentially useless error message.


I've been looking for a solution to this, albeit not very hard, for a while. Today David and I came up with a fairly neat one based on some ideas I'd read on the web. It's based on an Exim router that's checked at verify time.

We start with a Perl script that's run regularly (once an hour in our case) from cron. The purpose of this script is to work out which mailboxes are over quota and to write an lsearch type ACL file that lists these usernames. The value for each username is a :defer: rule that'll cause mail to be deferred.

Once we've got that running and successfully writing a data file we can use, we create an Exim router to check for over quota users. The router's a little special in that it's only used to verify time (meaning you need to verify recipients). The advantage of doing this check at verify time is that the defer happens before the SMTP session sends DATA. In other words, it's done before the bulk of the message is transferred. The :defer: keyword causes Exim to return a 451 error code, meaning that the remote MTA queues the message and retries later — queuing mail is not our problem ;-) The mail will hang around on the remote system until such time as it times out, after which a bounce message (containing a useful error message!) should be generated.

Our router for this looks something along these lines:

overquota_router:
   driver = redirect
   local_part_suffix_optional
   local_part_suffix = +imap
   domains = +local_domains
   data = ${lookup{${lc:$local_part}}lsearch{/usr/local/etc/exim/overquota.txt}}
   allow_defer
   verify_only

Some key points in this are verify_only, which ensures that the router is skipped during actual delivery, and allow_defer which allows the :defer: rule. The local_part_suffix* bits are peculiar to our setup and probably aren't necessary for others.

It's important that this router comes before the actual router that does Cyrus delivery (probably via Cyrus's deliver(8)) and answers for any domains that deliver into Cyrus.

You'll also need to ensure that you're verifying recipients in the acl_smtp_rcpt ACL section. A typical way of doing this is an ACL that looks like:

 accept domains = +local_domains
        endpass
        verify  = recipient
        message = No router would accept this message.

One last thing you need to do is turn on smtp_return_error_details. This'll ensure that the error message from the router is returned to the client (rather than "451 Temporary local problem - please try later").

Once you've done all this, test things using exim -bh before you go live. You should have an SMTP session that looks similar to the following (with the right values for your system):

220 imap.example.net ESMTP Exim 4.51 Thu, 13 Oct 2005 20:56:24 +0200
EHLO someone.example.net
250-imap.example.net Hello guy at someone.example.net [192.168.0.2]
250-SIZE 8388608
250-PIPELINING
250-STARTTLS
250 HELP
MAIL FROM:<guy@example.net>
250 OK
RCPT TO:<overquotauser@example.net>
451 The users mailbox is full. Please try re-sending your e-mail later.

You'll need to ensure that cron keeps your over quota lsearch list up-to-date. You'll also need to realise that there's a small delay between users going over quota and their being caught by this system (and again between when they drop below quota and when they drop out of this system). This delay depends on how often you update your quota ACL file and this, in turn, depends on how many users you have and how loaded your box is (the script does take a while to run on large systems).

I hope this recipe is useful to someone else. YMMV and all that.

posted by guy at: 22:05 SAST | path: /systems | permanent link

Bloxsom Powered

© 2002-2005, webmaster@mombe.org
 
 
RSS Valid XHTML 1.0!

Creative Commons License