NAME postoffice - process mail messages SYNOPSIS postoffice DESCRIPTION postoffice is an "asynchronous" mail processor; that is, it looks for files in a directory, processes each file in turn, then looks for more files. It is specifically not intended to be invoked for every message that is received; instead, something like procmail(1) is used to deposit messages into a directory, then postoffice is run as a cron(1) job to process a batch of messages. By itself, postoffice is just a "wrapper" program that reads and parses a configuration file then invokes a "worker" program to process messages. The main reason for two scripts is locking: postoffice uses a socket (listening on a TCP port) to prevent multiple instances from running. However, the actual processing of messages was easier to do in shell, hence the worker script (see below). A side benefit of a separate message processor is that the user can specify an alternate program (if desired). CONFIGURATION FILE postoffice reads its configuration from $HOME/.postoffice. Blank lines and lines that start with "#" are skipped; however, inline comments are not permitted. All other lines are expected to be in the form: keyword = value The accepted values for *keyword* are listed below. *value* is expected to be one or more non-blank characters; anything after the first "word" after the equal sign ("=") will be ignored, and quoting is not recognized. The following keywords are understood: *inbox* [default: $HOME/inbox] Where postoffice looks for incoming messages. Must be a *maildir*, and must exist before postoffice runs. *logdir* [default: $HOME/mail/postoffice] Where postoffice will put log files; will be created if it doesn't exist. Before creating the default log direcory, postoffice will look for the following directories in $HOME: log/postoffice, mail/postoffice, mail/log/postoffice, Mail/postoffice, Mail/log/postoffice, and will use whichever directory is found first (in the order shown). See LOGGING below for more details. *logfile* [default: /postoffice..log] Over-rides the default log file; see LOGGING below for more details. *outbox* [default: $HOME/mail] Where postoffice will put messages after processing; will be created if it doesn't exist. *port* [default: UID + 50,000] The TCP port postoffice will use for locking, to prevent multiple instances of postoffice from running simultaneously. *tmpdir* [default: $HOME] Where postoffice will create temporary files. These files should be removed when postoffice exits or aborts, but it wouldn't hurt to check for (and purge) left-over files. Before using the default temp directory, postoffice will look for (and use, if found) $HOME/tmp/postoffice then $HOME/tmp. *worker* [default: /opt/postoffice/bin/postalworker] The program invoked by postoffice to process messages. See WORKER PROGRAM below for details. WORKER PROGRAM postoffice invokes the worker program with four arguments: *logdir*, *tmpdir*, *inbox*, and *outbox*; postoffice expects the worker program to exit with zero (0) for success, or a positive (short) integer on failure. The exit code is reported to the user but no meaning (beyond failure) is attached to a non-zero exit code. The worker program should create its own log file (preferrably in *logdir*). There is no other communication between postoffice and the worker program. Furthermore, postoffice will always invoke the worker program; it is up to the worker program to decide if there is any work to be done. Worker Plug-in The default worker program (/opt/postoffice/bin/postalworker, a bash(1) script) looks for messages in *inbox*, and for each message counts the lines in the message body and inserts this into a "Lines:" header, adds a "X-Processed-By:" header, then runs everything through spamassassin. The processed message is then "delivered" into *outbox* according to standard maildir rules. Finally, the message in *inbox* is deleted. When all messages have been processed, postalworker will sleep for a short period (currently 15 seconds) then look for more messages; this cycle will repeat five times then postalworker will exit. Any errors will cause postalworker to abort; every effort is made to leave messages in a sensible state. postalworker also includes a simple plug-in mechanism: If the file $HOME/libexec/postalworker exists, postalworker will "source" that file (using the "dot" operator) before invoking "main()". There are four environment variables that can be set by the plug-in to modify execution within postalworker: "f__mainInit()", "f__workerInit()", "f__processInit()", and "f__processFinal()". The values (if set) are expected to be the names of additional functions to be executed within postalworker. The execution and calling sequences work as follows: "f__mainInit()" called in "main()" just before "worker()" is invoked; called with the same command-line args as postalworker (see above); at this point, only *logdir* is guaranteed to exist; no output is permitted "f__workerInit()" called in "worker()" just before changing directories to *inbox/new*; called with the same command-line args as postalworker; all directories are guaranteed to exist; no output is permitted "f__processInit()" called in "processMessage()" before anything else is done; the command-line arguments are *message*, *tmpdir*, and *outbox*; no output is permitted "f__processFinal()" called in "processMessage()" after the message has been processes and delivered into *outbox* but before the message has been deleted from *inbox* (which actually happens in "worker()"); the command-line arguments are *message*, *tmpdir*, *outbox*, and *newmessage* (where the processed message was stored); must print the full path of *newmessage* on stdout (even if *newmessage* is unchanged) A sample plug-in is supplied, but you'll need to read the postalworker source code to see what functions are available, how to do logging, etc. OPTIONS None. LOGGING By default, both postoffice and the worker program will write their log files in the log directory (see *logdir* above). To over-ride this, use *logfile* to specify the full path for the log file to be written by postoffice and *logdir* to specify the directory where the worker program will create its log file. There is no way to specify the full path of the log file that will be written by the worker program. FILES $HOME/.postoffice the configuration file .../postoffice..log postoffice log file, one per day; because lines from multiple instances may be intermingled, each line contains the PID .../postalworker..log worker program log file, one per instance; ("UUUUUU" is microseconds) /opt/postoffice/libexec/postoffice the sample worker program plug-in EXIT STATUS postoffice returns 0 on success, 1 if an error occurs. CAVEATS postoffice processes mail messages, and is intended to be run via cron(1); cron(1) sends errors via email. You are strongly encouraged to use something like procmail(1), and to configure it to deliver messages from cron(1) in such a way that they are not processed by postoffice. AUTHOR Adam Moskowitz, COPYRIGHT Copyright, 2009, Adam Moskowitz. All rights reserved. Any redistribution of this software must retain the above copyright notice, this list of conditions, and the following disclaimer. Without specific prior written permission from the copyright holder, you may not charge a fee for the redistribution of this software. All other redistribution and use is hereby permitted. This software is provided "as is" and without any express or implied warranties, including, without limitation, the implied warranties of merchantability and fitness for a particular purpose.