Using Procmail to Mark As Read

I've seen a couple of blog posts explaining how to mark Maildir messages as read with procmail. All of them point to a thread on the procmail mailing list as the source of this solution. However, all of them fail to make any kind of attempt at explaining whats going on. After some trial and error, I was able to learn what was happening. First the snippet of procmail code:

[sourcecode language="bash"]
:0
* conditions
{
foldername=whatever

:0c
.$foldername/ # stores in .$foldername/new/

:0
* LASTFOLDER ?? //[^/]+$
{ tail=$MATCH }

TRAP="mv $LASTFOLDER .$foldername/cur/$tail:2,S"

HOST
}
[/sourcecode]

OK, I'm some-what familiar with procmail, however this code was not very intuitive. Why does a copy of the message (:0c) get moved into $foldername? What is HOST and what does it do? I will attempt to explain:

* conditions
This can be whatever you want. In my case, my Blackberry forwards a copy of all sent email to my inbox so that I can store it in the sent folder for future reference. However, I don't want to see "new" messages in my sent folder. I want them to be moved there and marked as read. All messages coming from my Blackberry have a From address of [email protected], so my condition is ^From.*[email protected]. I make the assumption that I won't be emailing myself (I have a separate email account for that).

foldername=whatever
This is just storing the path to the folder we're going to work with. In my case, I'm using my sent folder: foldername=/home/raam/mail/sent

:0c
.$foldername/

This places a copy of the message in the /new directory. This confused me, since the point of this code was to mark messages as read. But I discovered this step was necessary for the next few lines to work.

:0
* LASTFOLDER ?? //[^/]+$
{ tail=$MATCH }

First, let's read what LASTFOLDER is according to the procmail documentation:

This variable is assigned to by procmail whenever it is delivering to a folder or program. It always contains the name of the last file (or program) procmail delivered to. If the last delivery was to several directory folders together then $LASTFOLDER will contain the hardlinked filenames as a space separated list.

OK, so in this case, LASTFOLDER would contain the full path to the email that was copied to $foldername in the previous step. I'm not entirely sure what the rest of the commands do, but they're necessary.

TRAP="mv $LASTFOLDER .$foldername/cur/$tail:2,S"
Deciphering the mv command is pretty simple. It moves the email that we copied to $foldername to the /cur/ directory and renames it to end with :2,S. Cool, that makes the email client see the message as read. But what is TRAP? Again, let's RTFM and find out what TRAP is used for:

When procmail terminates of its own accord and not because it received a signal, it will execute the contents of this variable. A copy of the mail can be read from stdin. Any output produced by this command will be appended to $LOGFILE. Possible uses for TRAP are: removal of temporary files, logging customised abstracts, etc.

Interesting. But the next line is even more interesting!

HOST
What on Earth could this do? Well to my surprise it is directly linked to TRAP. Since the contents of TRAP will be executed when procmail terminates, we need a way of terminating procmail (for this block anyway). We do this with HOST. Here is a good explanation from another mailing list thread:

Lacking an explicit "exit" command in procmailrc, "HOST" in procmail is
what "exit $EXITCODE" would be in a shell.

So there you have it. I had no idea there would be so much happening behind these few lines of procmail code, but I'm glad I took the time to learn!

HOWTO: Email Forwarding with Procmail using formail

Introduction
This was something I needed to do for Aerva and I spent quite awhile on it; a lot longer than I expected. I searched the web a million times looking for solutions and trying to get everything working properly. I decided to create this HOWTO in hopes that someone in the same situation won't have as much trouble.

Problem / Scenario
Reports from several computers are emailed to a single email address. Depending on which computer the report was sent from, I need to forward a copy of that email to a specific email address (the admin for that computer). The server receiving the email uses QMail as an MTA. I added the following line to the .qmail file for the email account (usually located in /var/qmail/mailnames/*domain*/*email-acct*/) to pass all incoming email along to procmail using the specified procmail config file: Continue reading