Making a vacation message with maildrop

(Note for RedHat based system users, e.g., Fedora and CentOS. RedHat based systems don't have a maildrop package. Although I've installed it from source without problems, Falko Timme has an excellent guide on using the various Courier packages, including maildrop, in RedHat based systems. He includes complete instructions for building your own rpm as well as offering his own precompiled rpm for Fedora 8.)

Although the vacation program exists (and its manpage is fairly clear) there are times when it doesn't work properly, or you wish to add little features that aren't available in the base program. It requires a $HOME/.forward file to be read, and some email combinations don't read a .forward file.

I thought this would be simple to get working, and now that I have done it, it is, but it took a bit of research to solve various problems.

At our company, we have sendmail running on an aging RedHat server. We were doing some reconfiguration, and the person primarily responsible for the server didn't have time to investigate why vacation didn't work out of the box. He asked me to set it up on a different machine.

We had another server running postifx. My preferred email combination is postfix for a box that is some sort of mailserver, getmail and maildrop. In this case, the O/S was FreeBSD, but this should work on most versions of Linux and BSD. My plan was to have the user account get mail from our mailserver (in this example, I will stretch my imagination and call it mail) and save it on the BSD box. The BSD box, using postfix, would send the vacation message back through our mailserver. Then, when the user returned from vacation, we'd briefly set their pop server to the BSD box, and let them get their stored mail. Therefore, rather than put messages in $HOME/Mail. we just set it for /var/mail/$USER.

(In most cases, one would simply leave the mail on the server, but with all the reconfiguring going on, we did it this way. It was a slightly unusual situation.)

I already had postfix running on the BSD box. Installing and configuring postfix for this box's needs was relatively simple. I wanted it to use maildrop as the delivery agent and send mail out through our mailserver. I got most of my information from the somewhat dated but still quite useful FreeBSD Diary site's article.

Postfix configuration can be an article in itself and one of these days, I'll probably make a page about it, but for the moment, I simply changed a few parameters, most of them described in the FreeBSD Diary article. During installation, one is given the option to have postfix replace sendmail in /etc/mailer.conf, which I did. (It can be done manually after installation, but it's easier to let the port's Makefile do it.)

I then used getmail to get the user's mail from the mailserver. For more information on configuring getmail see my getmail page. The user's .getmailrc file would look like this. (For this example, we'll call the user jsmith, with a password of 1234).

 

[options]
verbose = 0
delete = True

[retriever]
type = SimplePOP3Retriever
server = mail
username = jsmith 
password = 1234

[destination]
type = MDA_external
path = /usr/local/bin/maildrop
unixfrom = True

I then set up a cronjob for the user (again, see my getmail page) to grab mail from the mailserver every 4 hours.

For anyone in a similar situation, note the delete = True line. I could have made this false and left the mail on the usual mailserver, but again, this was an unusual case.

I wanted the user's mail to remain in /var/mail/jsmith so that when he got back from vacation, he could retrieve it from the BSD box. So, the next step was to setup maildrop for him. I cover this in far greater detail on my page about mutt, but briefly, I created a .mailfilter file in jsmith's home directory. It simply read

DEFAULT="/var/mail/jsmith"

This worked, mail would come in for him and go to /var/mail/jsmith.

If there had been no $HOME/.mailfilter file, the mail would have gone to /var/mail/jsmith anyway, but as I had other things to put in there, such as running it through spamassassin first I created the $HOME/.mailfilter file. Note that a $HOME/.mailfilter file should have permissions of 0600 or 0700, otherwise, it won't work, giving a warning that there shouldn't be group or world permissions on the file.

Next I set up qpopper. I installed it from ports, choosing the option of being able to run it in stand alone mode. I created an extremely simple script, qpopper.sh. As I will only need qpopper to run infrequently, I didn't put qpopper.sh in /usr/local/etc/rc.d, but just stuck it in /usr/local/bin/. Then, I can start and stop it at will, but it won't run every time the machine is started.

#!/bin/sh


case "$1" in

start) /usr/local/libexec/qpopper
;;

stop) killall qpopper 
;;

*) echo "Usage: $(basename $0) (start|stop)" >&2 
;;

esac

I copied /usr/local/etc/qpopper.conf.sample to /usr/local/etc/qpopper.conf. I was able to leave the defaults as they would serve my purpose.

At this point, I tested everything. I sent an email to jsmith@domain.com. I then went to the BSD box and got the email from the mailserver. I then started qpopper, and from a third machine, downloaded jsmith's email.

This setup was sufficient for storing mail on the BSD box, but it didn't send a vacation message. I hadn't realized that if one uses maildrop the $HOME/.forward file wouldn't be read.

It wasn't that difficult to have getmail feed messages directly to postifx (a bit more complex than with fetchmail, as, by design, getmail insists upon a destination) however, as mentioned, I wanted to use maildrop to do some other things. I tried it anyway, and ran into another problem.

The .forward file would send a copy of the message to the vacation program, and also keep a copy in /var/mail/ for the user. Postfix complained of a mail loop and would return the message.

A little research indicated that others have had this problem (but many others, including the creator of postfix, don't). There were a few recommended fixes, however, at this point, it seemed like less work to use a filter from man (7) maildropex designed to duplicate the vacation program using a .mailfilter rule.

The only things I had to change from the example were adding -I 'From $LOGNAME' and -t to $SENDMAIL. So, my filter rule looked like

cc $DEFAULT
xfilter "reformail -r -t -I 'From: $LOGNAME'"
/^To:.*/
getaddr{$MATCH}=~ /^.*/;
MATH=tolower${MATCH}
flock "vacation.lock" {
        `fgrep -iqx "$MATCH" vacation.lst 2>/dev/null || { \
                echo "$MATCH" >>vacation.lst ; \  
                exit 1 ; \
              } `
}
if ( $RETURNCODE == 0 )
        exit
to "| (cat - ; echo ''; cat ~/.vacation.msg) | $SENDMAIL -t" 

The maildropex man page gives a fairly good explanation of what's going on here. xfilter uses reformail to generate a header--the man page's example didn't have the -I $LOGNAME part, but if I left it out, the header generated by reformail gave a header of

User & <jsmith@localhost.domain.com>

Using the $LOGIN variable will give a From: of user@domain.com. In our case, we have several divisions, and most of the users don't have an address of domain.com, but have one of division.com. So, in most cases, I would change the reformail line to read

xfilter "reformail -r -t -I 'From: John Smith<jsmith@division.com>'"

This particular rule will create a list of people to whom it's sent .vacation.msg and not send it again. For our company, this is a good thing as customers might send many emails to a user while they're away, and this way, they don't get 30 vacation messages.

I also had to add the -t option to the $SENDMAIL command at the end, or I would get an error mesage. (The man page doesn't have the -t option, and I assume this changes with your MTA, but postfix, at least, requires it.)

In many cases, simply using the vacation (1) program will work. When it does, it's probably easier. However, with postfix, getmail and maildrop as your agents, this way works quite well and takes little time to create. It also makes it easy to do various other things. I've mentioned running messages through spamassassin, one can add other rules above the vacation rule to make sure that messages from a MAILER-DAEMON don't get an auto reply, etc. As maildrop stops processing rules once a match has been made, if you belong to various mailing-lists, you could also filter them before the vacation response rule, so that other mailing list members don't get one of those annoying vacation messages.

I want to thank Maxlor and Andre from the BSD nexus site's forums who gave helpful advice--Maxlor pointing out why $HOME/.forward wasn't getting read, and andre pointing out that it was reformail that was giving me those $USER & headers.