This document describes mail delivery via LMTP including Cyrus.
For an overview of all methods to host domains with Postfix, see
the HOSTING_README file.

1 - Postfix LMTP support
========================

LMTP stands for Local Mail Transfer Protocol, and is detailed in
RFC2033.  Postfix uses this protocol to communicate with the final
delivery agent, which may run on the local host or a remote host.

This protocol opens up interesting possibilities: one Postfix front
end machine can drive multiple mailbox back end machines over LMTP.
As the mail load increases, you add more Postfix front end systems
and more LMTP mailbox back end systems.  This is the model that
Wietse had in mind when he began drafting the design for Postfix
- a scalable architecture that allows you to keep adding SMTP
servers and mailbox servers painlessly.

Such a distributed architecture needs glue to keep things together.
You can use a networked database (LDAP or mysql) to share the user
database among the front end and back end systems. Use a replicated
database so that no machine becomes a single point of failure for
the entire mail infrastructure. Or you can use rsync when files
are small and/or when information does not change often.

Postfix LMTP support is based on a modified version of the Postfix
SMTP client. The initial version was by Philip A.  Prindeville of
Mirapoint, Inc., USA. This code was modified further by Amos Gouaux
of University of Texas at Dallas, Richardson, USA, who also revised
much of the documentation.  Wietse Venema reduced the code to its
present shape.


2 - Overview
============

Most of the examples in this document involve the CMU Cyrus IMAP/POP
server, available from:

    http://asg.web.cmu.edu/cyrus/

While certainly not the only application that could make use of
LMTP, it tends to be the most discussed.  These examples are based
on Cyrus 2.1.5.  The 2.x branch of Cyrus places greater emphasis on
LMTP delivery than the previous releases.  Those using older releases 
of Cyrus can find a discussion in the appendix of this document.

There are a variety of ways LMTP delivery can be configured in
Postfix.  The two basic flavors are delivery over UNIX-domain
sockets and delivery over TCP sockets.

  o Connections from the Postfix LMTP client over UNIX-domain
    sockets allow you to deliver to non-Postfix LMTP servers running
    on the same machine.

  o Connections from the Postfix LMTP client over TCP sockets allow
    you to deliver to non-Postfix LMTP servers across a local
    network.

Note: the above is not to be confused with the UNIX-domain sockets
that Postfix uses internally to speak its own protocols with the
Postfix LMTP client.

The precise syntax for UNIX-domain and TCP connection endpoints is
given in the lmtp(8) manual page. Examples are also given in the
text below.

Both socket flavors can be specified in either the Postfix main.cf
file (see section 5) or in a Postfix transport map (section 6).
What is the best approach for you depends upon the arrangement of
your servers.


3 - LMTP over UNIX-domain sockets
=================================

Use this to deliver mail from the Postfix LMTP client to an LMTP
server that is running on the same system.

A UNIX-domain socket is specified as the socket type ("unix") and
a name in the local file system:

    unix:/path/name

The "/path/name" part should be the name of a socket created by
the LMTP server on the local machine. See the specific examples
later in this document.

NOTE:

    If you run the Postfix LMTP client chrooted, the interpretation
    of the /path/name is relative to the Postfix queue directory
    (typically, /var/spool/postfix).

    By default, the Postfix LMTP client does not run chrooted.
    With LMTP delivery to the local machine there is no good reason
    to run the Postfix LMTP client chrooted.


4 - LMTP over TCP sockets
=========================

Use this to deliver mail from the Postfix LMTP client to an LMTP
server that is running on the same system or on a different system.

A TCP destination is specified as the socket type ("inet"), the
destination hostname and the TCP port:

    inet:hostname:port

The "inet:" part can be omitted, as it is the default socket type.

The destination port can be omitted as well. Currently the default
TCP port number for this type of connection is 24, but this can be
customized in the /etc/services file.  Specific examples are
given later in this document.

NOTE:

    With connections over TCP sockets, Cyrus 2.0.x LMTP server
    implementations insisted on SASL-style authentication.  This
    meant that Postfix had to be built with SASL support (see
    SASL_README).  While newer Cyrus releases offer an option to
    turn off this requirement, you must exercise great care in
    both determining the approach used and the configuration of
    your selection.  It is imperative that you do not allow
    unauthorized access to your LMTP server.  The examples below
    show both approaches.

    Some Cyrus LMTP server implementations do not allow SASL-style
    authentication via plaintext passwords over unencrypted
    connections.  This is not the case with 2.1.5.  However, you
    must realize that this could make your LMTP link vulnerable.
    If your LMTP communications traverse exposed networks, you
    should either use an encrypted connection or enable MD5 SASL
    mechanisms.


5 - Configuring LMTP using main.cf configuration
================================================

This is the simplest LMTP configuration.  

5.1 - Delivery mechanisms
-------------------------

Postfix main.cf supports three mechanisms to deliver mail to an
LMTP server.  Each method can use UNIX-domain or TCP sockets as
described in a later section.

main.cf mechanism 1
-------------------

mailbox_transport = lmtp:unix:/path/name (UNIX-domain socket example)
mailbox_transport = lmtp:hostname:port   (TCP socket example)

Mail that resolves as local (domain is listed in $mydestination)
is given to the Postfix local delivery agent.  The Postfix local
delivery agent expands aliases and .forward files, and delegates
mailbox delivery to the Postfix LMTP client which then sends it to
the non-Postfix LMTP server.

main.cf mechanism 2
-------------------

local_transport = lmtp:unix:/path/name (UNIX-domain socket example)
local_transport = lmtp:hostname:port   (TCP socket example)

Mail that resolves as local (domain is listed in $mydestination)
is directly given to the Postfix LMTP client which then sends it
to the non-Postfix LMTP server.  The mail is not processed by the
Postfix local delivery agent; therefore aliases and .forward files
are not processed.

main.cf mechanism 3
-------------------

fallback_transport = lmtp:unix:/path/name (UNIX-domain socket example)
fallback_transport = lmtp:hostname:port   (TCP socket example)

Mail that resolves as local (domain is listed in $mydestination)
is given to the Postfix local delivery agent.  The Postfix local
delivery agent processes aliases and .forward files, and delivers
to /var[/spool]/mail/$user for users that have a UNIX account.
Mail for other local users is delegated to the Postfix LMTP client
which then sends it to the non-Postfix LMTP server.

5.2 - Examples
--------------

5.2.1 - LMTP over UNIX-domain sockets
-------------------------------------

To utilize UNIX-domain sockets for the communication between
Postfix and Cyrus, the corresponding configuration files should
look something like this:

    /etc/cyrus.conf:
        SERVICES { 
          ... 
	  lmtpunix cmd="lmtpd" listen="/var/imap/socket/lmtp" prefork=1
	  ... 
        } 

    /etc/postfix/main.cf:
        mailbox_transport = lmtp:unix:/var/imap/socket/lmtp

    /etc/postfix/master.cf:
        lmtp      unix  -       -       n       -       -       lmtp

In this case, the Postfix local delivery agent expands aliases
and .forward files, and delegates mailbox delivery to the Cyrus
lmtpd server via the socket "/var/imap/socket/lmtp".

NOTE:

    Make sure that both the user id that Cyrus runs under and the
    Postfix user id can access the socket "/var/imap/socket/lmtp".
    While this is implied by the example above, it is often
    overlooked and so warrants emphasis.

5.2.2 - LMTP over TCP sockets (non-SASL)
----------------------------------------

For this example, suppose the following files are configured
thusly: 

    /etc/cyrus.conf:
        SERVICES { 
	  ... 
	  lmtp cmd="lmtpd -a" listen="127.0.0.1:lmtp" prefork=1 
	  ... 
        } 

    /etc/services:
        lmtp 2003/tcp

    /etc/postfix/main.cf:
        mailbox_transport = lmtp:localhost

    /etc/postfix/master.cf:
        lmtp      unix  -       -       n       -       -       lmtp

With the above settings, the Postfix local delivery agent expands
aliases and .forward files, and delegates mailbox delivery to the
Cyrus LMTP server.  Postfix makes a connection to port 2003 on the
local host, subsequently transmitting the message to the lmtpd
server managed by the Cyrus master process.  The port number has 
been changed in /etc/services from 24 to 2003 as that is what the
Cyrus LMTP server is now using.

See the Cyrus lmtpd(8) man page to verify that the version you
have supports the "-a" option.

NOTE:

    Consider this approach if and only if this particular host
    does not allow direct user logins or user-controlled
    processes.  Otherwise, this LMTP server may be abused!
    
    If the Cyrus lmtp service is to listen on a network other
    than the local loop-back (127.0.0.1), be sure to install
    Cyrus with tcp_wrappers support.  Then use tcp_wrappers
    to only allow access to the "lmtp" service from trusted
    hosts.  Otherwise, this LMTP server may be abused!

    Section 10 contains an example using tcp_wrappers.  For the
    configuration above, replace "deliver" with "lmtp" in the
    /etc/hosts.allow shown in that example.

5.2.3 - LMTP over TCP sockets (SASL)
------------------------------------

In the following example "cyhost.my.domain" is the name of the Cyrus
IMAP/POP server.  It is important that you use this name consistently
in the Postfix configuration settings.  The first approach uses the
PLAIN authentication mechanism (see the Cyrus SASL documentation.)

Suppose the Cyrus server has the following files configured thusly: 

    /etc/cyrus.conf:
        SERVICES { 
	  ... 
	  lmtp cmd="lmtpd" listen="cyhost.my.domain:lmtp" prefork=1
	  ... 
        } 

    /etc/imapd.conf:
        lmtp_admins: lmtpuser

    /etc/services:
        lmtp 2003/tcp

The Postfix host (may be same box) has the following configuration:

    /etc/postfix/main.cf:
        mailbox_transport = lmtp:cyhost.my.domain
        lmtp_sasl_auth_enable = yes
        lmtp_sasl_password_maps = hash:/etc/postfix/lmtp_sasl_pass
        lmtp_sasl_security_options = noanonymous

    /etc/postfix/lmtp_sasl_pass:
        cyhost.my.domain	lmtpuser:password

    /etc/services:
        lmtp 2003/tcp

    /etc/postfix/master.cf:
        lmtp      unix  -       -       n       -       -       lmtp

Instead of "hash", use the map type of your choice.  Some systems
use "dbm" instead.  Use "postconf -m" to find out what map types
are supported.

If your version of Cyrus does not support "lmtp_admins" as a 
setting in imapd.conf, use "admins" instead.

With the above settings, the Postfix local delivery agent expands
aliases and .forward files, and delegates mailbox delivery to the
Cyrus LMTP server.  Postfix makes a connection to port 2003 on the
local host, subsequently transmitting the message to the lmtpd
server managed by the Cyrus master process.  The port number has 
been changed in /etc/services from 24 to 2003 as that is what the
Cyrus LMTP server is now using.  The SASL configuration on the Cyrus
server will need to accept the user "lmtpuser" using the password
specified in /etc/postfix/lmtp_sasl_pass on the Postfix host.

If this LMTP conduit exists over an exposed network, you should
compile Postfix with MD5 (CRAM or DIGEST) password support.  See
SASL_README for more details.  Then configure Postfix as follows:

    /etc/postfix/main.cf:
        lmtp_sasl_security_options = noanonymous, noplaintext

On the Cyrus host you should also set:

    /etc/imapd.conf:
        lmtp_allowplaintext: no

You will need to make sure the "lmtpuser" is in the appropriate
SASL database.  As an example, the following would add "lmtpuser"
to /etc/sasldb2:

    saslpasswd2 -c -u cyhost.my.domain lmtpuser

If you encounter difficulties with "lmtpuser" not being permitted
to authenticate to the LMTP server, try the above command with the
un-qualified hostname:

    saslpasswd2 -c -u cyhost lmtpuser

Also make sure the Cyrus user has read permission of the SASL
database, /etc/sasldb2 in the example above.

Incidentally, it is very likely that the Cyrus server and the
Postfix server will need to use the same SASL backend databases
(e.g., auxprop or saslauthd.)  Currently it is not possible to
assign different SASL backends for different Cyrus services.
Only TLS (SSL) or STARTTLS can be used in conjunction with
saslauthd.  Since none of these encryption methods are available
for LMTP, if you need to encrypt your LMTP connections, you will
very likely have to use auxprop throughout.


6 - Configuring LMTP using transport map configuration
======================================================

This approach is quite similar to specifying the LMTP service in
the Postfix main.cf configuration file.  However, now we will use
a transport map to route mail to the appropriate LMTP server,
instead of depending on delegation by the Postfix local delivery
agent.

Why might this approach be useful?  This could be handy if you wish
to route mail for multiple domains to their respective mail retrieval
(IMAP/POP) server.  Example:

    /etc/postfix/transport:
	domain1.tld		lmtp1:unix:/path/name
	domain2.tld		lmtp2:lmtp2host

    /etc/postfix/master.cf:
        lmtp1      unix  -       -       n       -       -       lmtp
        lmtp2      unix  -       -       n       -       -       lmtp

    /etc/postfix/main.cf:
        transport_maps = hash:/etc/postfix/transport

For details of the Cyrus LMTP server configuration, see section 5.

Instead of "hash", use the map type of your choice.  Some systems use
"dbm" instead.  Use "postconf -m" to find out what map types are
supported.


7 - Performance considerations
==============================

Hopefully the preceding discussion has seemed pretty straight
forward.  Now things get interesting.  After reading the following
you will see that there are more factors to consider when setting
up LMTP services.


8 - Single instance message store
=================================

Presently this topic is more pertinent to sites running Cyrus, but
may be a factor with other applications as well.

Since 1.6.22, Cyrus has had the feature that if a message containing
multiple recipients is received via the LMTP protocol, and all
these recipients were on the same Cyrus partition, only one instance
of this message would be written to the file system.  The other
recipients would then see a hard link of this single instance.
Depending on your user base, this can be considerable motivation
to using LMTP.

With the examples in section 5.2, we can increase the number of
recipients (to $mydestination) that can be handled at once:

    /etc/postfix/main.cf:
        local_destination_recipient_limit = 300

The 300 was arbitrarily chosen for this example.  Be sure to pick a
number that is appropriate for the capabilities of your hardware.
The bigger the number, the more you can leverage the single instance
message store.  However, if it is too big the LMTP server will need
too much time to deliver a message and Postfix will experience
timeout errors.  Choose this value very carefully.

NOTE:

    Not all local delivery agent transports can support a recipient
    limit greater than 1.  Be sure to check the man page of the
    specific transport before attempting this with anything but the
    Postfix LMTP client.

If we wish to apply this single instance message store technique
with the configuration example in section 6, the setting would be:

    /etc/postfix/main.cf:
        lmtp1_destination_recipient_limit = 300
        lmtp2_destination_recipient_limit = 300

As previously mentioned, exercise tremendous care backed by
extensive analysis of your systems before setting the recipient
limit like this.


9 - Improving connection caching performance
============================================

After delivering a message via LMTP, Postfix will keep the connection
open for a while, so that it can be reused for a subsequent delivery.
This reduces overhead of LMTP servers that create one process per
connection.

For LMTP connection caching to work, the Postfix LMTP client should
not switch destination hosts.  This is no problem when you run only
one LMTP server. However, if you run multiple LMTP servers, this
can be an issue.

You can prevent the LMTP client from switching between servers by
configuring a separate LMTP delivery transport for each LMTP server:

    /etc/postfix/master.cf:
        lmtp1      unix  -       -       n       -       -       lmtp
        lmtp2      unix  -       -       n       -       -       lmtp
          .         .    .       .       .       .       .        .

Configure transport table entries such that the lmtp1 mail delivery
transport is used for all deliveries to the LMTP server #1, the
mail lmtp2 transport for the LMTP server #2, and so on.

    /etc/postfix/transport:
        foo.com lmtp1:lmtp1host
        bar.com lmtp2:lmtp2host


10 - Appendix: Older Cyrus versions
===================================

First of all, if you are using a Cyrus 2.x version prior to 2.1.4,
you should really consider upgrading.  There have been numerous bug
fixes and performance improvements since the early 2.0 releases.

Further back, 1.6.24 was the last pre-2.x production release.
(Actually, there was a 1.6.25-BETA, but it is uncertain whether this
will be released officially as CMU is now focusing support on the 2.x
branch.)  The following discussion touches on how to configure the
Postfix LMTP facilities with Cyrus 1.6.24.

One of the significant differences between Cyrus 1.x and 2.x is the
inclusion of the "master" process in 2.x.  This "master" process is
responsible for running the various components of Cyrus, such as
imapd, pop3d, and lmtpd.  Prior to 2.x, these services were managed
by inetd, the Internet services daemon.

To utilize LMTP delivery with Cyrus 1.6.24, the first thing to do is
configure inetd.  This involves the following file edits:

    /etc/services:
        lmtp 2003/tcp

    /etc/inetd.conf:
        lmtp stream tcp nowait cyrus /usr/sbin/tcpd /usr/cyrus/bin/deliver -e -l

    /etc/hosts.allow:
        deliver : localhost : ALLOW
        deliver : ALL@ALL : DENY

The "/usr/sbin/tcpd" is from the tcp_wrappers package, which is
discussed in the example "LMTP over TCP sockets, using hosts.allow."
It is important that you wrap this LMTP port to protect it from
unauthorized access.

On some systems, tcpd is built into inetd, so you do not have to
specify tcpd in the inetd.conf file. Instead of tcpd/inetd, xinetd
can do a similar job of logging and access control.

Now comes the Postfix configuration.  Basically, the Cyrus 2.x
discussions regarding LMTP delivery over TCP are also applicable to
Cyrus 1.x, with the exception of the /etc/cyrus.conf file.  A
typical Postfix configuration might look like this:

    /etc/postfix/master.cf:
        lmtp      unix  -       -       n       -       -       lmtp

    /etc/postfix/main.cf:
        mailbox_transport = lmtp

It is also possible to use the transport map to route mail to your
Cyrus 1.6.24 LMTP server:

    /etc/postfix/transport:
	domain1.tld		lmtp1:lmtp1host
	domain2.tld		lmtp2:lmtp2host

    /etc/postfix/master.cf:
        lmtp1      unix  -       -       n       -       -       lmtp
        lmtp2      unix  -       -       n       -       -       lmtp

    /etc/postfix/main.cf:
        transport_maps = hash:/etc/postfix/transport

If you have read the discussion covering the Cyrus 2.x installation,
you will notice the one significant difference with the Postfix
configuration is the lack of mention of the UNIX-domain sockets.
That is because delivery over UNIX-domain sockets is new with Cyrus
2.x, yet another reason to upgrade.  :-)
