Go to the first, previous, next, last section, table of contents.


15. The appendfile transport

The appendfile transport delivers a message by appending it to a file in the local file system, or by creating an entirely new file in a specified directory. Single files to which messages are appended can be in the traditional Unix mailbox format, or optionally in the MBX format supported by the Pine MUA and University of Washington IMAP daemon, inter alia. When each message is being delivered as a separate file, `maildir' format can optionally be used to give added protection against failures that happen part-way through the delivery. A third form of separate-file delivery known as `mailstore' is also supported. For all file formats, Exim attempts to create as many levels of directory as necessary, provided that create_directory is set.

The code for the optional formats is not included in the Exim binary by default. It is necessary to set SUPPORT_MBX, SUPPORT_MAILDIR and/or SUPPORT_MAILSTORE in `Local/Makefile' to have the appropriate code included.

Appendfile can be used by routers as a pseudo-remote transport for putting messages into files for remote delivery by some means other than Exim, though it is more commonly used by directors for local deliveries to users' mailboxes. It is also used for delivering messages to files or directories whose names are obtained directly from alias, forwarding, or filtering operations. In these cases, $local_part contains the local part that was aliased or forwarded, while $address_file contains the name of the file or directory.

As appendfile is a local transport, it is always run in a separate process, under a non-privileged uid and gid, which are set by setuid(). In the common local delivery case, these are the uid and gid belonging to the user to whom the mail is being delivered. The current directory is also normally set to the user's home directory. See chapter 13 for a discussion of the local delivery environment.

If the transport fails for any reason, the message remains on the input queue so that there can be another delivery attempt later. If there is an error while appending to a file (for example, quota exceeded or partition filled), Exim attempts to reset the file's length and last modification time back to what they were before. Exim supports a local quota, for use when the system facility is unavailable or cannot be used for some reason.

Before appending to a file, a number of security checks are made, and the file is locked. A detailed description is given below, after the list of private options.

15.1 Private options for appendfile

allow_fifo (appendfile)

Type: boolean
Default: false

Setting this option permits delivery to named pipes (FIFOs) as well as to regular files. If no process is reading the named pipe at delivery time, the delivery is deferred.

allow_symlink (appendfile)

Type: boolean
Default: false

By default, appendfile will not deliver if the path name for the file is that of a symbolic link. Setting this option relaxes that constraint, but there are security issues involved in the use of symbolic links. Be sure you know what you are doing if you set this. Details of exactly what this option affects are included in the discussion which follows this list of options.

batch (appendfile)

Type: string
Default: "none"

Normally, each address that is directed or routed to an appendfile transport is handled separately. In special cases it may be desirable to handle several addresses at once, for example, when passing a message with several addresses to a different mail regime (for example, UUCP), though this is more often done using the pipe transport. If this option is set to the string `domain', all addresses with the same domain that are directed or routed to the transport are handled in a single delivery. If it is set to `all' then multiple domains are batched. The list of addresses is included in the Envelope-to: header if the generic envelope_to_add option is set. When more than one address is being delivered, $local_part is not set, and $domain is set only if they all have the same domain. The only difference between this option and bsmtp is the inclusion of SMTP command lines in the output for bsmtp, and the escaping of lines that begin with a full stop (period).

batch_max (appendfile)

Type: integer
Default: 100

This limits the number of addresses that can be handled in a batch, and applies to both the batch and the bsmtp options.

bsmtp (appendfile)

Type: string
Default: "none"

This option is used to set up an appendfile transport as a pseudo-remote transport for delivering messages into local files in batch SMTP format for onward transmission by some non-Exim means. It is usually necessary to suppress the default settings of the prefix and suffix options when using batch SMTP. The check_string and escape_string options are forced to the values

check_string = "."
escape_string = ".."

when batched SMTP is in use. The value of bsmtp must be one of the strings `none', `one', `domain', or `all'. The first of these turns the feature off. A full description of the batch SMTP mechanism is given in section 48.8. When bstmp is set, the batch option automatically takes the same value. See also the use_crlf option.

bsmtp_helo (appendfile)

Type: boolean
Default: false

When this option is set, a HELO line is added to the output at the start of each message written in batch SMTP format. Some software that reads batch SMTP is unhappy without this.

check_group (appendfile)

Type: boolean
Default: false

The group owner of the file is checked to see that it is the same as the group under which the delivery process is running when this option is set. The default setting is false because the default file mode is 0600, which means that the group is irrelevant.

check_owner (appendfile)

Type: boolean
Default: true

The owner of the file is checked to ensure that it is the same as the user under which the delivery process is running when this option is set.

check_string (appendfile)

Type: string
Default: "From "

As appendfile writes the message, the start of each line is tested for matching check_string, and if it does, the initial matching characters are replaced by the contents of escape_string. The value of check_string is a literal string, not a regular expression, and the case of any letters it contains is significant. For backwards compatibility, if no_from_hack is specified, the values of check_string and escape_string are forced to be unset.

The default settings, along with prefix and suffix, are suitable for traditional `BSD' mailboxes, where a line beginning with `From ' indicates the start of a new message. All four options need changing if another format is used. For example, to deliver to mailboxes in MMDF format:

check_string = "\1\1\1\1\n"
escape_string = "\1\1\1\1 \n"
prefix = "\1\1\1\1\n"
suffix = "\1\1\1\1\n"

When the bsmtp option is set, the contents of check_string and escape_string are forced to values that implement the SMTP escaping protocol. Any settings made in the configuration file are ignored.

create_directory (appendfile)

Type: boolean
Default: true

When this option is true, Exim creates any missing superior directories for the file that it is about to write. A created directory's mode is given by the directory_mode option.

create_file (appendfile)

Type: string
Default: "anywhere"

This option constrains the location of files that are created by this transport. It must be set to one of the words `anywhere', `inhome', or `belowhome'. In the second and third cases, a home directory must have been set up for the address by the director that handled it. This option isn't useful when an explicit file name is given for normal mailbox deliveries; it is intended for the case when file names have been generated from user's `.forward' files, which are usually handled by an appendfile transport called address_file. See also file_must_exist.

current_directory (appendfile)

Type: string, expanded
Default: unset

If this option is set, it specifies the directory to make current when running the delivery process. The string is expanded at the time the transport is run. See chapter 13 for details of the local delivery environment.

directory (appendfile)

Type: string, expanded
Default: unset

This option is mutually exclusive with the file option. When it is set, the string is expanded, and the message is delivered into a new file or files in or below the given directory, instead of being appended to a single mailbox file. A number of different formats are provided (see maildir_format and mailstore_format), and see section 15.3 for further details of this form of delivery.

directory_mode (appendfile)

Type: octal integer
Default: 0700

If appendfile creates any directories as a result of the create_directory option, their mode is specified by this option.

escape_string (appendfile)

Type: string
Default: ">From "

See check_string above.

file (appendfile)

Type: string, expanded
Default: unset

This option is mutually exclusive with the directory option. It need not be set when appendfile is being used to deliver to files whose names are obtained from forwarding, filtering, or aliasing address expansions (by default under the instance name address_file), as in those cases the file name is associated with the address. Otherwise, the file option must be set unless the directory option is set. Either use_fcntl_lock or use_lockfile (or both) must be set with file. If you are using more than one host to deliver over NFS into the same mailboxes, you should always use lock files.

The string value is expanded for each delivery, and must yield an absolute path. The most common settings of this option are variations on one of these examples:

file = /var/spool/mail/$local_part
file = /home/$local_part/inbox
file = $home/inbox

In the first example, all deliveries are done into the same directory. If Exim is configured to use lock files (see use_lockfile below) it must be able to create a file in the directory, so the `sticky' bit must be turned on for deliveries to be possible, or alternatively the group option can be used to run the delivery under a group id which has write access to the directory.

If there is no file name, or the expansion fails, or a local part contains a forward slash character, a delivery error occurs.

file_format (appendfile)

Type: string
Default: unset

This option requests the transport to check the format of an existing file before adding to it. The check consists of matching a specific string at the start of the file. A list of check strings may be given, and associated with each is the the name of a transport. If the transport associated with a matched string is not the current transport, control is passed over to the other transport. There should always be an even number of items in a file_format setting. For example, if the standard local_delivery transport has this added to it:

file_format = "From       : local_delivery :\
               \1\1\1\1\n : local_mmdf_delivery"

then mailboxes that begin with `From' are handled by this transport, but if a mailbox begins with four binary ones followed by a newline, control is passed to a transport called local_mmdf_delivery which presumably is configured to do the delivery in MMDF format. If a mailbox does not exist or is empty, it is assumed to match the current transport. If the start of a mailbox doesn't match any string, or if the transport named for a given string is not defined, delivery is deferred.

file_must_exist (appendfile)

Type: boolean
Default: false

If this option is true, the file specified by the file option must exist, and an error occurs if it does not. Otherwise, it is created if it does not exist.

from_hack (appendfile)

Type: boolean
Default: true

This option is obsolete and is retained only for backwards compatibility. It has been replaced by check_string and escape_string. If it is explicitly unset (that is, if no_from_hack is specified), it causes both the new options to be unset. Otherwise it is ignored.

group (appendfile)

Type: string
Default: unset

If this option is set, it specifies the group under whose gid the delivery process is to be run, and, if check_group is set, the group owner of an existing file to which the message is to be appended. If the option is not set, a value associated with a user may be used (see below); otherwise a value must have been associated with the address by the director which handled it. If the string contains no $ characters, it is resolved when Exim starts up. Otherwise, the string is expanded at the time the transport is run, and must yield either a digit string or a name which can be looked up using getgrnam().

The group option is commonly set for local deliveries on systems where the set of user mailboxes is in a single directory owned by a group such as `mail'. Note that it should not be set on the instance of appendfile that is used for deliveries to files specified by users in their forward files (called address_file in the default configuration), because such deliveries should take place under the individual users' personal uids and gids.

lock_fcntl_timeout (appendfile)

Type: time
Default: 0s

By default, the appendfile transport uses non-blocking calls to fcntl() when locking an open mailbox file. If the call fails, it sleeps for lock_interval and tries again, up to lock_retries times. Non-blocking calls are used so that the file is not kept open during the wait for the lock; the reason for this is to make it as safe as possible for deliveries over NFS in the case when processes might be accessing an NFS mailbox without using a lock file. This should not be done, but misunderstandings and hence misconfigurations are not unknown.

On a busy system, however, the performance of a non-blocking lock approach is not as good as using a blocking lock with a timeout. In this case, the waiting is done inside the system call, and Exim's delivery process acquires the lock and can proceed as soon as the previous lock holder releases it.

If lock_fcntl_timeout is set to a non-zero time, blocking locks, with that timeout, are used. There may still be some retrying: the maximum number of retries is

(lock_retries * lock_interval) / lock_fcntl_timeout

rounded up to the next whole number. In other words, the total time during which appendfile is trying to get a lock is roughly the same, unless lock_fcntl_timeout is set very large.

You should consider setting this option if you are getting a lot of delayed local deliveries because of errors of the form

failed to lock mailbox /some/file (fcntl)

lock_interval (appendfile)

Type: time
Default: 3s

This specifies the time to wait between attempts to lock the file. See below for details of locking.

lock_retries (appendfile)

Type: integer
Default: 10

This specifies the maximum number of attempts to lock the file. A value of zero is treated as 1. See below for details of locking.

lockfile_mode (appendfile)

Type: octal integer
Default: 0600

This specifies the mode of the created lock file, when a lock file is being used (see use_lockfile).

lockfile_timeout (appendfile)

Type: time
Default: 30m

When a lock file is being used (see use_lockfile), if a lock file already exists and is older than this value, it is assumed to have been left behind by accident, and Exim attempts to remove it.

maildir_format (appendfile)

Type: boolean
Default: false

If this option is set with the directory option, the delivery is into a new file in the `maildir' format that is used by some other mail software. The option is available only if SUPPORT_MAILDIR is present in `Local/Makefile'. See section 15.3 below for further details.

maildir_retries (appendfile)

Type: integer
Default: 10

This option specifies the number of times to retry when writing a file in `maildir' format. See section 15.3 below.

maildir_tag (appendfile)

Type: string, expanded
Default: unset

This option applies only to deliveries in maildir format, and is described in section 15.3 below.

mailstore_format (appendfile)

Type: boolean
Default: false

If this option is set with the directory option, the delivery is into two new files in `mailstore' format. The option is available only if SUPPORT_MAILSTORE is present in `Local/Makefile'. See section 15.3 below for further details.

mailstore_prefix (appendfile)

Type: string, expanded
Default: unset

This option applies only to deliveries in mailstore format, and is described in section 15.3 below.

mailstore_suffix (appendfile)

Type: string, expanded
Default: unset

This option applies only to deliveries in mailstore format, and is described in section 15.3 below.

mbx_format (appendfile)

Type: boolean
Default: false

This option is available only if Exim has been compiled with SUPPORT_MBX set in `Local/Makefile'. If mbx_format is set with the file option, the message is appended to the mailbox file in MBX format instead of traditional Unix format. This format is supported by Pine4 and its associated IMAP and POP daemons, and is implemented by the c-client library that they all use. The prefix and suffix options are not automatically changed by the use of mbx_format; they should normally be set empty.

If none of the locking options are mentioned in the configuration, use_mbx_lock is assumed and the other locking options default to false. It is possible to specify the other kinds of locking with mbx_format, but use_fcntl_lock and use_mbx_lock are mutually exclusive. MBX locking inter~works with c-client, providing for shared access to the mailbox. It should not be used if any program that does not use this form of locking is going to access the mailbox, nor should it be used if the mailbox file is NFS mounted, because it works only when the mailbox is accessed from a single host.

If you set use_fcntl_lock with an MBX-format mailbox, you cannot use the standard version of c-client, because as long as it has a mailbox open (this means for the whole of a Pine or IMAP session), Exim will not be able to append messages to it.

mode (appendfile)

Type: octal integer
Default: 0600

If the output file is created, it is given this mode. If it already exists and has wider permissions, they are reduced to this mode. If it has narrower permissions, an error occurs unless mode_fail_narrower is false. However, if the delivery is the result of a save command in a filter file specifing a particular mode, the mode of the output file is always forced to take that value, and this option is ignored.

mode_fail_narrower (appendfile)

Type: boolean
Default: true

This option applies in the case when an existing mailbox file has a narrower mode than that specified by the mode option. If mode_fail_narrower is true, the delivery is frozen (`mailbox has the wrong mode'); otherwise Exim continues with the delivery attempt, using the existing mode of the file.

notify_comsat (appendfile)

Type: boolean
Default: false

If this option is true, the comsat daemon is notified after every successful delivery to a user mailbox. This is the daemon that notifies logged on users about incoming mail.

prefix (appendfile)

Type: string, expanded
Default: see below

The string specified here is expanded and output at the start of every message. The default is

prefix = "From ${if def:return_path{$return_path}{MAILER-DAEMON}}\
  ${tod_bsdinbox}\n"

This line can be suppressed by setting

prefix =

and this is usually necessary when doing batch SMTP deliveries, or delivering into individual files or MBX-format mailboxes.

quota (appendfile)

Type: string, expanded
Default: unset

This option imposes a limit on the size of the file to which Exim is appending, or to the total space used in the directory tree if the directory option is set. In the latter case, computation of the space used is expensive, as all the files in the directory (and any sub-directories) have to be individually inspected and their sizes summed (but see quota_size_regex below). Also, there is no interlock against two simultaneous deliveries into a multi-file mailbox. For single-file mailboxes, of course, an interlock is a necessity.

A file's size is take as its used value. Because of blocking effects, this may be a lot less than the actual amount of disc space allocated to the file. If the sizes of a number of files are being added up, the rounding effect can become quite noticeable, especially on systems that have large block sizes. Nevertheless, it seems best to stick to the used figure, because this is the obvious value which users will understand most easily.

The value of the option is expanded, and must then be a numerical value (decimal point allowed), optionally followed by one of the letters K or M. The expansion happens while Exim is running as root or the Exim user, before setuid() is called for the delivery, so files that are inaccessible to the end user can be used to hold quota values that are looked up in the expansion. When delivery fails because this quota is exceeded, the handling of the error is as for system quota failures.

By default, Exim's quota checking mimics system quotas, and restricts the mailbox to the specified maximum size, though the value is not accurate to the last byte, owing to separator lines and additional headers that may get added during message delivery. When a mailbox is nearly full, large messages may get refused even though small ones are accepted, because the size of the current message is added to the quota when the check is made. This behaviour can be changed by setting quota_is_inclusive false. When this is done, the check for exceeding the quota does not include the current message. Thus, deliveries continue until the quota has been exceeded; thereafter, no futher messages are delivered. See also quota_warn_threshold.

quota_filecount (appendfile)

Type: integer
Default: 0

This option applies when the directory option is set. It limits the total number of files in the directory (compare the inode limit in system quotas). It can only be used if quota is also set.

quota_is_inclusive (appendfile)

Type: boolean
Default: true

See quota above.

quota_size_regex (appendfile)

Type: string
Default: unset

This option applies when one of the delivery modes that writes a separate file for each message is being used. When Exim wants to find the size of one of these files in order to test the quota, it first checks quota_size_regex. If this is set to a regular expression that matches the file name, and it captures one string, that string is interpreted as a representation of the file's size. This feature is useful only when users have no shell access to their mailboxes -- otherwise they could defeat the quota simply by renaming the files. This facility can be used with maildir deliveries, by setting maildir_tag to add the file length to the file name. For example:

maildir_tag = ,S=$message_size
quota_size_regex = S=(\d+)$

The string is not expanded.

quota_warn_message (appendfile)

Type: string, expanded
Default: see below

See below for the use of this option. If it is not set when quota_warn_threshold is set, it defaults to

quota_warn_message = "\
  To: $local_part@$domain\n\
  Subject: Your mailbox\n\n\
  This message is automatically created \
  by mail delivery software.\n\n\
  The size of your mailbox has exceeded \
  a warning threshold that is\n\
  set by the system administrator.\n"

quota_warn_threshold (appendfile)

Type: string, expanded
Default: "0"

This option is expanded in the same way as quota (see above). If the resulting value is greater than zero, and delivery of the message causes the size of the file or total space in the directory tree to cross the given threshold, a warning message is sent. If quota is also set, the threshold may be specified as a percentage of it by following the value with a percent sign. For example:

quota_warn_threshold = 75%

The warning message itself is specified by the quota_warn_message option, and it must start with a To: header line containing the recipient(s). A Subject: line should also normally be supplied. The quota option does not have to be set in order to use this option; they are independent of one another except when the threshold is specified as a percentage.

require_lockfile (appendfile)

Type: boolean
Default: true

When a lock file is being used (see use_lockfile) and require_lockfile is true, a lock file must be created before delivery can proceed. If the option is not true, failure to create a lock file because of a `permission denied' error is not treated as an error, though failure of the fcntl() locking function is. This option should always be set when delivering from more than one host over NFS. It is required to be set if the file option is set and use_fcntl_lock is not set, except when mbx_format is set.

retry_use_local_part (appendfile)

Type: boolean
Default: true

When a local delivery suffers a temporary failure, both the local part and the domain are normally used to form a key that is used to determine when next to try the address. This handles common cases such as exceeding a quota, where the failure applies to the specific local part. However, when local delivery is being used to collect messages for onward transmission by some other means, a temporary failure may not depend on the local part at all. Setting this option false causes Exim to use only the domain when handling retries for this transport.

suffix (appendfile)

Type: string, expanded
Default: "\n"

The string specified here is expanded and output at the end of every message. The default blank line can be suppressed by setting

suffix =

and this is usually necessary when doing batch SMTP deliveries, or delivering into individual files or MBX-format mailboxes.

use_crlf (appendfile)

Type: boolean
Default: false

This option causes lines to be terminated with the two-character CRLF sequence (carriage return, linefeed) instead of just a linefeed character. In the case of batched SMTP, the byte sequence written to the file is then an exact image of what would be sent down a real SMTP connection.

The contents of the prefix and suffix options are written verbatim, so must contain their own carriage return characters if these are needed. Since the default values for both prefix and suffix end with a single linefeed, their values almost always need to be changed if use_crlf is set.

use_fcntl_lock (appendfile)

Type: boolean
Default: see below

This option controls the use of the fcntl() function to lock a file for exclusive use when a message is being appended. It is set by default unless use_mbx_lock is set. Otherwise, it should be turned off only if you know that all your MUAs use lock file locking. When use_fcntl_lock is off, use_lockfile and require_lockfile must both be on if mbx_format is not set.

use_lockfile (appendfile)

Type: boolean
Default: see below

If this option is turned off, Exim does not attempt to create a lock file when appending to a file. Thus the only locking is by fcntl(). This option is set by default unless use_mbx_lock is set. It is not possible to turn both use_lockfile and use_fcntl_lock off, except when mbx_format is set. You should only turn use_lockfile off if you are absolutely sure that every MUA that is ever going to look at your users' mailboxes uses fcntl() rather than a lock file, and even then only when you are not delivering over NFS from more than one host. In order to append to an NFS file safely from more than one host, it is necessary to take out a lock before opening the file, and the lock file achieves this. Otherwise, even with fcntl() locking, there is a risk of file corruption. See also the require_lockfile option.

use_mbx_lock (appendfile)

Type: boolean
Default: see below

This option is available only if Exim has been compiled with SUPPORT_MBX set in `Local/Makefile'. Setting the option specifies that special MBX locking rules be used. It is set by default if mbx_format is set and none of the locking options are mentioned in the configuration. The locking rules are the same as are used by the c-client library that underlies Pine4 and the IMAP4 and POP daemons that come with it (see the discussion below). The rules allow for shared access to the mailbox. However, this kind of locking does not work when the mailbox is NFS mounted.

user (appendfile)

Type: string
Default: unset

If this option is set, it specifies the user under whose uid the delivery process is to be run, and which must be the owner of an existing file to which the message is appended. If the option is not set, a value must have been associated with the address by the director that handled it. If the string contains no $ characters, it is resolved when Exim starts up. Otherwise, the string is expanded at the time the transport is run, and must yield either a digit string or a name which can be looked up using getpwnam(). When getpwnam() is used, either at start-up time or later, the group id value associated with the user is taken as the value to be used if the group option is not set.

15.2 Operational details for appending

Before appending to a file, Exim proceeds as follows:

At the end of delivery, Exim closes the file (which releases the fcntl() lock) and then deletes the lock file if one was created.

15.3 Operational details for delivery to a new file

When the directory option is set, each message is delivered into a newly-created file or set of files. No locking is required while writing the message, so the various locking options of the transport are ignored. The `From' line that by default separates messages in a single file is not normally needed, nor is the escaping of message lines that start with `From', and there is no need to ensure a newline at the end of each message. Consequently, the default settings in appendfile need changing as follows:

  check_string = ""
  prefix = ""
  suffix = ""

There are three different ways in which delivery to individual files can be done, depending on the settings of the maildir_format and mailstore_format options. Note that code to support maildir and mailstore formats is not included in the binary unless SUPPORT_MAILDIR or SUPPORT_MAILSTORE, respectively, are set in `Local/Makefile'.

In all three cases an attempt is made to create the directory and any necessary sub-directories if they do not exist, provided that the create_directory option is set (the default). A created directory's mode is given by the directory_mode option. If creation fails, or if the create_directory option is not set when creation is required, the delivery is deferred.


Go to the first, previous, next, last section, table of contents.