Running a script from procmail

Professional Software Engineering PSE-L at
Sat Sep 30 22:56:46 CEST 2006

At 06:28 2006-09-30 +0100, Steve A did say:

>- The fudging with awk is because I only keep a list of the user part of
>the addresses (as they're all to my own domain).

Ick.  Many of the simpler things one tries to accomplish with awk can be 
performed with sed instead, at a much lower processing cost.  However, as 
we'll see below, even the awk isn't necessary.

>- I've done some tests too, and the X-Original-To header is always
>written even if it's for multiple recipients, so that's handy too!

Then that's the case for _your_ mailhost.  Is this true for multiple 
_local_ recipients (i.e. at your mailhost, not the total number of 
addresses in To: or Cc:, which may be at OTHER domains)?

>- There is a possible slight anomoly in the log... (see after recipe),
>that makes me wonder if/how/why it might be testing the same condition

The verbose log output you posted does not indicate a double-exec.  There's 
one line saying it was executing the command, another saying there was a 
nonzero exit code, and yet another indicating the condition was evaluated 
as no match (because the condition could have been inverted).

>* ^X-Original-To: .*

If you're not going to be performing multiple recipes within the block 
below this, you can just merge this condition with the blacklist 
check.  Also, in regexp, if you want to interpret a DOT as a DOT, then it 
should be escaped.

>          :0
>          * $? formail -x"X-Original-To:" | \
>                  awk -F@ '{sub(/ /,\"\");print \$1}' | \
>                  fgrep -i -x -f $RCPT_BLACKLIST
>          blacklist

if you're writing to a file, you should use locking - add a ':' to the end 
of the flags line on this recipe.

So a first-pass simplification would look like:

* ^X-Original-To: .*@mydomain\.tld
* $? formail -x"X-Original-To:" | \
         awk -F@ '{sub(/ /,\"\");print \$1}' | \
         fgrep -i -x -f $RCPT_BLACKLIST

There's that whole awk thing, which can actually be avoided entirely (not 
even with a rewrite to sed) - as well as the formail call, which should 
REALLY simplify and speed things up (since you're making use of fewer 

* ^X-Original-To:[      ]*\/[^  ]*@mydomain\.tld
* MATCH ?? ^\/[^@]+
* $? fgrep -x -i "$MATCH" $RCPT_BLACKLIST

the conditions are evaluated in order, and if one should fail (like, there 
isn't a match on the X-Original-To:), then the recipe stops being 
processed, and the remaining conditions are not evaluated.  This allows you 
to do stuff like extract a match in the first condition, which is anchored 
on matching your domain as well, then in the second condition, match on the 
part up to, but not including the @ in that email address, and in the third 
grep the blacklist directly for that string, making the final condition 
based on whether the string is matched in the file or not.

Note that I started composing this before I saw Dallman's most recent 
contribution (which also suggests eliminating the formail/awk).  This 
remains an improvement over his very similar method because there's no need 
to pipe the match string from echo into formail, and this also brings in 
the outer domain condition.  Short of setting RCPT_BLACKLIST, the recipe 
above is the ENTIRETY of the recipe you need.

Comments from the gallery?

  Sean B. Straw / Professional Software Engineering

  Procmail disclaimer: <>
  Please DO NOT carbon me on list replies.  I'll get my copy from the list.

More information about the procmail mailing list