Email Filtering – How to Filter and Deliver a Message in Procmail

emailprocmail

I rewrite the subject line for certain incoming mails depending on TO: field:

:0fhw
* ! ^TO_user@domain\.com\>
* ^TO_[^<>@ ]+@domain\.com\>
* ^Subject:\/.+
| /usr/local/bin/formail -I"Subject: [SPAM]$MATCH"

The above code (from my earlier question procmail rewrite subject line if email recipient user fails match test) works perfectly – if I get mail from something OTHER THAN [email protected], the subject line is rewritten as [SPAM] (original subject)

But I would like to do multiple conditionals like this – the working block, above, will be the final one, but before that, I'd like to rewrite the subject line if the TO matches a different address.

So I added this block just above it:

:0fh
* ^TO_special@domain\.com
* ^Subject:\/.+
| /usr/local/bin/formail -I"Subject: [SPECIAL]$MATCH"
$DEFAULT

… and this works – emails sent to '[email protected]' get their subject line rewritten.

The problem is, Procmail doesn't stop – it moves onto the next block and rewrites it again. So emails sent to [email protected] get their subject lines rewritten as:

[SPAM] [SPECIAL] Original subject line blah blah

Why is this? Why doesn't the $DEFAULT action at the end of the first block cause Procmail to halt processing for that piece of email?

How can I match the new block and stop processing that piece of mail and just be done with it?

Best Answer

The $DEFAULT at the end is a syntax error. You can't specify multiple actions on the same recipe.

What you can do is split it into two recipes; or, in this case, simply combine the rewriting and the delivery.

:0:
* ^TO_special@domain\.com
* ^Subject:\/.+
| /usr/local/bin/formail -I"Subject: [SPECIAL]$MATCH" >>$DEFAULT

This no longer has the fh flags because we want to push the whole message through (not just the headers, which h does) and we want to deliver, not capture the results of the pipeline back into Procmail (which f does).

This assumes that $DEFAULT is a file, not a directory; and thus we also add a second : to specify locking.

If you wanted to specify two actions under a single set of conditions, you can use braces with multiple recipes inside them. Each recipe can have zero or more conditions but only one action.

:0
* ^TO_special@domain\.com
* ^Subject:\/.+
{
    :0fhw
    | formail -I"Subject: [SPECIAL]$MATCH"

    :0:
    $DEFAULT
}

but in this case that's an unnecessary complication.

(It would perhaps also be more idiomatic to move the ^Subject: condition to the formail recipe where it logically belongs, but this is just a tangent anyhow.)

Also tangentially, perhaps make sure your PATH is correct right at the start of your .procmailrc so you can avoid spelling out the full path to external utilities like formail.