> 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