Skip to content

dot qmail.5

Manvendra Bhangui edited this page Feb 25, 2024 · 9 revisions

NAME

dot-qmail - control the delivery of mail messages

DESCRIPTION

Normally the qmail-local program delivers each incoming message to your system Maildir, homedir**/Maildir/, where homedir is your Maildir directory. If you omit the slash, e.g. homedir/Mailbox**, it delivers it to your system mailbox file instead of Maildir.

It can instead write the mail to a different file or directory, forward it to another address, distribute it to a mailing list, or even execute programs, all under your control.

THE QMAIL FILE

To change qmail-local's behavior, set up a .qmail file in your home directory.

.qmail contains one or more lines. Each line is a delivery instruction. qmail-local follows each instruction in turn. There are five types of delivery instructions: (1) comment; (2) program; (3) forward; (4) mbox; (5) maildir; (6) branch;

(1)
A comment line begins with a number sign:

  # this is a comment

qmail-local ignores the line.

(2)
A program line begins with a vertical bar:

  |preline /usr/ucb/vacation djb

qmail-local takes the rest of the line as a command to supply to sh. See qmail-command(8) for further information. If the program line has filterit without the path, qmail-local will use it's internal filterit filter.

  |filterit ...

If program line has filterit with the path, qmail-local will execute filterit as an external command like any other program line.

  | /bin/filterit ...

(3)
A forward line begins with an ampersand:

     &me@new.job.com

qmail-local takes the rest of the line as a mail address; it uses qmail-queue to forward the message to that address. The address must contain a fully qualified domain name; it must not contain extra spaces, angle brackets, or comments:

  # the following examples are WRONG


  &me@new


  &<me@new.job.com>


  & me@new.job.com


  &me@new.job.com (New Address)

If the address begins with a letter or number, you may leave out the ampersand:

  me@new.job.com

Note that qmail-local omits its new Return-Path line when forwarding messages.

(4)
An mbox line begins with a slash or dot, and does not end with a slash:

  /home/djb/Mailbox.sos

qmail-local takes the entire line as a filename. It appends the mail message to that file, using flock -style file locking if possible. qmail-local stores the mail message in mbox format, as described in mbox(5) .

WARNING: On many systems, anyone who can read a file can flock it, and thus hold up qmail-local's delivery forever. Do not deliver mail to a publicly accessible file!

If qmail-local is able to lock the file, but has trouble writing to it (because, for example, the disk is full), it will truncate the file back to its original length. However, it cannot prevent mailbox corruption if the system crashes during delivery.

(5)
A maildir line begins with a slash or dot, and ends with a slash:

  /home/djb/Maildir/

qmail-local takes the entire line as the name of a directory in maildir format. It reliably stores the incoming message in that directory. See maildir(5) for more details.

(6)
A branch line begins with a question mark, and ends with a label

  ?label command arg ...
  ...
  :label

A .qmail file using this feature might look like:

  # Sort out mail from Sue.
  ?test [ "$SENDER" = sue@somewhere.org ] || exit 99
  /home/b1ff/mail/sue/
  # Skip all further processing.
  ?done
  :test

  # Is this a copy of a mailing list message?
  ?test iftocc `cat lists` || exit 99
  # Bounce this copy.
  |cat duplicate; exit 100
  :test

  # Deliver to the default mailbox.
  /home/b1ff/mail/main/

qmail-local will deliver the message to the command just as it does for a |command line, and if the command exits with status 99, qmail-local will skip down to the :label line; delivery instructions in the intervening lines are ignored. If the command exits with status other than 99, the result is the same as with a |command line (See qmail-command(8)). :label lines are otherwise ignored, just like #comment lines.

A label is a (possibly empty) sequence of non-space, non-tab, nonzero bytes. Text following a label on a ":" line is ignored. If there is no command on a ?label line, it's an unconditional jump. If a command exits 99 and the corresponding label is not found, all following delivery instructions are skipped (as with |command). There are no backward jumps.

This makes the .qmail language a little more useful, IMO, but not enough to cause trouble. (You get if-then-else, but no loops.) The syntax is a little ugly, but it gets the job done. The same functionality is already available with |command lines, but then you need multiple .qmail files, which exposes extra addresses to outside senders, so it gets a little more complicated.

(7)
A envdir line begins with a percent sign:

     % envdir_path

qmail-local takes the rest of the line as a directory with environment variables and sets/unsets environment variables like the envdir(8) command. An command executed using a command line in dot-qmail(5) will inherit these environment variables. You can also ensure that the commands run just with the environment variables from envdir_path by setting SANITIZE_ENV environment variable for qmail-local. If SANITIZE_ENV is enabled qmail-local will first clear all environment variables other than USE_FSYNC, USE_FDATASYNC, USE_SYNCDIR. You can set additional environment variables to preserve by setting SANITIZE_ENV as a colon ':' separated list of environment variables to preserve. The purpose of SANITIZE_ENV is to ensure programs run using dot-qmail(5) will run without any environment variable inherited from the startup scripts.

If .qmail has the execute bit set, it must not contain any program lines, mbox lines, or maildir lines. If qmail-local sees any such lines, it will stop and indicate a temporary failure.

If .qmail is completely empty (0 bytes long), or does not exist, qmail-local follows the defaultdelivery instructions set by your system administrator; normally defaultdelivery is ./Mailbox, so qmail-local appends the mail message to Mailbox in mbox format.

.qmail may contain extra spaces and tabs at the end of a line. Blank lines are allowed, but not for the first line of .qmail.

If .qmail is world-writable or group-writable, qmail-local stops and indicates a temporary failure.

SAFE QMAIL EDITING

Incoming messages can arrive at any moment. If you want to safely edit your .qmail file, first set the sticky bit on your home directory:

  chmod +t $HOME

qmail-local will temporarily defer delivery of any message to you if your home directory is sticky (or group-writable or other-writable, which should never happen). Make sure to

  chmod -t $HOME

when you are done! It's a good idea to test your new .qmail file as follows:

  qmail-local -n $USER ~ $USER '' '' '' '' ./Mailbox

EXTENSION ADDRESSES

In the qmail system, you control all local addresses of the form .IR user**-anything, as well as the address user itself, where user is your account name. Delivery to user-anything is controlled by the file homedir/.qmail**-anything.

(These rules may be changed by the system administrator; see qmail-users(5).)

The alias user controls all other addresses. Delivery to local is controlled by the file homedir/.qmail-local, where homedir is alias's home directory.

In the following description, qmail-local is handling a message addressed to local@domain, where local is controlled by .qmail-ext. Here is what it does.

If .qmail-ext is completely empty, qmail-local follows the defaultdelivery instructions set by your system administrator.

If .qmail-ext doesn't exist, qmail-local will try some default .qmail files. For example, if ext is foo-bar, qmail-local will try first .qmail-foo-bar, then .qmail-foo-default, and finally .qmail-default. If any of these default .qmail files exist, qmail-local will set the environment variable DEFAULT as the string "default". If none of these exist, qmail-local will bounce the message. (Exception: for the basic user address, qmail-local treats a nonexistent .qmail the same as an empty .qmail.)

WARNING: For security, qmail-local replaces any dots in ext with colons before checking .qmail-ext . For convenience, qmail-local converts any uppercase letters in ext to lowercase.

When qmail-local forwards a message as instructed in .qmail-ext (or .qmail-default ), it checks whether .qmail-ext**-owner** exists. If so, it uses local**-owner@**domain as the envelope sender for the forwarded message. Otherwise it retains the envelope sender of the original message. Exception: qmail-local always retains the original envelope sender if it is the empty address or #@[], i.e., if this is a bounce message. qmail-local sets the environment variable NEWSENDER to the envelope sender for the forwarded message.

qmail-local also supports variable envelope return paths (VERPs): if .qmail-ext**-owner** and .qmail-ext**-owner-default** both exist, it uses local**-owner-@domain-@[]** as the envelope sender. This will cause a recipient recip**@reciphost to see an envelope sender of local-owner-recip=reciphost@**domain.

ERROR HANDLING

If a delivery instruction fails, qmail-local stops immediately and reports failure. qmail-local handles forwarding after all other instructions, so any error in another type of delivery will prevent all forwarding.

If a program returns exit code 99, qmail-local ignores all succeeding lines in .qmail, but it still pays attention to previous forward lines.

To set up independent instructions, where a temporary or permanent failure in one instruction does not affect the others, move each instruction into a separate .qmail-ext file, and set up a central .qmail file that forwards to all of the .qmail-exts. Note that qmail-local can handle any number of forward lines simultaneously.

SEE ALSO

ifaddr(1), iftocc(1), iftoccfrom(1), condredirect(1), condtomaildir(1), filterto(1), except(1), bouncesaying(1), dot-forward(1), fastforward(1), forward(1), printforward(1), setforward(1), preline(1), qnotify(1), qreceipt(1), replier(1), rrforward(1), qmail-command(8), envelopes(5), maildir(5), mbox(5), qmail-users(5), qmail-local(8), qmail-queue(8), qmail-lspawn(8)

Clone this wiki locally