[This file still needs to be updated - some information is obsolete]

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 I
had in mind when I 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.

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 the forthcoming Cyrus 2.0.10, at least at the time of writing.
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 and the desired level of parallelization.

Please be sure to study this entire document as there are trade-offs
in convenience and in performance with these different approaches.

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, later Cyrus LMTP server
    implementations insist on SASL-style authentication. This means
    that Postfix must be built with SASL support (see SASL_README).
    The examples below show how to enable this in the Postfix LMTP
    client.

    Some Cyrus LMTP server implementations do not allow SASL-style
    authentication via plaintext passwords. You will have to jump
    some extra hoops in order to enable MD5 password support, or
    you will have to wait until this restriction is relaxed.


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".

5.2.2 - LMTP over TCP sockets
-----------------------------

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

/etc/cyrus.conf:

    SERVICES { 
	... 
	lmtp cmd="lmtpd" listen="127.0.0.1:lmtp" prefork=0 
	... 
    } 

/etc/services:

    lmtp 24/tcp

/etc/postfix/main.cf:

    mailbox_transport = lmtp:localhost
    lmtp_sasl_auth_enable = yes
    lmtp_sasl_password_maps = hash:/etc/postfix/lmtp_sasl_pass

/etc/postfix/lmtp_sasl_pass:
    localhost.my.domain	username:password

/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.

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 24 on the
local host, subsequently transmitting the message to the lmtpd
server managed by the Cyrus master process.


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.

However, there is a catch: the Postfix local delivery agent is
designed to deliver one recipient at a time, which in most cases
is more than adequate.  So, if you wish to support single instance
message store delivery, you will have to use a virtual table to
map these users to the appropriate LMTP destination (at the time
of writing, the Postfix transport table supports only per-domain
routing, and not per-recipient routing).

While the simplest thing to do would be to list the entire domain
in the transport map for LMTP delivery, this by-passes alias
expansion for otherwise local addresses (see section 5.1, delivery
mechanism 2).  If the site is to run software via aliases, like
most Mailing List Management (MLM) software, a more complex solution
is required.  A virtual table should do the trick.

As an example, suppose we wanted to support single instance message
store delivery for the hosted (not local) domain "example.org".
The configuration files for this domain could look something like
this:

    /etc/postfix/virtual:

        mlist@example.org   mlist@localhost

    /etc/postfix/transport:

        example.org         lmtp:unix:/var/imap/socket/lmtp

    /etc/postfix/aliases:

        mlist:              "|/path/to/mlm/software"

    /etc/postfix/master.cf:

        lmtp      unix  -       -       n       -       -       lmtp

    /etc/postfix/main.cf:

        mydestination = localhost, $myhostname, $mydomain
        virtual_maps = hash:/etc/postfix/virtual        
        transport_maps = hash:/etc/postfix/transport
        alias_maps = hash:/etc/postfix/aliases
        alias_database = hash:/etc/postfix/aliases

    /etc/cyrus.conf:

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

Breaking things down, we begin with the address "mlist@example.org",
which represents a mailing list.  By placing an entry in the virtual
map to direct this mail to "mlist@localhost", we can override the
transport map that would by default route all "@example.org" mail
to a LMTP server via a UNIX-domain socket.

To summarize, all mail that is to be processed by an alias entry
must first be diverted with a virtual table entry so that it does
not fall into the more general routing established by the transport
table.


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.0.10,
it would be good to upgrade.  The previous 2.x releases were beta
releases, and numerous bug fixes and enhancements have been
incorporated into the 2.0.10 release.

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 24/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.  :-)
