I want to change subject for all subscription list emails by adding [BULK] to its. Looks like global /etc/procmailrc file is the best place to do it. But this filter also drops all headers for some emails (my changes separated by dashes):

VIRTUALMIN=|/etc/webmin/virtual-server/lookup-domain.pl --exitcode 73 $LOGNAME
* ?/bin/test "$EXITCODE" = "73"
* ?/bin/test "$VIRTUALMIN" != ""
* ^List-Unsubscribe:.*
   :0 hw
   SUBJECT=| formail -xSubject:

   :0 hfw
   * ^List-Unsubscribe:.*
   | /usr/bin/formail -i "Subject: [BULKMAIL] $SUBJECT"

Individual .procmailrc in user home dir rules with this code works perfect but its hard to manage.


1 Answer 1


I am unable to reproduce your problem, and you are not posting any diagnostics, but I can suggest a different recipe which might avoid a couple of possible error conditions.

There is no reason to repeat the List-Unsubscribe: conditions inside the braces -- if you are inside the braces, you know it matched.

The convention to hard-code the path to formail seems clunky (and you fail to do that in one of the places where you call it) but if Procmail gets invoked with a really wonky PATH that could be a reason you see failure when you don't specify fully the path /usr/bin/formail.

Anyway, you want to avoid external processes as far as possible. Procmail can extract the Subject: header into MATCH and then you just need a single formail invocation for the entire recipe to succeed.

:0 hfw
* ^List-Unsubscribe:
* ^Subject:\/.+
| /usr/bin/formail -i "Subject: [BULKMAIL]$MATCH"

The special operator \/ causes Procmail to collect the matching string into the variable MATCH, and we then use that instead of the external formail -xSubject: you were running. This is hardly a crucial change, but should be more efficient, as well as easier to read and debug.

(The trailing wildcard .* is superfluous in the first regex; Procmail is satisfied if a match is found anywhere in a line.)

You can test from the command line (but this of course requires that your recipe file doesn't override DEFAULT):

root@vbvntv-docker:/# procmail DEFAULT=/dev/null VERBOSE=yes </tmp/nst.eml
procmail: [937] Thu Dec  1 06:57:20 2016
procmail: Rcfile: "/etc/procmailrc"
procmail: Assigning "PATH=/usr/local/bin:/usr/bin:/bin"
procmail: Match on "^List-Unsubscribe:"
procmail: Assigning "MATCH="
procmail: Matched " testing"
procmail: Match on "^Subject:\/.+"
procmail: Executing " /usr/bin/formail -i "Subject: [BULKMAIL]$MATCH""
procmail: Assigning "PATH=/root/bin:/usr/local/bin:/usr/bin:/bin"
procmail: Assigning "LASTFOLDER=/dev/null"
procmail: Opening "/dev/null"
procmail: Notified comsat: "root@0:/dev/null"
From foo@bar  Thu Dec  1 06:57:20 2016
 Subject: [BULKMAIL] testing
  Folder: /dev/null                             133

If you still can't get this to work, updating your question with a similar transcript whould be most helpful. Further troubleshooting tips can be found e.g. at http://www.iki.fi/era/mail/procmail-debug.html

Once you are satisfied that your code works, maybe you'll want to prefer formail -I over formail -i which leaves the now rather useless Old-Subject: in the headers.

(Your prose description says BULK but the code says BULKMAIL. It is obviously easy to change if your code was wrong.)

The Webmin stuff is truly atrocious but apparently it's not your own code. Somebody should supply the Webmin folks with a hint that Procmail contains a regex engine, so calling /bin/test to compare two strings is really, really inefficient and generally horrendous.

  • Very helpful. Also to inspect the final result DEFAULT can point to a temporary path and if non-existent just gets created as a .mbox
    – BaseZen
    Jun 16, 2021 at 19:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.