I run a two-computer system, one server/busybox, and one desktop. I use Dovecot IMAP for reading mail, and I have a server-side set of scripts sorting mail into specific mailboxes.

When new messages come in from legitimate people, I don't want to have to ssh into the server, just to update the procmail recipes with the new email addresses.

So, I decided to create a set of bash scripts that, when combined with cron, will automatically update the recipes list for me. All I need to do is move the new mail into the folder I ultimately want it to continue coming into.

And then, I thought, what the heck, maybe someone else might just like this too.

So, here y'all go, the WhiteDove Recipe Generator.

First script is auto-whitelist, which scans your maildirs for the first instance of "From:" in a message, and places it into a whitelist named after the maildir.

Code:

#!/bin/bash

# The WhiteDove Recipe Generator
# (C) 2006, Lampros Liontos, aka. "Reteo Varala"
# This program is licensed under the GNU GPL, version 2 or greater.

# A set of scripts to generate an automatically-updating whitelist using
# Dovecot and Procmail.

# Now, we need to make certain that the whitelist directory is clean. This should do nicely.
rm `find $WHITEDIR -type f`

for MAILDIR in $FOLDERS
do
# First thing's first, make certain a maildir is not being worked on
# by another process.
if [ -e $LOCK/`basename $MAILDIR` ];
then
# If the lock exists, skip the whole procedure, and move on to
# the next folder. Let's make certain that a notification is
# made, however.
echo "Skipping `basename $FOLDER`, as it is already in progress.";
else
# Create a lockfile so we can work on this folder in peace.
touch $LOCK/`basename $MAILDIR`;

# Because maildirs use three subdirs, we need to make certain
# that we don't miss anything. Also, since the actual mail
# messages use the hostname, that is a good way to tell an
# actual mailfile from a directory or an index file.
for MAILFILE in `find $MAILDIR/{cur,new,tmp} -type f `;
do
# We need to find the "From:" lines in the mailfiles,
# and pack them into a temporary file for processing.
# The -m 1 option prevents the reading of From: lines
# in attached messages.
grep -h -m 1 "^From:" $MAILFILE >> $TEMP/`basename $MAILDIR`;
done;

# We have one maildir tempfile prepared, now to process it.
# To do this, we need to do three things: sort it, eliminate
# all duplicates, and then write the final result
if [ -e $TEMP/`basename $MAILDIR` ];
then
# Okay, let's process the file.
cat $TEMP/`basename $MAILDIR` | sort | uniq > $WHITEDIR/`basename $MAILDIR`;
# Cleanliness is next to godliness.
rm $TEMP/`basename $MAILDIR`;
fi
# The file's made, the tempfile's gone, we're done. Let's
# unlock the whitefile, and move onto the next maildir.
rm $LOCK/`basename $MAILDIR`
fi
done;

Second script is the other half of the system, which reads all the whitelists generated by auto-whitelist, and then creates a procmail recipe file with every entry as its own recipe, outputting to the mailbox it originally came from.

This also creates a central procmail recipe file which includes all the created whitelist recipe files.

Code:

#!/bin/bash

# The WhiteDove Recipe Generator
# (C) 2006, Lampros Liontos, aka. "Reteo Varala"
# This program is licensed under the GNU GPL, version 2 or greater.

# A set of scripts to generate an automatically-updating whitelist using
# Dovecot and Procmail.

# procmail-generator: generates the procmail recipes from the whitelists
# created by auto-whitelist

# The following wildcard should flush out all directories. Since all
# maildirs start with a dot, and should have at least two characters, this
# should do for our needs.
for WHITEENTRY in $WHITEDIR/.??*;
do
# Strip the path, so we can process the filename as a whitelist.
WHITEFILE=`basename $WHITEENTRY`

# Now, this generates the include line in the include file.
echo "INCLUDERC=\$PMDIR/$INCLUDEDIR/rc$WHITEFILE" >> $PMDIR/$INCLUDEFILE;

# Now to generate the recipes, one per line in the whitelist file.
for LINE in `grep "From:" $WHITEENTRY`;
do
echo ":0" >> $PMDIR/$INCLUDEDIR/rc$WHITEFILE;
echo "* ^$LINE" >> $PMDIR/$INCLUDEDIR/rc$WHITEFILE;
echo "$WHITEFILE/" >> $PMDIR/$INCLUDEDIR/rc$WHITEFILE;

# The recipes need to be spaced apart by at least one line.
echo "" >> $PMDIR/$INCLUDEDIR/rc$WHITEFILE;
done;
done;

Hope someone finds these useful!

What you need to do is place these scripts in your binary directory, and set up cron to run the auto-whitelist first and the procmail-generator next. Finally, in your current .procmailrc, add the following:

Code:

INCLUDERC=${HOME}/${PMDIR}/${INCLUDEFILE}

Where ${HOME} is your home directory, ${PMDIR} is where you store your procmail scripts, and ${INCLUDEFILE} is the name of the file generated by the above script._________________Lampros Liontos (aka. Reteo Varala)

Linux Home Recording - Tips, tricks and techniques for setting up and using a recording studio with Linux.

Last edited by reteo on Thu Dec 14, 2006 9:07 pm; edited 2 times in total

Whenever a legitimate email address includes characters that have special meaning in regular expressions, it can match addresses other than the exact email address.

I am not certain how to fix this one perfectly, but I added some code to turn all regex-special symbols into the "match-one" symbol, the period.

First, we need to replace the following code in the procmail-generator script:

Code:

# Now to generate the recipes, one per line in the whitelist file.
for LINE in `grep "From:" $WHITEENTRY`;
do
echo ":0" >> $PMDIR/$INCLUDEDIR/rc$WHITEFILE;
echo "* ^$LINE" >> $PMDIR/$INCLUDEDIR/rc$WHITEFILE;
echo "$WHITEFILE/" >> $PMDIR/$INCLUDEDIR/rc$WHITEFILE;

# The recipes need to be spaced apart by at least one line.
echo "" >> $PMDIR/$INCLUDEDIR/rc$WHITEFILE;
done;

With the following code:

Code:

# Now to generate the recipes, one per line in the whitelist file.
for LINE in `grep "From:" $WHITEENTRY`;
do
# Let's get rid of regexp-command characters. The dot
# should suffice.
WORK=$LINE;
for i in '\\' '\[' '\^' '\$' '\|' '\?' '\*' '\+' '\(' '\)';
do
LINE2=`echo $WORK | tr $i '.'` ;
WORK=$LINE2 ;
done