procmail
[Top] [All Lists]

Re: Recipe ordering.

1997-01-16 00:55:05
    > On Wed, 15 Jan 1997, Alan K. Stebbens wrote:
    > 
    > }     OLDCOMSAT=${COMSAT:-off}
    > }     COMSAT=off
    > } 
    > }     # Remove duplicate messages
    > }     :0 Wh: .msgid.lock
    > }     | formail -D 16384 .msgid.cache
    > } 
    > }     COMSAT=$OLDCOMSAT
    > }     OLDCOMSAT
    > 
    > At NETCOM, I've heard that the above recipe can cause lost mail
    > due to NETCOM re-queing mail. Is this true?

Requeing mail, by itself, will not cause lost mail.  Using "formail -D",
and then causing procmail to "soft-fail" the current mail message, which
causes the mail to be requeued will effectively lose the mail because
the next time the recipe processes the message, the same message-id will
already be cached, and "formail -D" will succeed, causing the mail to be
dropped. 

Once procmail recieves the mail, its disposition is up to the procmail
recipe author.  If the procmail author uses "formail -D" to avoid
duplicate mail, then caution must be taken if any delivery errors are
handled by using a "soft failure".

FYI, a "soft failure" is used when the procmail recipe is exited in
error, without having delivered the mail, and the '-t' option had been
passed to procmail (which is typical).  In this case, procmail will
requeue the mail, on the assumption that it will be processed on a
later pass over the mail queue.

Also, some procmail authors will set EXITCODE=75 HOST explicitly,
forcing a soft failure, regardless of '-t'.  (75 is the value of
EX_TEMPFAIL, from "/usr/include/sysexits.h".  Here's an example:

    :0 Wh: .msgid.lock
    | formail -D 16384 .msgid.cache

    ... # other recipes

    :0:
    $DEFAULT
    :0e                         # did a write error occur?
    { EXITCODE=75 HOST }        # force a requeue, until we fix the drive

This recipe will lose mail when write errors occur on $DEFAULT, because
the requeued mail will never make it past the "formail -D" a second time
(unless the .msgid.cache file was also lost when the drive went bad :^).

If you wish to have this kind of fail-safe mechanism (ie: requeuing on
error), and also avoid duplicates, you must take extra pains.  Here's
one way:

    :0 Wh: .msgid.lock
    | formail -D 16384.msgid.cache

    ... # other recipes

    :0:         # or any other filing recipe
    $DEFAULT

    :0e         # an error?
    { JUNK=`rm -f .msgid.cache` # clear the cache
      EXITCODE=75 HOST  # then soft-fail the current mail
    }

Removing the cache is not harmful -- the worst is that you may receive a
few incoming duplicates, which had already been cached.  But, you should
not lose any mail from using "formail -D".

Another way to accomplish the same thing for any exit case is to set
"TRAP", well before any possible failure cases, but after having already
filtered the mail through "formail -D":

    # Remove duplicate mail
    :0 Wh: .msgid.lock
    | formail -D 16384.msgid.cache

    # Cause the .msgid.cache file to go away iff a soft-failure occurs
    TRAP='test "$EXITCODE" -eq 75 && rm -f .msgid.cache'

    ... # other recipes

BTW, using "formail -D" and failing to consider its effects is only one
of many scenarios in which it may be possible to lose mail.

The easiest way to lose mail is to have a bad recipe.  For example:

    SPAMMAIL="^Subject: (FREE|EASY) *MONEY"
    :0
    * $ $SPANMAIL
    /dev/null

In the recipe above, the author defined a variable named SPAMMAIL, but
misspelled it on the condition line, causing a blank condition, which
always matches, causing all mail to go into the bit bucket.  In other
words, mail is lost.

___________________________________________________________
Alan Stebbens <aks(_at_)sgi(_dot_)com>      http://reality.sgi.com/aks

<Prev in Thread] Current Thread [Next in Thread>