Subject: Re: an action that reads the mail twice?

From: [email-masked] (David W. Tamkin)
Date: Sun, 10 Jul 1994 22:28:07 -0500 (CDT)

Scott Hammond wondered,

| Trying to learn procmail, I created what I thought was a
| quick and dirty mail reflector on one of my accounts:
|
| :hb
| * ^Subject: ztesting
| | (formail -rk -A"Precedence: junk"; `sed -e 's/^/>/'`; \
| 	 echo "Mail received") | $SENDMAIL -t
|
| What I wanted was to reply with the quoted header and body of the
| message that was received.

BTW, hb is the default; you need to use 'h' only when you don't want 'b' or
vice versa.  You can think of it this way: 'h' means "lose the body" and
'b' means "lose the header," but the two together cancel each other out.

| I assumed the above would work because the man page says something run with
| backquotes will have the _entire mail_ as its standard input.

The man page says that any program *started*by*procmail* will have the
entire text as its standard input.  The presence of characters in
$SHELLMETAS will make the shell run it instead.  Your second and third
guesses are on target:

| 2.  Backquotes don't really work that way.
| 3.  Since the action is running under shell, the rules are different
|     and I don't realize it.

Here's Scott's recipe again:

  :hb
  * ^Subject: ztesting
  | (formail -rk -A"Precedence: junk"; `sed -e 's/^/>/'`; \
  	 echo "Mail received") | $SENDMAIL -t

sed is invoked with no input, so it generates no output.  Thus `sed etc.`
is replaced by shell command substitution with NOTHING.  Frankly, you
wouldn't want sed to read the letter in, because then command substitution
would put the entire output of sed onto the command line and the shell would
try to read it all as commands!  Anyhow, now we have this as the action line:

  (formail -rk -A"Precedence: junk"; ; echo "Mail received") | $SENDMAIL -t

Now, what does formail -rk do?  It inverts the header into a response, adds
Re: to the subject (that's why there's no loop), and, for lack of the -b or
-p options, escapes the body with ">", which is exactly the same character
Scott was trying to introduce.  That makes it look as though sed added the
">", but actually formail did.  Add "Mail received" and feed it to
$SENDMAIL -t.

So what comes back to Scott?  A letter with the same body (only escaped
with ">") plus the words "Mail received", a precedence header, and the
subject "Re: ztesting".

So how should one write such a recipe?  We need to get the header in there
twice: once inverted to a reply and once as text.  Here's my suggestion:

  : # 'c' is implicit in assignment recipes
  * ^Subject: ztesting
  RETURNHEAD=| formail -r -A"Precedence: junk" # no k, loses body

   :A # 'hb' is the default
   | (echo "$RETURNHEAD"; sed 's/^/>/'; echo Mail received) | $SENDMAIL -t

Since sed is the only part of the pipe action that reads standard input,
the entire text is fed to sed, and sed prefixes it all.

It can also be written with braces instead of the 'A' flag:

  : # 'c' is implicit at the opening of a brace structure
  * ^Subject: ztesting
  {
   # Here is a case where a program in backquotes reads the entire message:
   RETURNHEAD=`formail -r -A"Precedence: junk"` # no k, loses body

   :0
   | (echo "$RETURNHEAD"; sed 's/^/>/'; echo Mail received) | $SENDMAIL -t
  }

David W. Tamkin  P. O. Box 3284  Skokie IL  60076-6284
[email-masked]   MCI Mail: 426-1818   +1 312 714 5610