From: Wietse Venema Date: Mon, 5 Jan 2004 05:00:00 +0000 (-0500) Subject: postfix-2.0.16-20040105 X-Git-Tag: v2.1-RC1-20040331~8 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8b3ac07c6975c0646914828a59b2774d47c63555;p=thirdparty%2Fpostfix.git postfix-2.0.16-20040105 --- diff --git a/postfix/HISTORY b/postfix/HISTORY index 132ad8b09..7fb8e8d9a 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -8978,13 +8978,13 @@ Apologies for any names omitted. used by the Postfix SMTP server. Liviu Daia. Files: mail_params.h, smtpd.c, smtpd_sasl_glue.c. - Cleanup: shared config file parser for ldap, mysql, pgsql - lookup tables. Liviu Daia. Files: global/cfgparser.[hc], - global/dict_ldap.c, global/dict_mtsql.c, global/dict_pgsql.c - and documentation. + Cleanup: the LDAP client configuration parser is now shared + between the LDAP, MySQL, and PGSQL clients. Liviu Daia. + Files: global/cfgparser.[hc], global/dict_ldap.c, + global/dict_mtsql.c, global/dict_pgsql.c and documentation. - Cleanup: moved modules with dependencies on higher-level - code from the util directory to the global directory: + Cleanup: moved "util" modules with dependencies on higher-level + "global" code from the util directory to the global directory: util/dict_open.c, global/cfgparser.[hc], global/dict_ldap.c, global/dict_mtsql.c, global/dict_pgsql.c, global/mail_dict.c. @@ -8998,6 +8998,19 @@ Apologies for any names omitted. character stored. This avoids mis-leading warnings. File: global/vstring_vstream.c. +20040105 + + Cleanup: don't bother the flush daemon while deferring mail + if the destination is not "fast flush" eligible. File: + global/flush_clnt.c. + + Safety: the SMTP server flushes recipients to the cleanup + server in order to avoid SMTP timeouts when virtual or + canonical expansions take a lot of time. File smtpd/smtpd.c. + + Safety: add warnings to postmap and postalias when table + lookup results in an empty string. + Open problems: Low: in the SMTP client, pass the session, request and diff --git a/postfix/README_FILES/FILTER_README b/postfix/README_FILES/FILTER_README index 24ea183db..4364efa1d 100644 --- a/postfix/README_FILES/FILTER_README +++ b/postfix/README_FILES/FILTER_README @@ -314,7 +314,7 @@ filtering for incoming mail. This is required or else mail will stay in the content filtering loop. The "-o receive_override_options" overrides main.cf. It is -complementary to the the options that are specified in main.cf: +complementary to the options that are specified in main.cf: - Disable attempts to find out if a recipient is unknown, and disable header/body checks. This work was already done before diff --git a/postfix/README_FILES/VIRTUAL_MAILBOX_README b/postfix/README_FILES/VIRTUAL_MAILBOX_README index 44f2e1407..3b960a8a8 100644 --- a/postfix/README_FILES/VIRTUAL_MAILBOX_README +++ b/postfix/README_FILES/VIRTUAL_MAILBOX_README @@ -2,6 +2,9 @@ This code was created by Andrew McNamara and adapted to snapshot 20001121 by Xavier Beaudouin. It was merged with mainstream Postfix for snapshot 20010128 by Wietse. +See the VIRTUAL_README file for an overview of how you can host +multiple domains with one Postfix system. + Purpose of this software ======================== diff --git a/postfix/README_FILES/VIRTUAL_README b/postfix/README_FILES/VIRTUAL_README index 513e77f35..05b188314 100644 --- a/postfix/README_FILES/VIRTUAL_README +++ b/postfix/README_FILES/VIRTUAL_README @@ -1,17 +1,258 @@ -Porpose of this document +Purpose of this document ======================== -Hosting multiple domains on one server +This document describes how to configure one Postfix system for +final mail delivery of multiple Internet domains, using the mailbox +and maildir delivery mechanisms that are already built into Postfix. +See the LMTP_README file for an example of final delivery with +third-party mailstores such as Cyrus. -UNIX system accounts, domain shared with all users -================================================== +Preliminaries: local files versus databases +=========================================== -UNIX system accounts, domains not shared -======================================== +The examples in this text use table lookups from local files. +These are easy to debug with the postmap "-q" command option. -Non-UNIX accounts, domains not shared -===================================== +Example: postmap -q info@example.com hash:/etc/postfix/virtual + +See LDAP_README, MYSQL_README and PGSQL_README for how to replace +local files by databases. The reader is strongly advised to make +the system work with local files before migrating to database files, +and to use the postmap "-q" command option to verify that database +lookups produce the exact same results as local file lookup. + +Example: postmap -q info@example.com:ldap:/etc/postfix/virtual.cf + +Preliminaries: canonical versus virtual domains +=============================================== + +Each Postfix system does final delivery for a small number of +canonical domains; usually these are the names of the machine that +Postfix runs on. Sometimes the list of canonical domains also +includes the parent domain of the machine name. + +Postfix can be configured to do final delivery for additional +domains. The domains are called virtual, because they are not +associated with the name of the machine itself. + +Postfix understands two types of virtual domain: + +- The virtual alias domain, where each virtual address is aliased + to a different (remote or local) address. + +- The virtual mailbox domain, where each virtual address can have + its own mailbox. + +A third type, the "sendmail style virtual domain" was described +with older Postfix versions. It will not be discussed here in order +to avoid a lot of confusion. + +Shared domains, UNIX system accounts +==================================== + +The simplest method to host an additional domain is to specify the +user names in the UNIX password file and to specify the domain name +in the Postfix mydestination configuration parameter. + +In the examples we will use "example.com" as the domain that is +being hosted on the local Postfix machine. + +/etc/postfix/main.cf: + mydestination = $myhostname localhost.$mydomain ... example.com + +The downside of this approach is a total lack of separation: mail +for info@my.host.name is delivered to the same UNIX system account +as mail for info@example.com. If different domains need to have +different "info" mailboxes, then you can use one of the methods +described in the remainder of this document. + +Another downside of listing all users in the UNIX password file is +that administration of large numbers of users becomes inconvenient. + +Virtual ALIAS domains: separate domains, UNIX system accounts +============================================================= + +The simplest method to host separate domains is to create so-called +virtual aliases that redirect mail from each virtual address to +its own UNIX account. + +The example below shows how to set up the example.com domain +as a so-called virtual alias domain: + +/etc/postfix/main.cf: + virtual_alias_domains = example.com ...other domains... + virtual_alias_maps = hash:/etc/postfix/virtual + +/etc/postfix/virtual: + postmaster@example.com postmaster + info@example.com joe + sales@example.com jane + # Uncomment entry below to implement a catch-all address + # @example.com jim + ...virtual aliases for other domains... + +The virtual_alias_domains setting tells Postfix that example.com +is a so-called virtual alias domain. If you omit this step then +Postfix will either reject mail (relay access denied) or will not +be able to deliver it (mail for example.com loops back to myself). + +The /etc/postfix/virtual file contains the virtual aliases. With +the example above, mail for postmaster@example.com goes to the +local postmaster, while mail for info@example.com goes to the UNIX +account joe, and mail for sales@example.com goes to the UNIX account +jane. Mail for all other addresses in example.com is rejected with +the error message "User unknown". + +The commented out entry (text after #) shows how one would implement +a catch-all virtual alias that receives mail for every example.com +address not listed in the virtual alias file. This is not without +risk. Spammers nowadays try to send mail from (or mail to) every +possible name that they can think of. A catch-all mailbox is likely +to receive many spam messages, and many bounces for spam messages +that were sent in the name of anything@example.com. + +Execute the command "postmap /etc/postfix/virtual" after changing +the virtual file, and execute the command "postfix reload" after +changing the main.cf file. + +Note: virtual aliases can resolve to a local address or to a remote +address, or both. They don't have to resolve to UNIX system accounts +on your machine. + +More details about the virtual alias file are given in the virtual(5) +manual page, including multiple addresses on the right-hand side. + +Virtual aliasing solves one problem: it allows each domain to have +its own info mail address. Virtual aliasing to UNIX system accounts +still has the drawback that every user has to be listed in the UNIX +password file. The next section eliminates this problem. + +Virtual MAILBOX domains: separate domains, non-UNIX accounts +============================================================ + +As a system hosts more and more domains and users, it becomes +unpractical to give everyone their own UNIX system account. + +With the Postfix virtual delivery agent, every recipient address +can have its own virtual mailbox. Unlike virtual alias domains, +there is no translation from recipient addresses into different +addresses. + +The Postfix virtual delivery agent looks up the user mailbox +pathname, uid and gid via separate tables that are searched with +the recipient's mail address. Maildir style delivery is turned on +by terminating the mailbox pathname with "/". + +Here is an example of a virtual mailbox domain example.com: + +/etc/postfix/main.cf: + virtual_mailbox_base = /var/mail/vhosts + virtual_mailbox_maps = hash:/etc/postfix/vmailbox + virtual_mailbox_domains = example.com ...other domains... + virtual_minimum_uid = 100 + virtual_uid_maps = static:5000 + virtual_gid_maps = static:5000 + virtual_alias_maps = hash:/etc/postfix/virtual + +/etc/postfix/vmailbox: + info@example.com example.com/info + sales@example.com example.com/sales/ + # Comment out the entry below to implement a catch-all. + # @example.com example.com/catchall + ...virtual mailboxes for other domains... + +/etc/postfix/virtual: + postmaster@example.com postmaster + +The virtual_mailbox_base parameter specifies a prefix for all +virtual mailbox pathnames. This is a safety mechanism that prevents +mail from being delivered all over the file system. + +The virtual_mailbox_maps parameter specifies the lookup table with +mailbox (or maildir) pathnames, indexed by the virtual mail address. +In this example, mail for info@example.com goes to the mailbox at +/var/mail/vhosts/example.com/info while mail for sales@example.com +goes to the maildir located at /var/mail/vhosts/example.com/sales/. + +The virtual_minimum_uid prevents specifies a lower bound on the +mailbox or maildir owner's UID. This is a safety mechanism that +prevents mail from being written to sensitive files. + +In the above example, the virtual_uid_maps and virtual_gid_maps +parameters specify that all the virtual mailboxes are owned by a +fixed uid and gid 5000. If this is not what you want, specify +lookup tables that are searched by the recipient's mail address. + +The commented out entry (text after #) shows how one would implement +a catch-all virtual mailbox address. Be prepared to receive a lot +of spam, as well as bounced spam that was sent in the name of +anything@example.com. + +NEVER put a virtual MAILBOX wild-card in the virtual ALIAS file!! + +As you see above, it is possible to mix virtual aliases with virtual +mailboxes. We use this feature to redirect mail for example.com's +postmaster address to the local postmaster. + +Execute the command "postmap /etc/postfix/virtual" after changing +the virtual file, execute "postmap /etc/postfix/vmailbox" after +changing the vmailbox file, and execute the command "postfix reload" +after changing the main.cf file. + +Note: mail delivery happens with the UID/GID privileges of the +recipient. You must create maildirs in advance before you can use +them. Depending on directory permissions, Postfix may be able to +create mailbox files by itself, but it is safer to create them +ahead of time. + +More details about the virtual mailbox delivery agent are given +in the file VIRTUAL_MAILBOX_README, and in the virtual(8) manual +page. Aliases, mailing lists, etc. ============================ + +The examples above already show how to direct mail for virtual +postmaster addresses to a local postmaster. The same method can be +used to direct mail for other virtual addresses to a local or remote +address. + +Virtual aliases can't directly deliver to mailing list managers +such as majordomo. One solution is to set up a transport mapping +that directs the mail to the Postfix local delivery agent, and to +use the local alias file for delivery to the mailing list manager: + +/etc/postfix/main.cf: + transport_maps = hash:/etc/postfix/transport + +/etc/postfix/transport: + listname-request@example.com local: + listname@example.com local: + owner-listname@example.com local: + +/etc/aliases: + listname: "|/some/where/majordomo/wrapper ..." + owner-listname: ... + listname-request: ... + +You can achieve the same result with virtual aliases that direct +virtual addresses to the local delivery agent: + +/etc/postfix/main.cf: + virtual_alias_maps = hash:/etc/postfix/virtual + +/etc/postfix/virtual: + listname-request@example.com listname-request + listname@example.com listname + owner-listname@example.com owner-listname + +/etc/aliases: + listname: "|/some/where/majordomo/wrapper ..." + owner-listname: ... + listname-request: ... + +Either approach will do the job. + +More information about the Postfix local delivery agent can be +found in the local(8) manual page. diff --git a/postfix/html/postmap.1.html b/postfix/html/postmap.1.html index 82413da06..7072955f1 100644 --- a/postfix/html/postmap.1.html +++ b/postfix/html/postmap.1.html @@ -1,4 +1,4 @@ -
+  
 POSTMAP(1)                                             POSTMAP(1)
 
 NAME
diff --git a/postfix/makedefs b/postfix/makedefs
index 1d0d2f428..2c11f07f2 100644
--- a/postfix/makedefs
+++ b/postfix/makedefs
@@ -336,7 +336,7 @@ AR	= $AR
 ARFL	= $ARFL
 RANLIB	= $RANLIB
 SYSLIBS	= $AUXLIBS $SYSLIBS
-CC	= $CC $CCARGS
+CC	= $CC -DSNAPSHOT $CCARGS
 OPT	= $OPT
 DEBUG	= $DEBUG
 AWK	= $AWK
diff --git a/postfix/src/cleanup/Makefile.in b/postfix/src/cleanup/Makefile.in
index c390e5ae0..4d4e632e0 100644
--- a/postfix/src/cleanup/Makefile.in
+++ b/postfix/src/cleanup/Makefile.in
@@ -245,6 +245,7 @@ cleanup_init.o: ../../include/name_mask.h
 cleanup_init.o: ../../include/mail_addr.h
 cleanup_init.o: ../../include/mail_params.h
 cleanup_init.o: ../../include/ext_prop.h
+cleanup_init.o: ../../include/flush_clnt.h
 cleanup_init.o: cleanup.h
 cleanup_init.o: ../../include/vstring.h
 cleanup_init.o: ../../include/vbuf.h
diff --git a/postfix/src/cleanup/cleanup_init.c b/postfix/src/cleanup/cleanup_init.c
index fe8015cad..51a88a25d 100644
--- a/postfix/src/cleanup/cleanup_init.c
+++ b/postfix/src/cleanup/cleanup_init.c
@@ -78,6 +78,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /* Application-specific. */
 
@@ -244,6 +245,8 @@ void    cleanup_pre_jail(char *unused_name, char **unused_argv)
 	cleanup_rcpt_bcc_maps =
 	    maps_create(VAR_RCPT_BCC_MAPS, var_rcpt_bcc_maps,
 			DICT_FLAG_LOCK);
+
+    flush_init();
 }
 
 /* cleanup_post_jail - initialize after entering the chroot jail */
diff --git a/postfix/src/error/Makefile.in b/postfix/src/error/Makefile.in
index a6559a48b..82311bcf0 100644
--- a/postfix/src/error/Makefile.in
+++ b/postfix/src/error/Makefile.in
@@ -63,4 +63,5 @@ error.o: ../../include/recipient_list.h
 error.o: ../../include/mail_queue.h
 error.o: ../../include/bounce.h
 error.o: ../../include/deliver_completed.h
+error.o: ../../include/flush_clnt.h
 error.o: ../../include/mail_server.h
diff --git a/postfix/src/error/error.c b/postfix/src/error/error.c
index 001e8697e..3568ae515 100644
--- a/postfix/src/error/error.c
+++ b/postfix/src/error/error.c
@@ -81,6 +81,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /* Single server skeleton. */
 
@@ -176,9 +177,18 @@ static void error_service(VSTREAM *client_stream, char *unused_service, char **a
     }
 }
 
+/* pre_init - pre-jail initialization */
+
+static void pre_init(char *unused_name, char **unused_argv)
+{
+    flush_init();
+}
+
 /* main - pass control to the single-threaded skeleton */
 
 int     main(int argc, char **argv)
 {
-    single_server_main(argc, argv, error_service, 0);
+    single_server_main(argc, argv, error_service,
+		       MAIL_SERVER_PRE_INIT, pre_init,
+		       0);
 }
diff --git a/postfix/src/global/flush_clnt.c b/postfix/src/global/flush_clnt.c
index 714599f5d..12948c69e 100644
--- a/postfix/src/global/flush_clnt.c
+++ b/postfix/src/global/flush_clnt.c
@@ -6,6 +6,8 @@
 /* SYNOPSIS
 /*	#include 
 /*
+/*	void	flush_init()
+/*
 /*	int	flush_add(site, queue_id)
 /*	const char *site;
 /*	const char *queue_id;
@@ -22,6 +24,9 @@
 /*	is maintained for eligible destinations. A destination is the
 /*	right-hand side of a user@domain email address.
 /*
+/*	flush_init() initializes. It must be called before dropping
+/*	privileges in a daemon process.
+/*
 /*	flush_add() informs the "fast flush" cache manager that mail is
 /*	queued for the specified site with the specified queue ID.
 /*
@@ -77,13 +82,25 @@
 
 #include 
 #include 
-#include 
 #include 
+#include 
+#include 
+#include 
 
 /* Application-specific. */
 
 #define STR(x)	vstring_str(x)
 
+static DOMAIN_LIST *flush_domains;
+
+/* flush_init - initialize */
+
+void    flush_init(void)
+{
+    flush_domains = domain_list_init(match_parent_style(VAR_FFLUSH_DOMAINS),
+				     var_fflush_domains);
+}
+
 /* flush_purge - house keeping */
 
 int     flush_purge(void)
@@ -147,9 +164,12 @@ int     flush_send(const char *site)
 	msg_info("%s: site %s", myname, site);
 
     /*
-     * Don't bother the server if the service is turned off.
+     * Don't bother the server if the service is turned off, or if the site
+     * is not eligible.
      */
-    if (*var_fflush_domains == 0)
+    if (flush_domains == 0)
+	msg_panic("missing flush client initialization");
+    if (domain_list_match(flush_domains, site) == 0)
 	status = FLUSH_STAT_DENY;
     else
 	status = mail_command_client(MAIL_CLASS_PUBLIC, var_flush_service,
@@ -174,9 +194,12 @@ int     flush_add(const char *site, const char *queue_id)
 	msg_info("%s: site %s id %s", myname, site, queue_id);
 
     /*
-     * Don't bother the server if the service is turned off.
+     * Don't bother the server if the service is turned off, or if the site
+     * is not eligible.
      */
-    if (*var_fflush_domains == 0)
+    if (flush_domains == 0)
+	msg_panic("missing flush client initialization");
+    if (domain_list_match(flush_domains, site) == 0)
 	status = FLUSH_STAT_DENY;
     else
 	status = mail_command_client(MAIL_CLASS_PUBLIC, var_flush_service,
diff --git a/postfix/src/global/flush_clnt.h b/postfix/src/global/flush_clnt.h
index ee82a984c..2846fb377 100644
--- a/postfix/src/global/flush_clnt.h
+++ b/postfix/src/global/flush_clnt.h
@@ -14,6 +14,7 @@
  /*
   * External interface.
   */
+extern void flush_init(void);
 extern int flush_add(const char *, const char *);
 extern int flush_send(const char *);
 extern int flush_refresh(void);
diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h
index f5424cfb0..d1ededa9e 100644
--- a/postfix/src/global/mail_version.h
+++ b/postfix/src/global/mail_version.h
@@ -20,7 +20,7 @@
   * Patches change the patchlevel and the release date. Snapshots change the
   * release date only, unless they include the same bugfix as a patch release.
   */
-#define MAIL_RELEASE_DATE	"20040104"
+#define MAIL_RELEASE_DATE	"20040105"
 
 #define VAR_MAIL_VERSION	"mail_version"
 #define DEF_MAIL_VERSION	"2.0.16-" MAIL_RELEASE_DATE
diff --git a/postfix/src/lmtp/Makefile.in b/postfix/src/lmtp/Makefile.in
index a095dfb79..9b3ca14d8 100644
--- a/postfix/src/lmtp/Makefile.in
+++ b/postfix/src/lmtp/Makefile.in
@@ -75,6 +75,7 @@ lmtp.o: ../../include/mail_params.h
 lmtp.o: ../../include/mail_conf.h
 lmtp.o: ../../include/debug_peer.h
 lmtp.o: ../../include/mail_error.h
+lmtp.o: ../../include/flush_clnt.h
 lmtp.o: ../../include/mail_server.h
 lmtp.o: lmtp.h
 lmtp.o: lmtp_sasl.h
diff --git a/postfix/src/lmtp/lmtp.c b/postfix/src/lmtp/lmtp.c
index 873ff982e..ab045c360 100644
--- a/postfix/src/lmtp/lmtp.c
+++ b/postfix/src/lmtp/lmtp.c
@@ -253,6 +253,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /* Single server skeleton. */
 
@@ -496,6 +497,11 @@ static void pre_init(char *unused_name, char **unused_argv)
 	msg_warn("%s is true, but SASL support is not compiled in",
 		 VAR_LMTP_SASL_ENABLE);
 #endif
+
+    /*
+     * flush client.
+     */
+    flush_init();
 }
 
 /* cleanup - close any open connections, etc. */
diff --git a/postfix/src/local/Makefile.in b/postfix/src/local/Makefile.in
index 28dc05001..732b788d9 100644
--- a/postfix/src/local/Makefile.in
+++ b/postfix/src/local/Makefile.in
@@ -310,6 +310,7 @@ local.o: ../../include/mail_conf.h
 local.o: ../../include/been_here.h
 local.o: ../../include/ext_prop.h
 local.o: ../../include/maps.h
+local.o: ../../include/flush_clnt.h
 local.o: ../../include/mail_server.h
 local.o: local.h
 local.o: ../../include/tok822.h
diff --git a/postfix/src/local/local.c b/postfix/src/local/local.c
index 6c8ac2460..37c4af8b5 100644
--- a/postfix/src/local/local.c
+++ b/postfix/src/local/local.c
@@ -473,6 +473,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /* Single server skeleton. */
 
@@ -708,6 +709,8 @@ static void pre_init(char *unused_name, char **unused_argv)
     }
     alias_maps = maps_create("aliases", var_alias_maps,
 			     DICT_FLAG_LOCK | DICT_FLAG_PARANOID);
+
+    flush_init();
 }
 
 /* main - pass control to the single-threaded skeleton */
diff --git a/postfix/src/oqmgr/Makefile.in b/postfix/src/oqmgr/Makefile.in
index 1e932b43e..714a9bc17 100644
--- a/postfix/src/oqmgr/Makefile.in
+++ b/postfix/src/oqmgr/Makefile.in
@@ -74,6 +74,7 @@ qmgr.o: ../../include/mail_proto.h
 qmgr.o: ../../include/iostuff.h
 qmgr.o: ../../include/attr.h
 qmgr.o: ../../include/mail_flow.h
+qmgr.o: ../../include/flush_clnt.h
 qmgr.o: ../../include/master_proto.h
 qmgr.o: ../../include/mail_server.h
 qmgr.o: qmgr.h
diff --git a/postfix/src/oqmgr/qmgr.c b/postfix/src/oqmgr/qmgr.c
index b1837bcd5..c7ce96afb 100644
--- a/postfix/src/oqmgr/qmgr.c
+++ b/postfix/src/oqmgr/qmgr.c
@@ -255,6 +255,7 @@
 #include 
 #include 			/* QMGR_SCAN constants */
 #include 
+#include 
 
 /* Master process interface */
 
@@ -437,6 +438,13 @@ static void pre_accept(char *unused_name, char **unused_argv)
     }
 }
 
+/* qmgr_pre_init - pre-jail initialization */
+
+static void qmgr_pre_init(char *unused_name, char **unused_argv)
+{
+    flush_init();
+}
+
 /* qmgr_post_init - post-jail initialization */
 
 static void qmgr_post_init(char *unused_name, char **unused_argv)
@@ -519,6 +527,7 @@ int     main(int argc, char **argv)
 			MAIL_SERVER_STR_TABLE, str_table,
 			MAIL_SERVER_BOOL_TABLE, bool_table,
 			MAIL_SERVER_TIME_TABLE, time_table,
+			MAIL_SERVER_PRE_INIT, qmgr_pre_init,
 			MAIL_SERVER_POST_INIT, qmgr_post_init,
 			MAIL_SERVER_LOOP, qmgr_loop,
 			MAIL_SERVER_PRE_ACCEPT, pre_accept,
diff --git a/postfix/src/pipe/Makefile.in b/postfix/src/pipe/Makefile.in
index d1063fcb2..0add8c3d0 100644
--- a/postfix/src/pipe/Makefile.in
+++ b/postfix/src/pipe/Makefile.in
@@ -83,4 +83,5 @@ pipe.o: ../../include/split_addr.h
 pipe.o: ../../include/off_cvt.h
 pipe.o: ../../include/quote_822_local.h
 pipe.o: ../../include/quote_flags.h
+pipe.o: ../../include/flush_clnt.h
 pipe.o: ../../include/mail_server.h
diff --git a/postfix/src/pipe/pipe.c b/postfix/src/pipe/pipe.c
index 64bc15e15..37cd48df4 100644
--- a/postfix/src/pipe/pipe.c
+++ b/postfix/src/pipe/pipe.c
@@ -279,6 +279,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /* Single server skeleton. */
 
@@ -998,6 +999,13 @@ static void drop_privileges(char *unused_name, char **unused_argv)
     set_eugid(var_owner_uid, var_owner_gid);
 }
 
+/* pre_init - initialize */
+
+static void pre_init(char *unused_name, char **unused_argv)
+{
+    flush_init();
+}
+
 /* main - pass control to the single-threaded skeleton */
 
 int     main(int argc, char **argv)
@@ -1009,6 +1017,7 @@ int     main(int argc, char **argv)
 
     single_server_main(argc, argv, pipe_service,
 		       MAIL_SERVER_TIME_TABLE, time_table,
+		       MAIL_SERVER_PRE_INIT, pre_init,
 		       MAIL_SERVER_POST_INIT, drop_privileges,
 		       MAIL_SERVER_PRE_ACCEPT, pre_accept,
 		       0);
diff --git a/postfix/src/postalias/postalias.c b/postfix/src/postalias/postalias.c
index 2df71cc5c..dca63c82a 100644
--- a/postfix/src/postalias/postalias.c
+++ b/postfix/src/postalias/postalias.c
@@ -397,6 +397,12 @@ static int postalias_queries(VSTREAM *in, char **maps, const int map_count,
 		   dict_open3(maps[n], map_name, O_RDONLY, DICT_FLAG_LOCK) :
 		dict_open3(var_db_type, maps[n], O_RDONLY, DICT_FLAG_LOCK));
 	    if ((value = dict_get(dicts[n], STR(keybuf))) != 0) {
+		if (*value == 0) {
+		    msg_warn("table %s:%s: key %s: empty string result is not allowed",
+			     dicts[n]->type, dicts[n]->name, STR(keybuf));
+		    msg_warn("table %s:%s should return NO RESULT in case of NOT FOUND",
+			     dicts[n]->type, dicts[n]->name);
+		}
 		vstream_printf("%s:	%s\n", STR(keybuf), value);
 		found = 1;
 		break;
@@ -428,6 +434,12 @@ static int postalias_query(const char *map_type, const char *map_name,
 
     dict = dict_open3(map_type, map_name, O_RDONLY, DICT_FLAG_LOCK);
     if ((value = dict_get(dict, key)) != 0) {
+	if (*value == 0) {
+	    msg_warn("table %s:%s: key %s: empty string result is not allowed",
+		     map_type, map_name, key);
+	    msg_warn("table %s:%s should return NO RESULT in case of NOT FOUND",
+		     map_type, map_name);
+	}
 	vstream_printf("%s\n", value);
 	vstream_fflush(VSTREAM_OUT);
     }
diff --git a/postfix/src/postmap/postmap.c b/postfix/src/postmap/postmap.c
index 03aa9ed5a..66b2b5da7 100644
--- a/postfix/src/postmap/postmap.c
+++ b/postfix/src/postmap/postmap.c
@@ -345,6 +345,12 @@ static int postmap_queries(VSTREAM *in, char **maps, const int map_count,
 		   dict_open3(maps[n], map_name, O_RDONLY, DICT_FLAG_LOCK) :
 		dict_open3(var_db_type, maps[n], O_RDONLY, DICT_FLAG_LOCK));
 	    if ((value = dict_get(dicts[n], STR(keybuf))) != 0) {
+		if (*value == 0) {
+		    msg_warn("table %s:%s: key %s: empty string result is not allowed",
+			     dicts[n]->type, dicts[n]->name, STR(keybuf));
+		    msg_warn("table %s:%s should return NO RESULT in case of NOT FOUND",
+			     dicts[n]->type, dicts[n]->name);
+		}
 		vstream_printf("%s	%s\n", STR(keybuf), value);
 		found = 1;
 		break;
@@ -376,6 +382,12 @@ static int postmap_query(const char *map_type, const char *map_name,
 
     dict = dict_open3(map_type, map_name, O_RDONLY, DICT_FLAG_LOCK);
     if ((value = dict_get(dict, key)) != 0) {
+	if (*value == 0) {
+	    msg_warn("table %s:%s: key %s: empty string result is not allowed",
+		     map_type, map_name, key);
+	    msg_warn("table %s:%s should return NO RESULT in case of NOT FOUND",
+		     map_type, map_name);
+	}
 	vstream_printf("%s\n", value);
 	vstream_fflush(VSTREAM_OUT);
     }
diff --git a/postfix/src/qmgr/Makefile.in b/postfix/src/qmgr/Makefile.in
index 4926d1e40..9fd75b80f 100644
--- a/postfix/src/qmgr/Makefile.in
+++ b/postfix/src/qmgr/Makefile.in
@@ -76,6 +76,7 @@ qmgr.o: ../../include/mail_proto.h
 qmgr.o: ../../include/iostuff.h
 qmgr.o: ../../include/attr.h
 qmgr.o: ../../include/mail_flow.h
+qmgr.o: ../../include/flush_clnt.h
 qmgr.o: ../../include/master_proto.h
 qmgr.o: ../../include/mail_server.h
 qmgr.o: qmgr.h
diff --git a/postfix/src/qmgr/qmgr.c b/postfix/src/qmgr/qmgr.c
index e6adb235a..5a7ced9ae 100644
--- a/postfix/src/qmgr/qmgr.c
+++ b/postfix/src/qmgr/qmgr.c
@@ -300,6 +300,7 @@
 #include 
 #include 			/* QMGR_SCAN constants */
 #include 
+#include 
 
 /* Master process interface */
 
@@ -485,6 +486,13 @@ static void pre_accept(char *unused_name, char **unused_argv)
     }
 }
 
+/* qmgr_pre_init - pre-jail initialization */
+
+static void qmgr_pre_init(char *unused_name, char **unused_argv)
+{
+    flush_init();
+}
+
 /* qmgr_post_init - post-jail initialization */
 
 static void qmgr_post_init(char *name, char **unused_argv)
@@ -583,6 +591,7 @@ int     main(int argc, char **argv)
 			MAIL_SERVER_STR_TABLE, str_table,
 			MAIL_SERVER_BOOL_TABLE, bool_table,
 			MAIL_SERVER_TIME_TABLE, time_table,
+			MAIL_SERVER_PRE_INIT, qmgr_pre_init,
 			MAIL_SERVER_POST_INIT, qmgr_post_init,
 			MAIL_SERVER_LOOP, qmgr_loop,
 			MAIL_SERVER_PRE_ACCEPT, pre_accept,
diff --git a/postfix/src/smtp/Makefile.in b/postfix/src/smtp/Makefile.in
index 771e3c0bb..609123a10 100644
--- a/postfix/src/smtp/Makefile.in
+++ b/postfix/src/smtp/Makefile.in
@@ -75,6 +75,7 @@ smtp.o: ../../include/recipient_list.h
 smtp.o: ../../include/mail_params.h
 smtp.o: ../../include/mail_conf.h
 smtp.o: ../../include/debug_peer.h
+smtp.o: ../../include/flush_clnt.h
 smtp.o: ../../include/mail_server.h
 smtp.o: smtp.h
 smtp.o: smtp_sasl.h
diff --git a/postfix/src/smtp/smtp.c b/postfix/src/smtp/smtp.c
index a427164f0..824533d9b 100644
--- a/postfix/src/smtp/smtp.c
+++ b/postfix/src/smtp/smtp.c
@@ -282,6 +282,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /* Single server skeleton. */
 
@@ -452,6 +453,11 @@ static void pre_init(char *unused_name, char **unused_argv)
 	msg_warn("%s is true, but SASL support is not compiled in",
 		 VAR_SMTP_SASL_ENABLE);
 #endif
+
+    /*
+     * Flush client.
+     */
+    flush_init();
 }
 
 /* pre_accept - see if tables have changed */
diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c
index eefca9892..f3207f462 100644
--- a/postfix/src/smtpd/smtpd.c
+++ b/postfix/src/smtpd/smtpd.c
@@ -469,6 +469,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /* Single-threaded server skeleton. */
 
@@ -1266,12 +1267,17 @@ static int rcpt_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
 
     /*
      * Store the recipient. Remember the first one.
+     * 
+     * Flush recipients to maintain a stiffer coupling with the next stage and
+     * to better utilize parallelism.
      */
     state->rcpt_count++;
     if (state->recipient == 0)
 	state->recipient = mystrdup(argv[2].strval);
-    if (state->cleanup)
+    if (state->cleanup) {
 	rec_fputs(state->cleanup, REC_TYPE_RCPT, argv[2].strval);
+	vstream_fflush(state->cleanup);
+    }
     smtpd_chat_reply(state, "250 Ok");
     return (0);
 }
@@ -2396,6 +2402,11 @@ static void pre_jail_init(char *unused_name, char **unused_argv)
 	msg_warn("%s is true, but SASL support is not compiled in",
 		 VAR_SMTPD_SASL_ENABLE);
 #endif
+
+    /*
+     * flush client.
+     */
+    flush_init();
 }
 
 /* post_jail_init - post-jail initialization */
diff --git a/postfix/src/util/dict_open.c b/postfix/src/util/dict_open.c
index 2cc1e34e9..ec21b8e03 100644
--- a/postfix/src/util/dict_open.c
+++ b/postfix/src/util/dict_open.c
@@ -191,7 +191,9 @@ typedef struct {
 static DICT_OPEN_INFO dict_open_info[] = {
     DICT_TYPE_ENVIRON, dict_env_open,
     DICT_TYPE_UNIX, dict_unix_open,
+#ifdef SNAPSHOT
     DICT_TYPE_TCP, dict_tcp_open,
+#endif
 #ifdef HAS_DBM
     DICT_TYPE_DBM, dict_dbm_open,
 #endif
diff --git a/postfix/src/virtual/Makefile.in b/postfix/src/virtual/Makefile.in
index e439102f9..fda53bd6d 100644
--- a/postfix/src/virtual/Makefile.in
+++ b/postfix/src/virtual/Makefile.in
@@ -162,6 +162,7 @@ virtual.o: ../../include/mail_params.h
 virtual.o: ../../include/mail_conf.h
 virtual.o: ../../include/mail_addr_find.h
 virtual.o: ../../include/maps.h
+virtual.o: ../../include/flush_clnt.h
 virtual.o: ../../include/mail_server.h
 virtual.o: virtual.h
 virtual.o: ../../include/mbox_conf.h
diff --git a/postfix/src/virtual/virtual.c b/postfix/src/virtual/virtual.c
index 224fd3c5d..5b85109a0 100644
--- a/postfix/src/virtual/virtual.c
+++ b/postfix/src/virtual/virtual.c
@@ -312,6 +312,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /* Single server skeleton. */
 
@@ -476,6 +477,11 @@ static void pre_init(char *unused_name, char **unused_argv)
 		      VAR_VIRT_MAILBOX_LIMIT, VAR_MESSAGE_LIMIT);
 	set_file_limit(var_virt_mailbox_limit);
     }
+
+    /*
+     * flush client.
+     */
+    flush_init();
 }
 
 /* main - pass control to the single-threaded skeleton */