Dovecot LDA
The Dovecot LDA, called deliver, is a local delivery agent which takes mail from an MTA and delivers it to a user's mailbox, while keeping Dovecot index files up to date.
This page describes the common settings required to make deliver work. You should read it first, and then the MTA specific pages:
Main features of Dovecot LDA
Mailbox indexing during mail delivery, providing faster mailbox access later
Sieve language support by a plugin
- Mail filtering
- Mail forwarding
- Vacation auto-reply
Common configuration
The configuration is done in the protocol lda section in dovecot.conf. The important settings are:
postmaster_address is used as the From: header address in bounce mails
hostname is used in generated Message-IDs and in Reporting-UA: header in bounce mails
sendmail_path is used to send mails. Note that the default is /usr/lib/sendmail, which doesn't necessarily work the same as /usr/sbin/sendmail.
auth_socket_path specifies the UNIX socket to dovecot-auth where deliver can lookup userdb information when -d parameter is used. See below how to configure Dovecot to create the socket.
Note that dovecot.conf file must be world readable to enable deliver process read it, while running with user privileges.
Parameters
Parameters accepted by deliver:
-d <username>: Destination username. If given, the user information is looked up from dovecot-auth. Typically used with virtual users, but not necessarily with system users.
-a <address>: Destination address (e.g. user+ext@domain). Default is the same as username. (v1.1+ only)
-f <address>: Envelope sender address.
-c <path>: Alternative configuration file path.
-m <mailbox>: Destination mailbox (default is INBOX). If the mailbox doesn't exist, it's created (unless -n is used). If message couldn't be saved to the mailbox for any reason, it's delivered to INBOX instead.
- If Sieve plugin is used, this mailbox is used as the "keep" action's mailbox. It's also used if there is no Sieve script or if the script fails for some reason.
v1.1: Deliveries to namespace prefix will result in saving the mail to INBOX instead. For example if you have "Mail/" namespace, this allows you to specify deliver -n -m Mail/$mailbox where mail is stored to Mail/$mailbox or to INBOX if $mailbox is empty.
The mailbox name is specified the same as it's visible in IMAP client. For example if you've a Maildir with .box.sub/ directory and your namespace configuration is prefix=INBOX/, separator=/, the correct way to deliver mail there is to use -m INBOX/box/sub
-n: If the destination mailbox doesn't exist, don't create it. This affects both -m parameter and fileinto action in Sieve scripts. The fallback is to deliver mail to INBOX.
-s: Subscribe to mailboxes that are automatically created (via -m parameter or fileinto Sieve action). (v1.1.3+)
-e: If mail gets rejected, write the rejection reason to stderr and exit with EX_NOPERM. The default is to send a rejection mail ourself (v1.0.1+).
-k: Don't clear all environment at startup (v1.1+).
-p <path>: Path to the mail to be delivered instead of reading from stdin. If using maildir the file is hard linked to the destination if possible. This allows a single mail to be delivered to multiple users using hard links, but currently it also prevents deliver from updating cache file so it shouldn't be used unless really necessary. (v1.1+)
Return values
deliver will exit with one of the following values:
- 0 (EX_OK): Delivery was successful.
- 64 (EX_USAGE): Invalid parameter given.
- 67 (EX_NOUSER): The destination username was not found.
- 78 (EX_CONFIG): Failed to read configuration file, a missing configuration setting or deliver binary is setuid-root and world-executable. (v1.2+ no longer uses this.)
77 (EX_NOPERM): -e parameter was used and mail was rejected. Typically this happens when user is over quota and quota_full_tempfail=no.
- 75 (EX_TEMPFAIL): A temporary failure. This is returned for almost all failures. See the log file for details.
System users
You can use deliver with a few selected system users (ie. user is found from /etc/passwd / NSS) by calling deliver in the user's ~/.forward file:
| "/usr/local/libexec/dovecot/deliver"
This should work with any MTA which supports per-user .forward files. For qmail's per-user setup, see LDA/Qmail.
This method doesn't require the authentication socket explained below since it's executed as the user itself.
Virtual users
With a lookup
Give the destination username to deliver with -d parameter, for example:
deliver -f $FROM_ENVELOPE -d $DEST_USERNAME
You'll need to set up a master authentication socket for deliver so it knows where to find mailboxes for the users:
protocol lda { .. # UNIX socket path to master authentication server to find users. #auth_socket_path = /var/run/dovecot/auth-master } auth default { .. socket listen { # Note that we're setting a master socket. SMTP AUTH for Postfix and Exim uses client sockets. master { # Typically under base_dir/, if not the directory must be created. path = /var/run/dovecot/auth-master # Auth master socket can be used to look up userdb information for # given usernames. This probably isn't very sensitive information # for most systems, but still try to restrict the socket access if possible. mode = 0600 user = vmail # User running deliver #group = mail # Or alternatively mode 0660 + deliver user in this group } } .. }
The master socket can be used to do userdb lookups for given usernames. Typically the result will contain the user's UID, GID and home directory, but depending on your configuration it may return other information as well. So the information is similar to what can be found from eg. /etc/passwd for system users. This means that it's probably not a problem to use mode=0666 for the socket, but you should try to restrict it more just to be safe.
Without a lookup
If you have already looked up the user's home directory and you don't need a userdb lookup for any other reason either (such as overriding settings for specific users), you can run deliver similar to how it's run for system users:
HOME=/path/to/user/homedir deliver -f $FROM_ENVELOPE
This way you don't need to have a master listener socket. Note that you should verify the user's existence prior to running deliver, otherwise you'll end up having mail delivered to non-existing users as well.
You must have set the proper UID (and GID) before running deliver. It's not possible to run deliver as root without -d parameter.
Multiple UIDs
If you're using more than one UID for users, you're going to have problems running deliver, as most MTAs won't let you run deliver as root. There are two ways to work around this problem:
- Make deliver setuid-root.
- Use sudo to wrap the invocation of deliver.
Making deliver setuid-root:
Beware: it's insecure to make deliver setuid-root, especially if you have untrusted users in your system. Setuid-root deliver can be used to gain root privileges. You should take extra steps to make sure that untrusted users can't run it and potentially gain root privileges. You can do this by making sure only your MTA has execution access to it. For example:
# chgrp secmail /usr/local/libexec/dovecot/deliver # chmod 04750 /usr/local/libexec/dovecot/deliver # ls -l /usr/local/libexec/dovecot/deliver -rwsr-x--- 1 root secmail 4023932 2009-01-15 16:23 deliver
Then start deliver as a user that belongs to secmail group. Note that you have to recreate these rights after each update of dovecot.
Using sudo:
Alternatively, you can use sudo to wrap the invocation of deliver. This has the advantage that updates will not clobber the setuid bit, but note that it is just as insecure being able to run deliver via sudo as setuid-root. Make sure you only give your MTA the ability to invoke deliver via sudo.
First configure sudo to allow 'dovelda' user to invoke deliver by adding the following to your /etc/sudoers:
Defaults:dovelda !syslog dovelda ALL=NOPASSWD:/usr/local/libexec/dovecot/deliver
Then configure your MTA to invoke deliver as user 'dovelda' and via sudo:
/usr/bin/sudo /usr/local/libexec/dovecot/deliver
instead of just plain /usr/local/libexec/dovecot/deliver.
Problems with deliver
Namespaces are supported with v1.1 and later. With v1.0 and older versions mails can be delivered only to mailboxes specified by the mail_location setting.
If you are using prefetch userdb, keep in mind that deliver does not make a password query and thus will not work if -d parameter is used. The UserDatabase/Prefetch page explains how to fix this.
See Checkpassword for how to make deliver work with checkpassword.
Logging
- Normally Dovecot logs everything through its master process, which is running as root. Deliver doesn't, which means that you might need some special configuration for it to log anything at all.
- If deliver fails to write to log files it exits with temporary failure.
If you have trouble finding where Dovecot logs by default, see Logging.
Note that Postfix's mailbox_size_limit setting applies to all files that are written to. So if you have a limit of 50 MB, deliver can't write to log files larger than 50 MB and you'll start getting temporary failures.
If you want deliver to keep using Dovecot's the default log files:
If you're logging to syslog, make sure the syslog socket (usually /dev/log) has enough write permissions for deliver. For example set it world-read/writable: chmod a+rw /dev/log.
- If you're logging to Dovecot's default log files again you'll need to give enough write permissions to the log files for deliver.
You can also specify different log files for deliver. This way you don't have to give any extra write permissions to other log files or the syslog socket. You can do this by overriding the log_path and info_log_path settings:
protocol lda { .. # remember to give proper permissions for these files as well log_path = /var/log/dovecot-deliver-errors.log info_log_path = /var/log/dovecot-deliver.log }
For using syslog with deliver, set the paths empty:
protocol lda { .. log_path = info_log_path = # You can also override the default syslog_facility: #syslog_facility = mail } Dovecot
Plugins
Most of the Dovecot plugins work with deliver.
Virtual quota can be enforced using Quota plugin.
Sieve language support can be added with Sieve plugin.