.procmailrc Checker
Reads a personal ~/.procmailrc and says, recipe by recipe, what it
actually does with your mail.
A procmailrc is terse in a way that hides mistakes. :0 and
:0: differ by one character, and one of them corrupts an mbox folder
when two messages arrive at once. A folder name with a trailing slash is a maildir
and the same name without one is a single file. Conditions are handed to procmail's
own egrep, which is not PCRE — \d matches the letter d, and a
$VAR in a condition is an end-of-line anchor followed by some letters
unless you asked for substitution. And any recipe with no conditions that delivers
quietly ends the file: everything below it is dead.
So this checks the structure — flags, locking, braces, the one action line every recipe must have — and then writes each recipe back out in plain English, including the ones that can never run.
Everything runs in your browser. The file is never uploaded, and no request is made when you press Check.
Findings
Nothing yet.
Paste a .procmailrc above,
then press Check.
What it checks, and what it cannot
What a recipe is
A recipe is :0, then its flags, then optionally a second colon and a
lockfile name; then zero or more condition lines starting with *; then
exactly one action line. Most structural mistakes are a recipe that lost
its action line, or picked up an extra one.
The action decides where the mail goes, and its last character decides what kind
of destination it is. A name ending in / is a maildir and one ending
in /. is an MH folder; anything else is a single file in mbox format.
| pipes to a program, ! forwards to an address, and
{ opens a block of further recipes. Since no folder is ever looked at
on disk, a name that was meant to be a maildir and lost its slash cannot be told
apart from a deliberate mbox — which is why the outline says which one each recipe
is getting, in as many words.
Locking
Appending to an mbox file is not atomic, so two messages delivered at the same
moment can interleave and leave the folder unreadable. :0: takes a
lockfile for the duration and is what an mbox delivery wants. Writing into a
maildir creates a new file instead, which is already atomic, so a lock there is
just work. On a pipe or a forward there is no folder name for procmail to derive
the default lockfile name from — it uses the destination filename, or the one
after the first >> — so a bare :0: there has
nothing to work with and wants an explicit name.
The regex engine
Conditions go to procmail's own egrep. It has ^ $ . * + ? [ ] | ( )
and the backslash, plus procmail's own \<, \> and
\/ — and nothing else. There are no character-class escapes, so
\d is just a quoted d; no (?…) groups; no
lazy quantifiers; and no named character classes. Matching ignores case unless the
recipe carries the D flag.
Condition lines are also the one place comments do not work. procmailrc(5) puts it
plainly: those lines are fed to the internal egrep literally. So a
# in a condition is part of the pattern, and this tool leaves it
alone too — except when it is surrounded by spaces and looks like someone writing a
comment, which it will point out.
Left alone on purpose
INCLUDERC and SWITCHRC name other files, and nothing is
ever fetched, so their recipes are not read and the unreachable-recipe check can
only speak for what you pasted. No folder, program or address is checked for
existence. Nothing is rewritten and there is nothing to copy or download: the only
safe normalisation of a working mail filter is the one you make yourself.
Assumed
A per-user ~/.procmailrc. A system-wide /etc/procmailrc
runs as root with different defaults and is not what this checks.
Index of /t/procmail/
../ procmail.js 16-Sep-2026 06:37 53265