Qmail defines a complex but well-specified environment in which to run the programs specified in .qmail command lines. Each command is run under the user's user ID and primary group ID, in the user's home directory, via /bin/sh -c. The command's standard input is the message file, while the standard output and standard error are a pipe back to qmail-lspawn, which logs anything the command writes to its output. If the program fails (exit 100), its output is mailed back to the sender as part of the error report. The message file is guaranteed to be an actual file, so that programs can read the message, seek back to the beginning, and read it again. (This isn't very useful for individual programs, but it's quite useful for programs like condredirect that fork off a child program that reads and analyzes the message, then when the child is done, reprocess the message itself.) The program's environment variables are inherited from the qmail-start command that originally started qmail, with quite a few added variables to help manage the delivery:
Other than the translations of whitespace to underscores or dashes, there's no attempt to defend against strange or hostile characters in environment variables, so scripts should be sure to double-quote variable references and remember that hostile senders can put any characters they want, including punctuation and spaces, into a message's envelope. Programs called from .qmail files should be equally cautious if they use the environment variables either directly or as program arguments. For example, if a Perl script uses a subaddress to select a file to use, be sure it does something reasonable when a sender sends you a message where the subaddress is |rm -f. There is no provision for continuation lines in a .qmail file, so each command has to be on a single line. There's no limit to the length of that single line, so you can put arbitrarily complex shell commands in your .qmail file. In practice, if the shell script is more than about 100 characters, it's easier to put the script in a separate file and call the script file from the .qmail file. Any program run from .qmail files should run to completion and exit. If it forks and continues in the background, the results are unpredictable, because all program and mailbox deliveries from a .qmail file share the same input file descriptor, and the program's file reads are intermixed with those of other commands run from the same .qmail file. (qmail-local resets the seek pointer to the beginning of the file before each delivery.) Delivery programs should not take very long to complete. Qmail normally limits itself to 10 simultaneous local deliveries, so 10 long-running delivery programs lock out all other local deliveries. 10.3.1 Delivery UtilitiesQmail provides a small set of programs intended for use in deliveries. 10.3.1.1 forwardThe most useful of the programs is forward, which remails the input message to all of the addresses given on the command line, as though the addresses were each on a forward line in the .qmail file. This is useful both because forward can be embedded in shell scripts to be run conditionally and the addresses can be calculated at runtime. For example, to forward a message to a different address depending on what the day of the week is, type: | forward "day-$(date +%a)@example.com" Or to route mail from one sender specially, type: | case "$SENDER" in fred@domain.com) forward fredflame ;; *) forward inquiries ;; esac 10.3.1.2 bouncesayingBounce a message back to the sender either unconditionally or if a program succeeds. Most often, bouncesaying is used to turn off addresses that are no longer active: | bouncesaying "Sorry, this employee has left the company" It's occasionally useful as a simple mail filter: | bouncesaying "No tropical fruit, please" grep -q "guava|mango|papaya" ./Maildir/ This scans the message for forbidden words and bounces the message if the grep succeeds. Otherwise it delivers the message to the user's Maildir. Note that the -q flag keeps the grep command from producing unwanted output that would be mailed back with the bounce message. 10.3.1.3 condredirectConditionally remail a message to a different address. The arguments are the new address and a shell command to run. If the command succeeds and exits 0, the message is mailed to the new address, and condredirect exits 99, telling qmail to ignore any subsequent lines in the .qmail file. If the command exits 111, so does condredirect. If the command exits with any other code, condredirect exits 0: | condredirect subscriptions grep -q -i "Subject:.*subscribe" ./Maildir/ Except in the most simple applications, it's usually easier to use procmail. 10.3.1.4 exceptReverse the exit code of a program: | bouncesaying "Tropical fruit required here" except grep -q "guava|mango|papaya" ./Maildir/ The except command reverses the sense of the grep so the mail is bounced if the magic words don't appear in the message.[3]
|