summaryrefslogtreecommitdiffstats
path: root/html/MILTER_README.html
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 19:59:03 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 19:59:03 +0000
commita848231ae0f346dc7cc000973fbeb65b0894ee92 (patch)
tree44b60b367c86723cc78383ef247885d72b388afe /html/MILTER_README.html
parentInitial commit. (diff)
downloadpostfix-a848231ae0f346dc7cc000973fbeb65b0894ee92.tar.xz
postfix-a848231ae0f346dc7cc000973fbeb65b0894ee92.zip
Adding upstream version 3.8.5.upstream/3.8.5
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--html/MILTER_README.html1003
1 files changed, 1003 insertions, 0 deletions
diff --git a/html/MILTER_README.html b/html/MILTER_README.html
new file mode 100644
index 0000000..c69a5bf
--- /dev/null
+++ b/html/MILTER_README.html
@@ -0,0 +1,1003 @@
+<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+
+<html>
+
+<head>
+
+<title>Postfix before-queue Milter support </title>
+
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<link rel='stylesheet' type='text/css' href='postfix-doc.css'>
+
+</head>
+
+<body>
+
+<h1><img src="postfix-logo.jpg" width="203" height="98" ALT="">Postfix before-queue Milter support </h1>
+
+<hr>
+
+<h2>Introduction</h2>
+
+<p> Postfix implements support for the Sendmail version 8 Milter
+(mail filter) protocol. This protocol is used by applications that
+run outside the MTA to inspect SMTP events (CONNECT, DISCONNECT),
+SMTP commands (HELO, MAIL FROM, etc.) as well as mail content
+(headers and body). All this happens before mail is queued. </p>
+
+<p> The reason for adding Milter support to Postfix is that there
+exists a large collection of applications, not only to block unwanted
+mail, but also to verify authenticity (examples: <a
+href="http://www.opendkim.org/">OpenDKIM</a> and <a
+href="http://www.trusteddomain.org/opendmarc/">DMARC </a>)
+or to digitally sign mail (example: <a
+href="http://www.opendkim.org/">OpenDKIM</a>).
+Having yet another Postfix-specific version of all that software
+is a poor use of human and system resources. </p>
+
+<p> The Milter protocol has evolved over time, and different Postfix
+versions implement different feature sets. See the <a
+href="#workarounds">workarounds</a> and <a
+href="#limitations">limitations</a> sections at the end of this
+document for differences between Postfix and Sendmail implementations.
+</p>
+
+<p> This document provides information on the following topics: </p>
+
+<ul>
+
+<li><a href="#plumbing">How Milter applications plug into Postfix </a>
+
+<li><a href="#when-inspect">When Postfix and Milters inspect an
+SMTP session </a>
+
+<li><a href="#building">Building Milter applications</a>
+
+<li><a href="#running">Running Milter applications</a>
+
+<li><a href="#config">Configuring Postfix</a>
+
+<li><a href="#workarounds">Workarounds</a>
+
+<li><a href="#limitations">Limitations</a>
+
+</ul>
+
+<h2><a name="plumbing">How Milter applications plug into Postfix </a> </h2>
+
+<p> The Postfix Milter implementation uses two different lists of
+mail filters: one list of filters for SMTP mail only,
+and one list of filters for non-SMTP mail. The two
+lists have different capabilities, which is unfortunate. Avoiding
+this would require major restructuring of Postfix. </p>
+
+<ul>
+
+<li> <p> The SMTP-only filters handle mail that arrives via the
+Postfix <a href="smtpd.8.html">smtpd(8)</a> server. They are typically used to filter unwanted
+mail and to sign mail from authorized SMTP clients. You specify
+SMTP-only Milter applications with the <a href="postconf.5.html#smtpd_milters">smtpd_milters</a> parameter as
+described in a later section. Mail that arrives via the Postfix
+<a href="smtpd.8.html">smtpd(8)</a> server is not filtered by the non-SMTP filters that are
+described next. </p>
+
+<li> <p> The non-SMTP filters handle mail that arrives via the
+Postfix <a href="sendmail.1.html">sendmail(1)</a> command-line or via the Postfix <a href="qmqpd.8.html">qmqpd(8)</a> server.
+They are typically used to digitally sign mail only. Although
+non-SMTP filters can be used to filter unwanted mail, they have
+limitations compared to the SMTP-only filters. You specify non-SMTP
+Milter applications with the <a href="postconf.5.html#non_smtpd_milters">non_smtpd_milters</a> parameter as described
+in a later section. </p>
+
+</ul>
+
+<p> For those who are familiar with the Postfix architecture, the
+figure below shows how Milter applications plug into Postfix. Names
+followed by a number are Postfix commands or server programs, while
+unnumbered names inside shaded areas represent Postfix queues. To
+avoid clutter, the path for local submission is simplified (the
+<a href="OVERVIEW.html">OVERVIEW</a> document has a more complete description of the Postfix
+architecture). </p>
+
+<blockquote>
+
+<table>
+
+<tr>
+
+<td colspan="2"> </td>
+
+<td align="center"> SMTP-only <br> filters </td>
+
+<td> </td>
+
+<td align="center"> non-SMTP <br> filters </td>
+
+</tr>
+
+<tr>
+
+<td colspan="2"> </td>
+
+<td align="center"> <table> <tr> <td align="center">
+^<br> <tt> | </tt> </td> <td align="center"> <tt> |<br> v </tt>
+</td> </tr> </table> </td>
+
+<td rowspan="2"> </td>
+
+<td rowspan="3" align="center"> <table> <tr> <td align="center">
+^<br> <tt> |<br> |<br> | </tt> </td> <td align="center"> <tt> |<br>
+|<br> |<br> v </tt> </td> </tr> </table> </td>
+
+</tr>
+
+<tr>
+
+<td> Network </td> <td> <tt> -&gt; </tt> </td>
+
+<td bgcolor="#f0f0ff" align="center" valign="middle"> <a href="smtpd.8.html">smtpd(8)</a>
+</td>
+
+</tr>
+
+<tr>
+
+<td colspan="3"> </td> <td> <tt> \ </tt> </td>
+
+</tr>
+
+<tr>
+
+<td> Network </td> <td> <tt> -&gt; </tt> </td>
+
+<td bgcolor="#f0f0ff" align="center" valign="middle"> <a href="qmqpd.8.html">qmqpd(8)</a>
+</td>
+
+<td> <tt> -&gt; </tt> </td>
+
+<td bgcolor="#f0f0ff" align="center" valign="middle"> <a href="cleanup.8.html">cleanup(8)</a>
+</td>
+
+<td> <tt> -&gt; </tt> </td>
+
+<td bgcolor="#f0f0ff" align="center" valign="middle"> <a
+href="QSHAPE_README.html#incoming_queue"> incoming </a> </td>
+
+</tr>
+
+<tr>
+
+<td colspan="3"> </td> <td> <tt> / </tt> </td>
+
+</tr>
+
+<tr>
+
+<td colspan="2"> </td>
+
+<td bgcolor="#f0f0ff" align="center" valign="middle"> <a href="pickup.8.html">pickup(8)</a>
+</td>
+
+</tr>
+
+<tr> <td colspan="2"> </td> <td align="center"> : </td> </tr>
+
+<tr>
+
+<td> Local </td> <td> <tt> -&gt; </tt> </td>
+
+<td bgcolor="#f0f0ff" align="center" valign="middle"> <a href="sendmail.1.html">sendmail(1)</a>
+</td>
+
+</tr>
+
+</table>
+
+</blockquote>
+
+<h2><a name="when-inspect">When Postfix and Milters inspect an SMTP
+session </a></h2>
+
+<p> Generally, Postfix inspects information first, then the first
+configured Milter, the second configured Milter, and so on. </p>
+
+<ul>
+
+<li><p> With most SMTP commands: Postfix reviews one SMTP command,
+and if Postfix does not reject it, Postfix passes the command to
+the first configured Milter. If the first Milter does not reject
+the command, Postfix passes it to the second configured Milter, and
+so on. This includes commands with an envelope sender (MAIL FROM)
+or envelope recipient (RCPT TO). Postfix stores the same envelope
+records in a queue file as when no Milters are configured, including
+rewritten envelope addresses, expanded virtual aliases, BCC addresses
+from sender/recipient_bcc_maps, and so on. </p>
+
+<li><p> With header/body content: Postfix may rewrite or reject
+header/body content before it stores that content in the queue file;
+Postfix stores the same header/body content as when no Milters are
+configured. If Postfix does not reject the header/body content,
+Postfix passes it to the first configured Milter which may modify
+or reject that content or may modify the stored envelope. If the
+first Milter does not reject the header/body content, Postfix passes
+it to the second configured Milter, and so on. </p>
+
+</ul>
+
+<p> Details: </p>
+
+<ul>
+
+<li><p> Postfix hides its own Postfix-prepended Received: header, for
+compatibility with Sendmail. Postfix does not hide other headers that
+Postfix or Milters added or modified. </p>
+
+
+<li><p> When the Postfix SMTP server receives a sequence of one or
+more valid BDAT commands, it generates one DATA command for the
+Milters. </p>
+
+<li><p> The Milter API does not support inspection of SMTP commands
+such as QUIT, NOOP, or VRFY; the API supports only commands that are
+needed for email delivery. <p>
+
+</ul>
+
+<h2><a name="building">Building Milter applications</a></h2>
+
+<p> Milter applications have been written in C, Haskell, Java, Perl,
+Python, Rust, and more, but
+this document covers C applications only. For these, you need
+an object library that implements the Sendmail 8 Milter protocol.
+Postfix currently does not provide such a library, but Sendmail
+does. </p>
+
+<p> Some
+systems install the Sendmail libmilter library by default. With
+other systems, libmilter may be provided by a package (called
+"sendmail-devel" on some Linux systems). </p>
+
+<p> Once libmilter is installed, applications such as <a
+href="http://www.opendkim.org/">OpenDKIM</a> and
+<a href="http://www.trusteddomain.org/opendmarc/">OpenDMARC</a>
+build out of the box without requiring any tinkering:</p>
+
+<blockquote>
+<pre>
+$ <b>gzcat opendkim-<i>x.y.z</i>.tar.gz | tar xf -</b>
+$ <b>cd opendkim-<i>x.y.z</i></b>
+$ <b>./configure ...<i>options</i>...</b>
+$ <b>make</b>
+[...<i>lots of output omitted</i>...]
+$ <b>make install</b>
+</pre>
+</blockquote>
+
+<h2><a name="running">Running Milter applications</a></h2>
+
+<p> To run a Milter application, see the documentation of the filter
+for options. A typical command looks like this:</p>
+
+<blockquote>
+<pre>
+# <b>/some/where/opendkim -l -u <i>userid</i> -p inet:<i>portnumber</i>@localhost ...<i>other options</i>...</b>
+</pre>
+</blockquote>
+
+<p> Please specify a <i>userid</i> value that isn't used for other
+applications (not "postfix", not "www", etc.). </p>
+
+<h2><a name="config">Configuring Postfix</a></h2>
+
+<p> Like Sendmail, Postfix has a lot of configuration options that
+control how it talks to Milter applications. Besides global options
+that apply to all Milter applications, Postfix 3.0 and later
+support per-Milter timeouts, per-Milter error handling, etc. </p>
+
+<p> Information in this section: </p>
+
+<ul>
+
+<li><a href="#smtp-only-milters">SMTP-Only Milter applications </a>
+
+<li><a href="#non-smtp-milters">Non-SMTP Milter applications </a>
+
+<li><a href="#errors">Milter error handling </a>
+
+<li><a href="#version">Milter protocol version</a>
+
+<li><a href="#timeouts">Milter protocol timeouts</a>
+
+<li><a href="#per-milter">Different settings for different Milter
+applications </a>
+
+<li><a href="#per-client">Different settings for different SMTP
+clients </a>
+
+<li><a href="#macros">Sendmail macro emulation</a>
+
+<li><a href="#send-macros">What macros will Postfix send to Milters?</a>
+
+</ul>
+
+<h3><a name="smtp-only-milters">SMTP-Only Milter applications</a></h3>
+
+<p> The SMTP-only Milter applications handle mail that arrives via
+the Postfix <a href="smtpd.8.html">smtpd(8)</a> server. They are typically used to filter
+unwanted mail, and to sign mail from authorized SMTP clients. Mail
+that arrives via the Postfix <a href="smtpd.8.html">smtpd(8)</a> server is not filtered by the
+non-SMTP filters that are described in the next section. </p>
+
+<blockquote> NOTE for Postfix versions that have a <a href="postconf.5.html#mail_release_date">mail_release_date</a>
+before 20141018: do not use the <a href="header_checks.5.html">header_checks(5)</a> IGNORE action to remove
+Postfix's own Received: message header. This causes problems with
+mail signing filters. Instead, keep Postfix's own Received: message
+header and use the <a href="header_checks.5.html">header_checks(5)</a> REPLACE action to sanitize
+information. </blockquote>
+
+<p> You specify SMTP-only Milter applications (there can be more
+than one) with the <a href="postconf.5.html#smtpd_milters">smtpd_milters</a> parameter. Each Milter application
+is identified by the name of its listening socket; other Milter
+configuration options will be discussed in later sections. Postfix
+sends commands to each Milter application in the order as configured
+with <a href="postconf.5.html#smtpd_milters">smtpd_milters</a>. When a Milter application rejects a command,
+that will override responses from other Milter applications. </p>
+
+<blockquote>
+<pre>
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
+ # Milters for mail that arrives via the <a href="smtpd.8.html">smtpd(8)</a> server.
+ # See below for socket address syntax.
+ <a href="postconf.5.html#smtpd_milters">smtpd_milters</a> = inet:localhost:<i>portnumber</i> ...<i>other filters</i>...
+</pre>
+</blockquote>
+
+<p> The general syntax for listening sockets is as follows: </p>
+
+<blockquote>
+
+<dl>
+
+<dt> <b>unix:</b><i>pathname</i> </dt> <dd><p>Connect to the local
+UNIX-domain server that is bound to the specified pathname. If the
+<a href="smtpd.8.html">smtpd(8)</a> or <a href="cleanup.8.html">cleanup(8)</a> process runs chrooted, an absolute pathname
+is interpreted relative to the Postfix queue directory. On many
+systems, <b>local</b> is a synonym for <b>unix</b></p> </dd>
+
+<dt> <b> inet:</b><i>host</i><b>:</b><i>port</i> </dt> <dd> <p>
+Connect to the specified TCP port on the specified local or remote
+host. The host and port can be specified in numeric or symbolic
+form.</p>
+
+<p> NOTE: Postfix syntax differs from Milter syntax which has the
+form <b>inet:</b><i>port</i><b>@</b><i>host</i>. </p> </dd>
+
+</dl>
+
+</blockquote>
+
+<p> For advanced configuration see "<a href="#per-client">Different
+settings for different SMTP clients</a>" and "<a
+href="#per-milter">Different settings for different Milter
+applications</a>". </p>
+
+<h3> <a name="non-smtp-milters">Non-SMTP Milter applications </a> </h3>
+
+<p> The non-SMTP Milter applications handle mail that arrives via
+the Postfix <a href="sendmail.1.html">sendmail(1)</a> command-line or via the Postfix <a href="qmqpd.8.html">qmqpd(8)</a>
+server. They are typically used to digitally sign mail. Although
+non-SMTP filters can be used to filter unwanted mail, there are
+limitations as discussed later in this section. Mail that arrives
+via the Postfix <a href="smtpd.8.html">smtpd(8)</a> server is not filtered by the non-SMTP
+filters. </p>
+
+<p> NOTE: Do not use the <a href="header_checks.5.html">header_checks(5)</a> IGNORE action to remove
+Postfix's own Received: message header. This causes problems with
+mail signing filters. Instead, keep Postfix's own Received: message
+header and use the <a href="header_checks.5.html">header_checks(5)</a> REPLACE action to sanitize
+information. </p>
+
+<p> You specify non-SMTP Milter applications with the <a href="postconf.5.html#non_smtpd_milters">non_smtpd_milters</a>
+parameter. This parameter uses the same syntax as the <a href="postconf.5.html#smtpd_milters">smtpd_milters</a>
+parameter in the previous section. As with the SMTP-only filters,
+you can specify more than one Milter application. Postfix sends
+commands to each Milter application in the order as configured with
+<a href="postconf.5.html#non_smtpd_milters">non_smtpd_milters</a>. When a Milter application rejects a command,
+that will override responses from other Milter applications. </p>
+
+<blockquote>
+<pre>
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
+ # Milters for non-SMTP mail.
+ # See below for socket address syntax.
+ <a href="postconf.5.html#non_smtpd_milters">non_smtpd_milters</a> = inet:localhost:<i>portnumber</i> ...<i>other filters</i>...
+</pre>
+</blockquote>
+
+<p> There's one small complication when using Milter applications
+for non-SMTP mail: there is no SMTP session. To keep Milter
+applications happy, the Postfix <a href="cleanup.8.html">cleanup(8)</a> server actually has to
+simulate the SMTP client CONNECT and DISCONNECT events, and the
+SMTP client EHLO, MAIL FROM, RCPT TO and DATA commands. </p>
+
+<ul>
+
+<li> <p> When new mail arrives via the <a href="sendmail.1.html">sendmail(1)</a> command line,
+the Postfix <a href="cleanup.8.html">cleanup(8)</a> server pretends that the mail arrives with
+ESMTP from "localhost" with IP address "127.0.0.1". The result is
+very similar to what happens with command line submissions in
+Sendmail version 8.12 and later, although Sendmail uses a different
+mechanism to achieve this result. </p>
+
+<li> <p> When new mail arrives via the <a href="qmqpd.8.html">qmqpd(8)</a> server, the Postfix
+<a href="cleanup.8.html">cleanup(8)</a> server pretends that the mail arrives with ESMTP, and
+uses the QMQPD client hostname and IP address. </p>
+
+<li> <p> When old mail is re-injected into the queue with "postsuper
+-r", the Postfix <a href="cleanup.8.html">cleanup(8)</a> server uses the same client information
+that was used when the mail arrived as new mail. </p>
+
+</ul>
+
+<p> This generally works as expected, with only one exception:
+non-SMTP filters must not REJECT or TEMPFAIL simulated RCPT TO
+commands. When a <a href="postconf.5.html#non_smtpd_milters">non_smtpd_milters</a> application REJECTs or TEMPFAILs
+a recipient, Postfix will report a configuration error, and mail
+will stay in the queue. </p>
+
+<h4> Signing internally-generated bounce messages </h4>
+
+<p> Postfix normally does not apply content filters to mail
+that is generated internally such as bounces or Postmaster
+notifications. Filtering internally-generated bounces would result
+in loss of mail when a filter rejects a message, as the resulting
+double-bounce message would almost certainly also be blocked. </p>
+
+<p> To sign Postfix's own bounce messages, enable filtering of
+internally-generated bounces (line 2 below), and don't reject any
+internally-generated bounces with <a href="postconf.5.html#non_smtpd_milters">non_smtpd_milters</a>, <a href="postconf.5.html#header_checks">header_checks</a>
+or <a href="postconf.5.html#body_checks">body_checks</a> (lines 3-5 below). </p>
+
+<blockquote>
+<pre>
+1 /etc/postfix/<a href="postconf.5.html">main.cf</a>:
+2 <a href="postconf.5.html#internal_mail_filter_classes">internal_mail_filter_classes</a> = bounce
+3 <a href="postconf.5.html#non_smtpd_milters">non_smtpd_milters</a> = <i>don't reject internally-generated bounces</i>
+4 <a href="postconf.5.html#header_checks">header_checks</a> = <i>don't reject internally-generated bounces</i>
+5 <a href="postconf.5.html#body_checks">body_checks</a> = <i>don't reject internally-generated bounces</i>
+</pre>
+</blockquote>
+
+<h3><a name="errors">Milter error handling</a></h3>
+
+<p> The <a href="postconf.5.html#milter_default_action">milter_default_action</a> parameter specifies how Postfix handles
+Milter application errors. The default action is to respond with a
+temporary error status, so that the client will try again later.
+Specify "accept" if you want to receive mail as if the filter does
+not exist, and "reject" to reject mail with a permanent status.
+The "quarantine" action is like "accept" but freezes the message
+in the "<a href="QSHAPE_README.html#hold_queue">hold" queue</a>, and is available with Postfix 2.6 or later.
+</p>
+
+<blockquote>
+<pre>
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
+ # What to do in case of errors? Specify accept, reject, tempfail,
+ # or quarantine (Postfix 2.6 or later).
+ <a href="postconf.5.html#milter_default_action">milter_default_action</a> = tempfail
+</pre>
+</blockquote>
+
+<p> See "<a href="#per-milter">Different settings for different
+Milter applications</a>" for advanced configuration options. </p>
+
+<h3><a name="version">Milter protocol version</a></h3>
+
+<p> As Postfix is not built with the Sendmail libmilter library,
+you may need to configure the Milter protocol version that Postfix
+should use. The default version is 6 (before Postfix 2.6 the default
+version is 2). </p>
+
+<blockquote>
+<pre>
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
+ # Postfix &ge; 2.6
+ <a href="postconf.5.html#milter_protocol">milter_protocol</a> = 6
+ # 2.3 &le; Postfix &le; 2.5
+ <a href="postconf.5.html#milter_protocol">milter_protocol</a> = 2
+</pre>
+</blockquote>
+
+<p> If the Postfix <a href="postconf.5.html#milter_protocol">milter_protocol</a> setting specifies a too low
+version, the libmilter library will log an error message like this:
+</p>
+
+<blockquote>
+<pre>
+<i>application name</i>: st_optionneg[<i>xxxxx</i>]: 0x<i>yy</i> does not fulfill action requirements 0x<i>zz</i>
+</pre>
+</blockquote>
+
+<p> The remedy is to increase the Postfix <a href="postconf.5.html#milter_protocol">milter_protocol</a> version
+number. See, however, the <a href="#limitations">limitations</a>
+section below for features that aren't supported by Postfix. </p>
+
+<p> With Postfix 2.7 and earlier, if the Postfix <a href="postconf.5.html#milter_protocol">milter_protocol</a>
+setting specifies a too high
+version, the libmilter library simply hangs up without logging a
+warning, and you see a Postfix warning message like one of the
+following: </p>
+
+<blockquote>
+<pre>
+warning: milter inet:<i>host</i>:<i>port</i>: can't read packet header: Unknown error : 0
+warning: milter inet:<i>host</i>:<i>port</i>: can't read packet header: Success
+warning: milter inet:<i>host</i>:<i>port</i>: can't read SMFIC_DATA reply packet header: No such file or directory
+</pre>
+</blockquote>
+
+<p> The remedy is to lower the Postfix <a href="postconf.5.html#milter_protocol">milter_protocol</a> version
+number. Postfix 2.8 and later will automatically turn off protocol
+features that the application's libmilter library does not expect.
+</p>
+
+<p> See "<a href="#per-milter">Different settings for different
+Milter applications</a>" for advanced configuration options. </p>
+
+<h3><a name="timeouts">Milter protocol timeouts</a></h3>
+
+<p> Postfix uses different time limits at different Milter protocol
+stages. The table shows the timeout settings and the corresponding
+protocol stages
+(EOH = end of headers; EOM = end of message). </p>
+
+<blockquote>
+
+<table border="1">
+
+<tr> <th> Postfix parameter </th> <th> Time limit </th> <th> Milter
+protocol stage</th> </tr>
+
+<tr> <td> <a href="postconf.5.html#milter_connect_timeout">milter_connect_timeout</a> </td> <td> 30s </td> <td> CONNECT
+</td> </tr>
+
+<tr> <td> <a href="postconf.5.html#milter_command_timeout">milter_command_timeout</a> </td> <td> 30s </td> <td> HELO,
+MAIL, RCPT, DATA, UNKNOWN </td> </tr>
+
+<tr> <td> <a href="postconf.5.html#milter_content_timeout">milter_content_timeout</a> </td> <td> 300s </td> <td> HEADER,
+EOH, BODY, EOM </td> </tr>
+
+</table>
+
+</blockquote>
+
+<p> Beware: 30s may be too short for Milter applications that do
+lots of DNS lookups. However, if you increase the above timeouts
+too much, remote SMTP clients may hang up and mail may be delivered
+multiple times. This is an inherent problem with before-queue
+filtering. </p>
+
+<p> See "<a href="#per-milter">Different settings for different
+Milter applications</a>" for advanced configuration options. </p>
+
+<h3><a name="per-milter">Different settings for different Milter
+applications </a></h3>
+
+<p> The previous sections list a number of Postfix <a href="postconf.5.html">main.cf</a> parameters
+that control time limits and other settings for all Postfix Milter
+clients. This is sufficient for simple configurations. With more
+complex configurations it becomes desirable to have different
+settings for different Milter clients. This is supported with Postfix
+3.0 and later. </p>
+
+<p> The following example shows a "non-critical" Milter client with
+a short connect timeout, and with "accept" as default action when
+the service is unvailable. </p>
+
+<blockquote>
+<pre>
+1 /etc/postfix/<a href="postconf.5.html">main.cf</a>:
+2 <a href="postconf.5.html#smtpd_milters">smtpd_milters</a> = { inet:host:port,
+3 connect_timeout=10s, default_action=accept }
+</pre>
+</blockquote>
+
+<p> Instead of a server endpoint, we now have a list enclosed in {}. </p>
+
+<ul>
+
+<li> <p> Line 2: The first item in the list is the server endpoint.
+This supports the exact same "inet" and "unix" syntax as described
+earlier. </p>
+
+<li> <p> Line 3: The remainder of the list contains per-Milter
+settings. These settings override global <a href="postconf.5.html">main.cf</a> parameters, and
+have the same name as those parameters, without the "milter_" prefix.
+The per-Milter settings that are supported as of Postfix 3.0 are
+command_timeout, connect_timeout, content_timeout, default_action,
+and protocol. </p>
+
+</ul>
+
+<p> Inside the list, syntax is similar to what we already know from
+<a href="postconf.5.html">main.cf</a>: items separated by space or comma. There is one difference:
+<b>you must enclose a setting in parentheses, as in "{ name = value
+}", if you want to have space or comma within a value or around
+"="</b>. </p>
+
+<h3><a name="per-client">Different settings for different SMTP
+clients </a></h3>
+
+<p> The <a href="postconf.5.html#smtpd_milter_maps">smtpd_milter_maps</a> feature supports different Milter settings
+for different client IP addresses. Lookup results override the the
+global <a href="postconf.5.html#smtpd_milters">smtpd_milters</a> setting, and have the same syntax. For example,
+to disable Milter settings for local address ranges: </p>
+
+<pre>
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
+ <a href="postconf.5.html#smtpd_milter_maps">smtpd_milter_maps</a> = <a href="cidr_table.5.html">cidr</a>:/etc/postfix/smtpd_milter_map
+ <a href="postconf.5.html#smtpd_milters">smtpd_milters</a> = inet:host:port, { inet:host:port, ... }, ...
+
+/etc/postfix/smtpd_milter_map:
+ # Disable Milters for local clients.
+ 127.0.0.0/8 DISABLE
+ 192.168.0.0/16 DISABLE
+ ::/64 DISABLE
+ 2001:db8::/32 DISABLE
+</pre>
+
+<p> This feature is available with Postfix 3.2 and later. </p>
+
+<h3><a name="macros">Sendmail macro emulation</a></h3>
+
+<p> Postfix emulates a limited number of Sendmail macros, as shown
+in the table. Some macro values depend on whether a recipient is
+rejected (rejected recipients are available on request by the Milter
+application). Different macros are available at different Milter
+protocol stages (EOH = end-of-header, EOM = end-of-message); their
+availability is not
+always the same as in Sendmail. See the <a
+href="#workarounds">workarounds</a> section below for solutions.
+</p>
+
+<blockquote>
+
+<table border="1">
+
+<tr> <th> Sendmail macro </th> <th> Milter protocol stage </th>
+<th> Description </th> </tr>
+
+<tr> <td> i </td> <td> DATA, EOH, EOM </td> <td> Queue ID, also
+Postfix queue file name </td> </tr>
+
+<tr> <td> j </td> <td> Always </td> <td> Value of <a href="postconf.5.html#myhostname">myhostname</a> </td>
+</tr>
+
+<tr> <td> _ </td> <td> Always </td> <td> The validated client name
+and address </td> </tr>
+
+<tr> <td> {auth_authen} </td> <td> MAIL, DATA, EOH, EOM </td> <td> SASL
+login name </td> </tr>
+
+<tr> <td> {auth_author} </td> <td> MAIL, DATA, EOH, EOM </td> <td> SASL
+sender </td> </tr>
+
+<tr> <td> {auth_type} </td> <td> MAIL, DATA, EOH, EOM </td> <td> SASL
+login method </td> </tr>
+
+<tr> <td> {client_addr} </td> <td> Always </td> <td> Remote client
+IP address </td> </tr>
+
+<tr> <td> {client_connections} </td> <td> CONNECT </td> <td>
+Connection concurrency for this client (zero if the client is
+excluded from all smtpd_client_* limits). </td> </tr>
+
+<tr> <td> {client_name} </td> <td> Always </td> <td> Remote client
+hostname <br> When address &rarr; name lookup or name &rarr; address
+verification fails: "unknown" </td> </tr>
+
+<tr> <td> {client_port} </td> <td> Always (Postfix &ge;2.5) </td>
+<td> Remote client TCP port </td> </tr>
+
+<tr> <td> {client_ptr} </td> <td> CONNECT, HELO, MAIL, DATA </td>
+<td> Client name from address &rarr; name lookup <br> When address
+&rarr; name lookup fails: "unknown" </td> </tr>
+
+<tr> <td> {cert_issuer} </td> <td> HELO, MAIL, DATA, EOH, EOM </td> <td>
+TLS client certificate issuer </td> </tr>
+
+<tr> <td> {cert_subject} </td> <td> HELO, MAIL, DATA, EOH, EOM </td>
+<td> TLS client certificate subject </td> </tr>
+
+<tr> <td> {cipher_bits} </td> <td> HELO, MAIL, DATA, EOH, EOM </td> <td>
+TLS session key size </td> </tr>
+
+<tr> <td> {cipher} </td> <td> HELO, MAIL, DATA, EOH, EOM </td> <td> TLS
+cipher </td> </tr>
+
+<tr> <td> {daemon_addr} </td> <td> Always (Postfix &ge;3.2) </td>
+<td> Local server IP address </td> </tr>
+
+<tr> <td> {daemon_name} </td> <td> Always </td> <td> value of
+<a href="postconf.5.html#milter_macro_daemon_name">milter_macro_daemon_name</a> </td> </tr>
+
+<tr> <td> {daemon_port} </td> <td> Always (Postfix &ge;3.2) </td>
+<td> Local server TCP port </td> </tr>
+
+<tr> <td> {mail_addr} </td> <td> MAIL </td> <td> Sender address
+</td> </tr>
+
+<tr> <td> {mail_host} </td> <td> MAIL (Postfix &ge; 2.6, only with
+<a href="postconf.5.html#smtpd_milters">smtpd_milters</a>) </td> <td> Sender next-hop destination </td> </tr>
+
+<tr> <td> {mail_mailer} </td> <td> MAIL (Postfix &ge; 2.6, only with
+<a href="postconf.5.html#smtpd_milters">smtpd_milters</a>) </td> <td> Sender mail delivery transport </td> </tr>
+
+<tr> <td> {rcpt_addr} </td> <td> RCPT </td> <td> Recipient address
+<br> With rejected recipient: descriptive text </td> </tr>
+
+<tr> <td> {rcpt_host} </td> <td> RCPT (Postfix &ge; 2.6, only with
+<a href="postconf.5.html#smtpd_milters">smtpd_milters</a>) </td> <td> Recipient next-hop destination <br> With
+rejected recipient: enhanced status code </td> </tr>
+
+<tr> <td> {rcpt_mailer} </td> <td> RCPT (Postfix &ge; 2.6, only with
+<a href="postconf.5.html#smtpd_milters">smtpd_milters</a>) </td> <td> Recipient mail delivery transport <br>
+With rejected recipient: "error" </td> </tr>
+
+<tr> <td> {tls_version} </td> <td> HELO, MAIL, DATA, EOH, EOM </td>
+<td> TLS protocol version </td> </tr>
+
+<tr> <td> v </td> <td> Always </td> <td> value of <a href="postconf.5.html#milter_macro_v">milter_macro_v</a>
+</td> </tr>
+
+</table>
+
+</blockquote>
+
+<h3><a name="send-macros">What macros will Postfix send to Milters?</a></h3>
+
+<p> Postfix sends specific sets of macros at different Milter protocol
+stages. The names of these macros are configured with the parameters
+shown in the table below (EOH = end of headers; EOM = end of message).
+Some lists require a minimum Milter protocol version. </p>
+
+<p> As of Sendmail 8.14.0, Milter applications can specify what
+macros they want to receive at different Milter protocol stages.
+An application-specified list takes precedence over a Postfix-specified
+list. </p>
+
+<blockquote>
+
+<table border="1">
+
+<tr> <th> Postfix parameter </th> <th> Milter protocol version </th>
+<th> Milter protocol stage </th> </tr>
+
+<tr> <td> <a href="postconf.5.html#milter_connect_macros">milter_connect_macros</a> </td> <td> 2 or higher </td> <td>
+CONNECT </td> </tr>
+
+<tr> <td> <a href="postconf.5.html#milter_helo_macros">milter_helo_macros</a> </td> <td> 2 or higher </td> <td>
+HELO/EHLO </td> </tr>
+
+<tr> <td> <a href="postconf.5.html#milter_mail_macros">milter_mail_macros</a> </td> <td> 2 or higher </td> <td> MAIL
+FROM </td> </tr>
+
+<tr> <td> <a href="postconf.5.html#milter_rcpt_macros">milter_rcpt_macros</a> </td> <td> 2 or higher </td> <td> RCPT
+TO </td> </tr>
+
+<tr> <td> <a href="postconf.5.html#milter_data_macros">milter_data_macros</a> </td> <td> 4 or higher </td> <td> DATA
+</td> </tr>
+
+<tr> <td> <a href="postconf.5.html#milter_end_of_header_macros">milter_end_of_header_macros</a> </td> <td> 6 or higher </td>
+<td> EOH </td> </tr>
+
+<tr> <td> <a href="postconf.5.html#milter_end_of_data_macros">milter_end_of_data_macros</a> </td> <td> 2 or higher </td>
+<td> EOM </td> </tr>
+
+<tr> <td> <a href="postconf.5.html#milter_unknown_command_macros">milter_unknown_command_macros</a> </td> <td> 3 or higher </td>
+<td> unknown command </td> </tr>
+
+</table>
+
+</blockquote>
+
+<p> By default, Postfix will send only macros whose values have been
+updated with information from <a href="postconf.5.html">main.cf</a> or <a href="master.5.html">master.cf</a>, from an SMTP session
+(for example; SASL login, or TLS certificates) or from a Mail delivery
+transaction (for example; queue ID, sender, or recipient). </p>
+
+<p> To force a macro to be sent even when its value has not been updated,
+you may specify macro default values with the <a href="postconf.5.html#milter_macro_defaults">milter_macro_defaults</a>
+parameter. Specify zero or more <i>name=value</i> pairs separated by
+comma or whitespace; you may even specify macro names that Postfix does
+not know about! </p>
+
+<h2><a name="workarounds">Workarounds</a></h2>
+
+<ul>
+
+<li> <p> To avoid breaking DKIM etc. signatures with an SMTP-based
+content filter, update the before-filter SMTP client in <a href="master.5.html">master.cf</a>,
+and add a line with "-o <a href="postconf.5.html#disable_mime_output_conversion">disable_mime_output_conversion</a>=yes" (note:
+no spaces around the "="). For details, see the <a
+href="FILTER_README.html#advanced_filter">advanced content filter</a>
+example. </p>
+
+<pre>
+/etc/postfix/<a href="master.5.html">master.cf</a>:
+ # =============================================================
+ # service type private unpriv chroot wakeup maxproc command
+ # (yes) (yes) (yes) (never) (100)
+ # =============================================================
+ scan unix - - n - 10 smtp
+ -o <a href="postconf.5.html#smtp_send_xforward_command">smtp_send_xforward_command</a>=yes
+ -o <a href="postconf.5.html#disable_mime_output_conversion">disable_mime_output_conversion</a>=yes
+ -o <a href="postconf.5.html#smtp_generic_maps">smtp_generic_maps</a>=
+</pre>
+
+<li> <p> Some Milter applications use the "<tt>{if_addr}</tt>" macro
+to recognize local mail; this macro does not exist in Postfix.
+Workaround: use the "<tt>{daemon_addr}</tt>" (Postfix &ge; 3.2) or
+"<tt>{client_addr}</tt>" macro instead. </p>
+
+<li> <p> Some Milter applications log a warning that looks like
+this: </p>
+
+<blockquote> <pre>
+sid-filter[36540]: WARNING: sendmail symbol 'i' not available
+</pre>
+</blockquote>
+
+<p> And they may insert an ugly message header with "unknown-msgid"
+like this: </p>
+
+<blockquote>
+<pre>
+X-SenderID: Sendmail Sender-ID Filter vx.y.z host.example.com &lt;unknown-msgid&gt;
+</pre>
+</blockquote>
+
+<p> The problem is that Milter applications expect that the queue
+ID is known <i>before</i> the MTA accepts the MAIL FROM (sender)
+command. Postfix does not choose a queue ID, which is used as the
+queue file name, until <i>after</i> it accepts the first valid RCPT
+TO (recipient) command. </p>
+
+<p> If you experience the ugly header problem, see if a recent
+version of the Milter application fixes it. For example, current
+versions of dkim-filter and dk-filter already have code that looks
+up the Postfix queue ID at a later protocol stage, and sid-filter
+version 1.0.0 no longer includes the queue ID in the message header.
+</p>
+
+<p> To fix the ugly message header, you will need to add code that
+looks up the Postfix queue ID at some later point in time. The
+example below adds the lookup after the end-of-message. </p>
+
+<ul>
+
+<li> <p> Edit the filter source file (typically named
+<tt>xxx-filter/xxx-filter.c</tt> or similar). </p>
+
+<li> <p> Look up the <tt>mlfi_eom()</tt> function and add code near
+the top shown as <b>bold</b> text below: </p>
+
+</ul>
+
+<blockquote>
+<pre>
+dfc = cc->cctx_msg;
+assert(dfc != NULL);
+<b>
+/* Determine the job ID for logging. */
+if (dfc->mctx_jobid == 0 || strcmp(dfc->mctx_jobid, JOBIDUNKNOWN) == 0) {
+ char *jobid = smfi_getsymval(ctx, "i");
+ if (jobid != 0)
+ dfc->mctx_jobid = jobid;
+}</b>
+</pre>
+</blockquote>
+
+<p> NOTES: </p>
+
+<ul>
+
+<li> <p> Different mail filters use slightly different names for
+variables. If the above code does not compile, look elsewhere in
+the mail filter source file for code that looks up the "i" macro
+value, and copy that code. </p>
+
+<li> <p> This change fixes only the ugly message header, but not
+the WARNING message. Fortunately, many Milters log that message
+only once. </p>
+
+</ul>
+
+</ul>
+
+<h2><a name="limitations">Limitations</a></h2>
+
+<p> This section lists limitations of the Postfix Milter implementation.
+Some limitations will be removed as the implementation is extended
+over time. Of course the usual limitations of before-queue filtering
+will always apply. See the <a href="CONTENT_INSPECTION_README.html">CONTENT_INSPECTION_README</a> document for
+a discussion. </p>
+
+<ul>
+
+<li> <p> The Milter protocol has evolved over time. Therefore,
+different Postfix versions implement different feature sets. </p>
+
+<table border="1">
+
+<tr> <th> Postfix </th> <th> Supported Milter requests </th>
+</tr>
+
+<tr> <td align="center"> 2.6 </td> <td> All Milter requests of
+Sendmail 8.14.0 (see notes below). </td> </tr>
+
+<tr> <td align="center"> 2.5 </td> <td> All Milter requests of
+Sendmail 8.14.0, except: <br> SMFIP_RCPT_REJ (report rejected
+recipients to the mail filter), <br> SMFIR_CHGFROM (replace sender,
+with optional ESMTP parameters), <br> SMFIR_ADDRCPT_PAR (add
+recipient, with optional ESMTP parameters). </td> </tr>
+
+<tr> <td align="center"> 2.4 </td> <td> All Milter requests of
+Sendmail 8.13.0. </td> </tr>
+
+<tr> <td align="center"> 2.3 </td> <td> All Milter requests of
+Sendmail 8.13.0, except: <br> SMFIR_REPLBODY (replace message body).
+
+</table>
+
+<li> <p> For Milter applications that are written in C, you need
+to use the Sendmail libmilter library. </p>
+
+<li> <p> Postfix has TWO sets of mail filters: filters that are used
+for SMTP mail only (specified with the <a href="postconf.5.html#smtpd_milters">smtpd_milters</a> parameter),
+and filters for non-SMTP mail (specified with the <a href="postconf.5.html#non_smtpd_milters">non_smtpd_milters</a>
+parameter). The non-SMTP filters are primarily for local submissions.
+</p>
+
+<p> When mail is filtered by <a href="postconf.5.html#non_smtpd_milters">non_smtpd_milters</a>, the Postfix <a href="cleanup.8.html">cleanup(8)</a>
+server has to simulate SMTP client requests. This works as expected,
+with only one exception: <a href="postconf.5.html#non_smtpd_milters">non_smtpd_milters</a> must not REJECT or
+TEMPFAIL simulated RCPT TO commands. When this rule is violated,
+Postfix will report a configuration error, and mail will stay in
+the queue. </p>
+
+<li> <p> When you use the before-queue content filter for incoming
+SMTP mail (see <a href="SMTPD_PROXY_README.html">SMTPD_PROXY_README</a>), Milter applications have access
+only to the SMTP command information; they have no access to the
+message header or body, and cannot make modifications to the message
+or to the envelope. </p>
+
+<li> <p> Postfix 2.6 ignores the optional ESMTP parameters in
+requests to replace the sender (SMFIR_CHGFROM) or to append a
+recipient (SMFIR_ADDRCPT_PAR). Postfix logs a warning message when
+a Milter application supplies such ESMTP parameters: </p>
+
+<pre>
+warning: <i>queue-id</i>: cleanup_chg_from: ignoring ESMTP arguments "<i>whatever</i>"
+warning: <i>queue-id</i>: cleanup_add_rcpt: ignoring ESMTP arguments "<i>whatever</i>"
+</pre>
+
+<li> <p> Postfix 2.3 does not implement requests to replace the
+message body. Milter applications log a warning message when they
+need this unsupported operation: </p>
+
+<pre>
+st_optionneg[134563840]: 0x3d does not fulfill action requirements 0x1e
+</pre>
+
+<p> The solution is to use Postfix version 2.4 or later. </p>
+
+<li> <p> Postfix versions before 3.0 did not support per-Milter
+timeouts, per-Milter error handling, etc. </p>
+
+</ul>
+
+</body>
+
+</html>