-TCRYPTO_EX_DATA
-TCTABLE
-TCTABLE_ENTRY
+-TDELIVERED_HDR_INFO
-TDELIVER_ATTR
-TDELIVER_REQUEST
-TDELTA_TIME
20070331
Bugfix (introduced Postfix 2.3): segfault with HOLD action
- in header/body_checks on 64-bit platforms. File:
- cleanup/cleanup_api.c.
+ in access/header_checks/body_checks on 64-bit platforms.
+ File: cleanup/cleanup_api.c.
20070402
broke with "fcntl F_DUPFD: Invalid argument" on 64-bit
Solaris. Files: master/multi_server.c, *qmgr/qmgr_transport.c.
+20070405
+
+ Feature: BCC access/policy action, to demonstrate that this
+ is not a good feature. The action's behavior is non-intuitive
+ and requires too much documentation to explain. It's
+ therefore snapshot only. File: smtpd/smtpd_check.c.
+
+20070414
+
+ Cleanup: expire cached results from addres rewriting, address
+ resolution, and from transport map lookups. Results expire
+ after 30 seconds; short enough that it doesn't freak out
+ people who run the same test repeatedly, and long enough
+ that it doesn't upset other people with continuous streams
+ of "*" transport map lookups. Files: global/rewrite_clnt.c,
+ global/resolve_clnt.c, trivial-rewrite/transport.c.
+
+20070421
+
+ Cleanup: on (Linux) platforms that cripple signal handlers
+ with deadlock, "postfix stop" now forcefully stops all the
+ processes in the master's process group, not just the master
+ process alone. File: conf/postfix-script.
+
+20070422
+
+ Cleanup: the "Delivered-To:" loop detection implementation
+ was moved from the local(8) delivery agent to the library,
+ where it can also be used by other delivery agents. Files:
+ global/delivered_hdr.[hc].
+
+ Safety: the "Delivered-To:" loop detection implementation
+ keeps state for no more than 1000 "Delivered-To:" headers.
+
+ Feature: $domain command-line macro support, to get access
+ to the recipient address domain portion. Based on code by
+ Koen Vermeer. File: pipe/pipe.c.
+
+ Cleanup: suport for "Delivered-To:" loop detection in the
+ pipe(8) delivery agent. This follows a general principle:
+ if a program creates the "Delivered-To:" header, then it
+ is also responsible for "Delivered-To:" loop detection.
+ File pipe/pipe.c.
+
Wish list:
Remove defer(8) and trace(8) references and man pages. These
are services not program names.
Bind all deliveries to the same local delivery process,
- making Postfix perform as poorly as monolithic mailers,
- but giving a possibility to eliminate duplicate deliveries.
+ making Postfix perform as poorly as monolithic mailers, but
+ giving a possibility to eliminate duplicate deliveries.
Maybe declare loop when resolve_local(mxhost) is true?
Here is an example of all the attributes that the Postfix SMTP server sends in
a delegated SMTPD access policy request:
+ P\bPo\bos\bst\btf\bfi\bix\bx v\bve\ber\brs\bsi\bio\bon\bn 2\b2.\b.1\b1 a\ban\bnd\bd l\bla\bat\bte\ber\br:\b:
request=smtpd_access_policy
protocol_state=RCPT
protocol_name=SMTP
If you upgrade from Postfix 2.3 or earlier, read RELEASE_NOTES-2.4
before proceeding.
+
+Incompatibility with Postfix snapshot 20070422
+==============================================
+
+When the pipe(8) delivery agent is configured to create the optional
+Delivered-To: header, it first checks if that same header is already
+present. If so, the mail is returned as undeliverable. This test
+should have been included with Postfix 2.0 when Delivered-To: support
+was added to the pipe(8) delivery agent.
# Apply the named UCE restriction(s) (permit, reject,
# reject_unauth_destination, and so on).
#
+# BCC user@domain
+# Send one copy of the message to the specified
+# recipient.
+#
+# If multiple BCC actions are specified within the
+# same SMTP MAIL transaction, only the last action
+# will be used.
+#
+# This feature is not part of the stable Postfix
+# release.
+#
# DISCARD optional text...
# Claim successful delivery and silently discard the
# message. Log the optional text if specified, oth-
# Postfix master process configuration file. For details on the format
# of the file, see the master(5) manual page (command: "man 5 master").
#
+# Do not forget to execute "postfix reload" after editing this file.
+#
# ==========================================================================
# service type private unpriv chroot wakeup maxproc command + args
# (yes) (yes) (yes) (never) (100)
sleep 1
done
$WARN stopping the Postfix mail system with force
- kill -9 `sed 1q pid/master.pid`
+ pid=`awk '{ print $1; exit 0 } END { exit 1 }' pid/master.pid` &&
+ kill -9 -$pid
;;
abort)
<blockquote>
<pre>
+<b>Postfix version 2.1 and later:</b>
request=smtpd_access_policy
protocol_state=RCPT
protocol_name=SMTP
Apply the named UCE restriction(s) (<b>permit</b>, <b>reject</b>,
<b><a href="postconf.5.html#reject_unauth_destination">reject_unauth_destination</a></b>, and so on).
+ <b>BCC</b> <i>user@domain</i>
+ Send one copy of the message to the specified
+ recipient.
+
+ If multiple BCC actions are specified within the
+ same SMTP MAIL transaction, only the last action
+ will be used.
+
+ This feature is not part of the stable Postfix
+ release.
+
<b>DISCARD</b> <i>optional text...</i>
Claim successful delivery and silently discard the
message. Log the optional text if specified, oth-
<b>if /</b><i>pattern</i><b>/</b><i>flags</i>
<b>endif</b> Match the input string against the patterns between
- <b>if</b> and <b>endif</b>, if and only if the input string also
- matches <i>pattern</i>. The <b>if</b>..<b>endif</b> can nest.
+ <b>if</b> and <b>endif</b>, if and only if that same input string
+ also matches <i>pattern</i>. The <b>if</b>..<b>endif</b> can nest.
Note: do not prepend whitespace to patterns inside
<b>if</b>..<b>endif</b>.
<b>if !/</b><i>pattern</i><b>/</b><i>flags</i>
<b>endif</b> Match the input string against the patterns between
- <b>if</b> and <b>endif</b>, if and only if the input string does
- <b>not</b> match <i>pattern</i>. The <b>if</b>..<b>endif</b> can nest.
+ <b>if</b> and <b>endif</b>, if and only if that same input string
+ does <b>not</b> match <i>pattern</i>. The <b>if</b>..<b>endif</b> can nest.
Note: do not prepend whitespace to patterns inside
<b>if</b>..<b>endif</b>.
<a href="trace.8.html"><b>trace</b>(8)</a> daemon as appropriate.
<b>SINGLE-RECIPIENT DELIVERY</b>
- Some external commands cannot handle more than one recipi-
- ent per delivery request. Examples of such transports are
- pagers or fax machines.
+ Some destinations cannot handle more than one recipient
+ per delivery request. Examples are pagers or fax machines.
+ In addition, multi-recipient delivery is undesirable when
+ prepending a <b>Delivered-to:</b> or <b>X-Original-To:</b> message
+ header.
To prevent Postfix from sending multiple recipients per
delivery request, specify
<b>D</b> Prepend a "<b>Delivered-To:</b> <i>recipient</i>" message
header with the envelope recipient address.
Note: for this to work, the <i>transport</i><b>_desti-</b>
- <b>nation_recipient_limit</b> must be 1.
+ <b>nation_recipient_limit</b> must be 1 (see SIN-
+ GLE-RECIPIENT DELIVERY above for details).
+
+ This code also enforces loop detection
+ (Postfix 2.5 and later). If a message
+ already contains a <b>Delivered-To:</b> header with
+ the same recipient address, then the message
+ is returned as undeliverable.
This feature is available as of Postfix 2.0.
- <b>F</b> Prepend a "<b>From</b> <i>sender time</i><b>_</b><i>stamp</i>" envelope
- header to the message content. This is
+ <b>F</b> Prepend a "<b>From</b> <i>sender time</i><b>_</b><i>stamp</i>" envelope
+ header to the message content. This is
expected by, for example, <b>UUCP</b> software.
- <b>O</b> Prepend an "<b>X-Original-To:</b> <i>recipient</i>" mes-
- sage header with the recipient address as
- given to Postfix. Note: for this to work,
+ <b>O</b> Prepend an "<b>X-Original-To:</b> <i>recipient</i>" mes-
+ sage header with the recipient address as
+ given to Postfix. Note: for this to work,
the <i>transport</i><b>_destination_recipient_limit</b>
- must be 1.
+ must be 1 (see SINGLE-RECIPIENT DELIVERY
+ above for details).
This feature is available as of Postfix 2.0.
<b>R</b> Prepend a <b>Return-Path:</b> message header with
the envelope sender address.
- <b>h</b> Fold the command-line <b>$recipient</b> domain name
- and <b>$nexthop</b> host name to lower case. This
- is recommended for delivery via <b>UUCP</b>.
+ <b>h</b> Fold the command-line <b>$recipient</b> address
+ domain part (text to the right of the right-
+ most <b>@</b> character) to lower case; fold the
+ entire command-line <b>$domain</b> and <b>$nexthop</b>
+ host or domain information to lower case.
+ This is recommended for delivery via <b>UUCP</b>.
- <b>q</b> Quote white space and other special charac-
+ <b>q</b> Quote white space and other special charac-
ters in the command-line <b>$sender</b> and <b>$recip-</b>
<b>ient</b> address localparts (text to the left of
the right-most <b>@</b> character), according to an
- 8-bit transparent version of <a href="http://www.faqs.org/rfcs/rfc822.html">RFC 822</a>. This
- is recommended for delivery via <b>UUCP</b> or
+ 8-bit transparent version of <a href="http://www.faqs.org/rfcs/rfc822.html">RFC 822</a>. This
+ is recommended for delivery via <b>UUCP</b> or
<b>BSMTP</b>.
- The result is compatible with the address
- parsing of command-line recipients by the
+ The result is compatible with the address
+ parsing of command-line recipients by the
Postfix <a href="sendmail.1.html"><b>sendmail</b>(1)</a> mail submission command.
- The <b>q</b> flag affects only entire addresses,
+ The <b>q</b> flag affects only entire addresses,
not the partial address information from the
- <b>$user</b>, <b>$extension</b> or <b>$mailbox</b> command-line
+ <b>$user</b>, <b>$extension</b> or <b>$mailbox</b> command-line
macros.
<b>u</b> Fold the command-line <b>$recipient</b> address
- localpart (text to the left of the right-
- most <b>@</b> character) to lower case. This is
+ localpart (text to the left of the right-
+ most <b>@</b> character) to lower case. This is
recommended for delivery via <b>UUCP</b>.
<b>.</b> Prepend "<b>.</b>" to lines starting with "<b>.</b>". This
is needed by, for example, <b>BSMTP</b> software.
- > Prepend ">" to lines starting with "<b>From</b> ".
+ > Prepend ">" to lines starting with "<b>From</b> ".
This is expected by, for example, <b>UUCP</b> soft-
ware.
<b>null_sender</b>=<i>replacement</i> (default: MAILER-DAEMON)
Replace the null sender address (typically used for
- delivery status notifications) with the specified
+ delivery status notifications) with the specified
text when expanding the <b>$sender</b> command-line macro,
and when generating a From_ or Return-Path: message
header.
- If the null sender replacement text is a non-empty
- string then it is affected by the <b>q</b> flag for
+ If the null sender replacement text is a non-empty
+ string then it is affected by the <b>q</b> flag for
address quoting in command-line arguments.
The null sender replacement text may be empty; this
- form is recommended for content filters that feed
+ form is recommended for content filters that feed
mail back into Postfix. The empty sender address is
- not affected by the <b>q</b> flag for address quoting in
+ not affected by the <b>q</b> flag for address quoting in
command-line arguments.
Caution: a null sender address is easily mis-parsed
- by naive software. For example, when the <a href="pipe.8.html"><b>pipe</b>(8)</a>
+ by naive software. For example, when the <a href="pipe.8.html"><b>pipe</b>(8)</a>
daemon executes a command such as:
command -f$sender -- $recipient (<i>bad</i>)
the command will mis-parse the -f option value when
- the sender address is a null string. For correct
+ the sender address is a null string. For correct
parsing, specify <b>$sender</b> as an argument by itself:
command -f $sender -- $recipient (<i>good</i>)
- This feature is available with Postfix 2.3 and
- later.
+ This feature is available as of Postfix 2.3.
<b>size</b>=<i>size</i><b>_</b><i>limit</i> (optional)
Messages greater in size than this limit (in bytes)
This is available in Postfix 2.2 and later.
+ <b>${domain</b>}
+ This macro expands to the domain portion of
+ the recipient address. For example, with an
+ address <i>user+foo@domain</i> the domain is
+ <i>domain</i>.
+
+ This information is modified by the <b>h</b> flag
+ for case folding.
+
+ This is available in Postfix 2.5 and later.
+
<b>${extension</b>}
- This macro expands to the extension part of
- a recipient address. For example, with an
+ This macro expands to the extension part of
+ a recipient address. For example, with an
address <i>user+foo@domain</i> the extension is
<i>foo</i>.
- A command-line argument that contains
- <b>${extension</b>} expands into as many command-
+ A command-line argument that contains
+ <b>${extension</b>} expands into as many command-
line arguments as there are recipients.
- This information is modified by the <b>u</b> flag
+ This information is modified by the <b>u</b> flag
for case folding.
<b>${mailbox</b>}
- This macro expands to the complete local
- part of a recipient address. For example,
- with an address <i>user+foo@domain</i> the mailbox
+ This macro expands to the complete local
+ part of a recipient address. For example,
+ with an address <i>user+foo@domain</i> the mailbox
is <i>user+foo</i>.
- A command-line argument that contains
- <b>${mailbox</b>} expands to as many command-line
+ A command-line argument that contains
+ <b>${mailbox</b>} expands to as many command-line
arguments as there are recipients.
- This information is modified by the <b>u</b> flag
+ This information is modified by the <b>u</b> flag
for case folding.
<b>${nexthop</b>}
This macro expands to the next-hop hostname.
- This information is modified by the <b>h</b> flag
+ This information is modified by the <b>h</b> flag
for case folding.
<b>${recipient</b>}
This macro expands to the complete recipient
address.
- A command-line argument that contains
+ A command-line argument that contains
<b>${recipient</b>} expands to as many command-line
arguments as there are recipients.
- This information is modified by the <b>hqu</b>
+ This information is modified by the <b>hqu</b>
flags for quoting and case folding.
<b>${sasl_method</b>}
- This macro expands to the SASL authentica-
- tion mechanism used during the reception of
- the message. An empty string is passed if
- the message has been received without SASL
+ This macro expands to the SASL authentica-
+ tion mechanism used during the reception of
+ the message. An empty string is passed if
+ the message has been received without SASL
authentication.
- This is available in Postfix 2.2 and later.
+ This is available in Postfix 2.2 and later.
<b>${sasl_sender</b>}
- This macro expands to the SASL sender name
- (i.e. the original submitter as per <a href="http://www.faqs.org/rfcs/rfc2554.html">RFC</a>
- <a href="http://www.faqs.org/rfcs/rfc2554.html">2554</a>) used during the reception of the mes-
+ This macro expands to the SASL sender name
+ (i.e. the original submitter as per <a href="http://www.faqs.org/rfcs/rfc2554.html">RFC</a>
+ <a href="http://www.faqs.org/rfcs/rfc2554.html">2554</a>) used during the reception of the mes-
sage.
- This is available in Postfix 2.2 and later.
+ This is available in Postfix 2.2 and later.
<b>${sasl_username</b>}
- This macro expands to the SASL user name
+ This macro expands to the SASL user name
used during the reception of the message. An
- empty string is passed if the message has
+ empty string is passed if the message has
been received without SASL authentication.
- This is available in Postfix 2.2 and later.
+ This is available in Postfix 2.2 and later.
<b>${sender</b>}
- This macro expands to the envelope sender
+ This macro expands to the envelope sender
address. By default, the null sender address
- expands to MAILER-DAEMON; this can be
- changed with the <b>null_sender</b> attribute, as
+ expands to MAILER-DAEMON; this can be
+ changed with the <b>null_sender</b> attribute, as
described above.
- This information is modified by the <b>q</b> flag
+ This information is modified by the <b>q</b> flag
for quoting.
<b>${size</b>}
- This macro expands to Postfix's idea of the
- message size, which is an approximation of
+ This macro expands to Postfix's idea of the
+ message size, which is an approximation of
the size of the message as delivered.
<b>${user</b>}
This macro expands to the username part of a
- recipient address. For example, with an
+ recipient address. For example, with an
address <i>user+foo@domain</i> the username part is
<i>user</i>.
- A command-line argument that contains
- <b>${user</b>} expands into as many command-line
+ A command-line argument that contains
+ <b>${user</b>} expands into as many command-line
arguments as there are recipients.
- This information is modified by the <b>u</b> flag
+ This information is modified by the <b>u</b> flag
for case folding.
<b>STANDARDS</b>
<a href="http://www.faqs.org/rfcs/rfc3463.html">RFC 3463</a> (Enhanced status codes)
<b>DIAGNOSTICS</b>
- Command exit status codes are expected to follow the con-
- ventions defined in <<b>sysexits.h</b>>. Exit status 0 means
+ Command exit status codes are expected to follow the con-
+ ventions defined in <<b>sysexits.h</b>>. Exit status 0 means
normal successful completion.
- Postfix version 2.3 and later support <a href="http://www.faqs.org/rfcs/rfc3463.html">RFC 3463</a>-style
- enhanced status codes. If a command terminates with a
- non-zero exit status, and the command output begins with
+ Postfix version 2.3 and later support <a href="http://www.faqs.org/rfcs/rfc3463.html">RFC 3463</a>-style
+ enhanced status codes. If a command terminates with a
+ non-zero exit status, and the command output begins with
an enhanced status code, this status code takes precedence
over the non-zero exit status.
- Problems and transactions are logged to <b>syslogd</b>(8). Cor-
- rupted message files are marked so that the queue manager
+ Problems and transactions are logged to <b>syslogd</b>(8). Cor-
+ rupted message files are marked so that the queue manager
can move them to the <b>corrupt</b> queue for further inspection.
<b>SECURITY</b>
- This program needs a dual personality 1) to access the
- private Postfix queue and IPC mechanisms, and 2) to exe-
+ This program needs a dual personality 1) to access the
+ private Postfix queue and IPC mechanisms, and 2) to exe-
cute external commands as the specified user. It is there-
fore security sensitive.
<b>CONFIGURATION PARAMETERS</b>
- Changes to <a href="postconf.5.html"><b>main.cf</b></a> are picked up automatically as <a href="pipe.8.html"><b>pipe</b>(8)</a>
- processes run for only a limited amount of time. Use the
+ Changes to <a href="postconf.5.html"><b>main.cf</b></a> are picked up automatically as <a href="pipe.8.html"><b>pipe</b>(8)</a>
+ processes run for only a limited amount of time. Use the
command "<b>postfix reload</b>" to speed up a change.
- The text below provides only a parameter summary. See
+ The text below provides only a parameter summary. See
<a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including examples.
<b>RESOURCE AND RATE CONTROLS</b>
- In the text below, <i>transport</i> is the first field in a <b>mas-</b>
+ In the text below, <i>transport</i> is the first field in a <b>mas-</b>
<b>ter.cf</b> entry.
<i>transport</i><b>_destination_concurrency_limit ($<a href="postconf.5.html#default_destination_concurrency_limit">default_destina</a>-</b>
<b><a href="postconf.5.html#default_destination_concurrency_limit">tion_concurrency_limit</a>)</b>
Limit the number of parallel deliveries to the same
- destination, for delivery via the named <i>transport</i>.
+ destination, for delivery via the named <i>transport</i>.
The limit is enforced by the Postfix queue manager.
<i>transport</i><b>_destination_recipient_limit ($<a href="postconf.5.html#default_destination_recipient_limit">default_destina</a>-</b>
<b><a href="postconf.5.html#default_destination_recipient_limit">tion_recipient_limit</a>)</b>
- Limit the number of recipients per message deliv-
- ery, for delivery via the named <i>transport</i>. The
+ Limit the number of recipients per message deliv-
+ ery, for delivery via the named <i>transport</i>. The
limit is enforced by the Postfix queue manager.
<i>transport</i><b>_time_limit ($<a href="postconf.5.html#command_time_limit">command_time_limit</a>)</b>
- Limit the time for delivery to external command,
+ Limit the time for delivery to external command,
for delivery via the named <i>transport</i>. The limit is
enforced by the pipe delivery agent.
- Postfix 2.4 and later support a suffix that speci-
- fies the time unit: s (seconds), m (minutes), h
+ Postfix 2.4 and later support a suffix that speci-
+ fies the time unit: s (seconds), m (minutes), h
(hours), d (days), w (weeks). The default time unit
is seconds.
<b>MISCELLANEOUS CONTROLS</b>
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
- The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
+ The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
<a href="master.5.html">master.cf</a> configuration files.
<b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
- How much time a Postfix daemon process may take to
- handle a request before it is terminated by a
+ How much time a Postfix daemon process may take to
+ handle a request before it is terminated by a
built-in watchdog timer.
<b><a href="postconf.5.html#delay_logging_resolution_limit">delay_logging_resolution_limit</a> (2)</b>
- The maximal number of digits after the decimal
+ The maximal number of digits after the decimal
point when logging sub-second delay values.
<b><a href="postconf.5.html#export_environment">export_environment</a> (see 'postconf -d' output)</b>
- The list of environment variables that a Postfix
+ The list of environment variables that a Postfix
process will export to non-Postfix processes.
<b><a href="postconf.5.html#ipc_timeout">ipc_timeout</a> (3600s)</b>
and most Postfix daemon processes.
<b><a href="postconf.5.html#max_idle">max_idle</a> (100s)</b>
- The maximum amount of time that an idle Postfix
- daemon process waits for an incoming connection
+ The maximum amount of time that an idle Postfix
+ daemon process waits for an incoming connection
before terminating voluntarily.
<b><a href="postconf.5.html#max_use">max_use</a> (100)</b>
- The maximal number of incoming connections that a
- Postfix daemon process will service before termi-
+ The maximal number of incoming connections that a
+ Postfix daemon process will service before termi-
nating voluntarily.
<b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
- The process ID of a Postfix command or daemon
+ The process ID of a Postfix command or daemon
process.
<b><a href="postconf.5.html#process_name">process_name</a> (read-only)</b>
- The process name of a Postfix command or daemon
+ The process name of a Postfix command or daemon
process.
<b><a href="postconf.5.html#queue_directory">queue_directory</a> (see 'postconf -d' output)</b>
- The location of the Postfix top-level queue direc-
+ The location of the Postfix top-level queue direc-
tory.
<b><a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> (empty)</b>
The syslog facility of Postfix logging.
<b><a href="postconf.5.html#syslog_name">syslog_name</a> (postfix)</b>
- The mail system name that is prepended to the
- process name in syslog records, so that "smtpd"
+ The mail system name that is prepended to the
+ process name in syslog records, so that "smtpd"
becomes, for example, "postfix/smtpd".
<b>SEE ALSO</b>
syslogd(8), system logging
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>
<b>endif</b> Match the input string against the patterns between
<b>if</b> and <b>endif</b>, if and only if that same input string
- does <b>not</b> match <i>pattern</i>. The <b>if</b>..<b>endif</b> can nest.
- matches <i>pattern</i>. The <b>if</b>..<b>endif</b> can nest.
+ does <b>not</b> match <i>pattern</i>. The <b>if</b>..<b>endif</b> can nest.
- Note: do not prepend whitespace to patterns inside
+ Note: do not prepend whitespace to patterns inside
<b>if</b>..<b>endif</b>.
This feature is available in Postfix 2.1 and later.
blank lines and comments
- Empty lines and whitespace-only lines are ignored,
- as are lines whose first non-whitespace character
+ Empty lines and whitespace-only lines are ignored,
+ as are lines whose first non-whitespace character
is a `#'.
multi-line text
- A logical line starts with non-whitespace text. A
- line that starts with whitespace continues a logi-
+ A logical line starts with non-whitespace text. A
+ line that starts with whitespace continues a logi-
cal line.
- Each pattern is a POSIX regular expression enclosed by a
+ Each pattern is a POSIX regular expression enclosed by a
pair of delimiters. The regular expression syntax is docu-
- mented in <b>re_format</b>(7) with 4.4BSD, in <b>regex</b>(5) with
+ mented in <b>re_format</b>(7) with 4.4BSD, in <b>regex</b>(5) with
Solaris, and in <b>regex</b>(7) with Linux. Other systems may use
other document names.
- The expression delimiter can be any character, except
+ The expression delimiter can be any character, except
whitespace or characters that have special meaning (tradi-
- tionally the forward slash is used). The regular expres-
+ tionally the forward slash is used). The regular expres-
sion can contain whitespace.
By default, matching is case-insensitive, and newlines are
- not treated as special characters. The behavior is con-
- trolled by flags, which are toggled by appending one or
+ not treated as special characters. The behavior is con-
+ trolled by flags, which are toggled by appending one or
more of the following characters after the pattern:
<b>i</b> (default: on)
- Toggles the case sensitivity flag. By default,
+ Toggles the case sensitivity flag. By default,
matching is case insensitive.
<b>x</b> (default: on)
- Toggles the extended expression syntax flag. By
- default, support for extended expression syntax is
+ Toggles the extended expression syntax flag. By
+ default, support for extended expression syntax is
enabled.
<b>m</b> (default: off)
- Toggle the multi-line mode flag. When this flag is
- on, the <b>^</b> and <b>$</b> metacharacters match immediately
- after and immediately before a newline character,
- respectively, in addition to matching at the start
+ Toggle the multi-line mode flag. When this flag is
+ on, the <b>^</b> and <b>$</b> metacharacters match immediately
+ after and immediately before a newline character,
+ respectively, in addition to matching at the start
and end of the input string.
<b>TABLE SEARCH ORDER</b>
- Patterns are applied in the order as specified in the ta-
- ble, until a pattern is found that matches the input
+ Patterns are applied in the order as specified in the ta-
+ ble, until a pattern is found that matches the input
string.
- Each pattern is applied to the entire input string.
- Depending on the application, that string is an entire
+ Each pattern is applied to the entire input string.
+ Depending on the application, that string is an entire
client hostname, an entire client IP address, or an entire
- mail address. Thus, no parent domain or parent network
- search is done, and <i>user@domain</i> mail addresses are not
- broken up into their <i>user</i> and <i>domain</i> constituent parts,
+ mail address. Thus, no parent domain or parent network
+ search is done, and <i>user@domain</i> mail addresses are not
+ broken up into their <i>user</i> and <i>domain</i> constituent parts,
nor is <i>user+foo</i> broken up into <i>user</i> and <i>foo</i>.
<b>TEXT SUBSTITUTION</b>
- Substitution of substrings from the matched expression
- into the result string is possible using $1, $2, etc.;
+ Substitution of substrings from the matched expression
+ into the result string is possible using $1, $2, etc.;
specify $$ to produce a $ character as output. The macros
- in the result string may need to be written as ${n} or
+ in the result string may need to be written as ${n} or
$(n) if they aren't followed by whitespace.
- Note: since negated patterns (those preceded by <b>!</b>) return
+ Note: since negated patterns (those preceded by <b>!</b>) return
a result when the expression does not match, substitutions
are not available for negated patterns.
.IP \fIrestriction...\fR
Apply the named UCE restriction(s) (\fBpermit\fR, \fBreject\fR,
\fBreject_unauth_destination\fR, and so on).
+.IP "\fBBCC \fIuser@domain\fR"
+Send one copy of the message to the specified recipient.
+.sp
+If multiple BCC actions are specified within the same SMTP
+MAIL transaction, only the last action will be used.
+.sp
+This feature is not part of the stable Postfix release.
.IP "\fBDISCARD \fIoptional text...\fR
Claim successful delivery and silently discard the message.
Log the optional text if specified, otherwise log a generic
.IP "\fBif /\fIpattern\fB/\fIflags\fR"
.IP "\fBendif\fR"
Match the input string against the patterns between \fBif\fR
-and \fBendif\fR, if and only if the input string also matches
+and \fBendif\fR, if and only if that same input string also matches
\fIpattern\fR. The \fBif\fR..\fBendif\fR can nest.
.sp
Note: do not prepend whitespace to patterns inside
.IP "\fBif !/\fIpattern\fB/\fIflags\fR"
.IP "\fBendif\fR"
Match the input string against the patterns between \fBif\fR
-and \fBendif\fR, if and only if the input string does \fBnot\fR
+and \fBendif\fR, if and only if that same input string does \fBnot\fR
match \fIpattern\fR. The \fBif\fR..\fBendif\fR can nest.
.sp
Note: do not prepend whitespace to patterns inside
Match the input string against the patterns between \fBif\fR
and \fBendif\fR, if and only if that same input string does
\fBnot\fR match \fIpattern\fR. The \fBif\fR..\fBendif\fR can nest.
-matches \fIpattern\fR. The \fBif\fR..\fBendif\fR can nest.
.sp
Note: do not prepend whitespace to patterns inside
\fBif\fR..\fBendif\fR.
.nf
.ad
.fi
-Some external commands cannot handle more than one recipient
-per delivery request. Examples of such transports are pagers
-or fax machines.
+Some destinations cannot handle more than one recipient per
+delivery request. Examples are pagers or fax machines.
+In addition, multi-recipient delivery is undesirable when
+prepending a \fBDelivered-to:\fR or \fBX-Original-To:\fR
+message header.
To prevent Postfix from sending multiple recipients per delivery
request, specify
.IP \fBD\fR
Prepend a "\fBDelivered-To: \fIrecipient\fR" message header with the
envelope recipient address. Note: for this to work, the
-\fItransport\fB_destination_recipient_limit\fR must be 1.
+\fItransport\fB_destination_recipient_limit\fR must be 1
+(see SINGLE-RECIPIENT DELIVERY above for details).
+.sp
+This code also enforces loop detection (Postfix 2.5 and later).
+If a message already contains a \fBDelivered-To:\fR header
+with the same recipient address, then the message is
+returned as undeliverable.
.sp
This feature is available as of Postfix 2.0.
.IP \fBF\fR
.IP \fBO\fR
Prepend an "\fBX-Original-To: \fIrecipient\fR" message header
with the recipient address as given to Postfix. Note: for this to
-work, the \fItransport\fB_destination_recipient_limit\fR must be 1.
+work, the \fItransport\fB_destination_recipient_limit\fR must be 1
+(see SINGLE-RECIPIENT DELIVERY above for details).
.sp
This feature is available as of Postfix 2.0.
.IP \fBR\fR
Prepend a \fBReturn-Path:\fR message header with the envelope sender
address.
.IP \fBh\fR
-Fold the command-line \fB$recipient\fR domain name and \fB$nexthop\fR
-host name to lower case.
+Fold the command-line \fB$recipient\fR address domain part
+(text to the right of the right-most \fB@\fR character) to
+lower case; fold the entire command-line \fB$domain\fR and
+\fB$nexthop\fR host or domain information to lower case.
This is recommended for delivery via \fBUUCP\fR.
.IP \fBq\fR
Quote white space and other special characters in the command-line
command -f $sender -- $recipient (\fIgood\fR)
.fi
.IP
-This feature is available with Postfix 2.3 and later.
+This feature is available as of Postfix 2.3.
.IP "\fBsize\fR=\fIsize_limit\fR (optional)"
Messages greater in size than this limit (in bytes) will
be returned to the sender as undeliverable.
This macro expands to the remote client protocol.
.sp
This is available in Postfix 2.2 and later.
+.IP \fB${\fBdomain\fR}\fR
+This macro expands to the domain portion of the recipient
+address. For example, with an address \fIuser+foo@domain\fR
+the domain is \fIdomain\fR.
+.sp
+This information is modified by the \fBh\fR flag for case folding.
+.sp
+This is available in Postfix 2.5 and later.
.IP \fB${\fBextension\fR}\fR
This macro expands to the extension part of a recipient address.
For example, with an address \fIuser+foo@domain\fR the extension is
<blockquote>
<pre>
+<b>Postfix version 2.1 and later:</b>
request=smtpd_access_policy
protocol_state=RCPT
protocol_name=SMTP
# .IP \fIrestriction...\fR
# Apply the named UCE restriction(s) (\fBpermit\fR, \fBreject\fR,
# \fBreject_unauth_destination\fR, and so on).
+# .IP "\fBBCC \fIuser@domain\fR"
+# Send one copy of the message to the specified recipient.
+# .sp
+# If multiple BCC actions are specified within the same SMTP
+# MAIL transaction, only the last action will be used.
+# .sp
+# This feature is not part of the stable Postfix release.
# \" .IP "\fBDELAY \fItime\fR"
# \" Place the message into the deferred queue, and delay the
# \" initial delivery attempt by \fItime\fR. The time value may
# .IP "\fBif /\fIpattern\fB/\fIflags\fR"
# .IP "\fBendif\fR"
# Match the input string against the patterns between \fBif\fR
-# and \fBendif\fR, if and only if the input string also matches
+# and \fBendif\fR, if and only if that same input string also matches
# \fIpattern\fR. The \fBif\fR..\fBendif\fR can nest.
# .sp
# Note: do not prepend whitespace to patterns inside
# .IP "\fBif !/\fIpattern\fB/\fIflags\fR"
# .IP "\fBendif\fR"
# Match the input string against the patterns between \fBif\fR
-# and \fBendif\fR, if and only if the input string does \fBnot\fR
+# and \fBendif\fR, if and only if that same input string does \fBnot\fR
# match \fIpattern\fR. The \fBif\fR..\fBendif\fR can nest.
# .sp
# Note: do not prepend whitespace to patterns inside
# Match the input string against the patterns between \fBif\fR
# and \fBendif\fR, if and only if that same input string does
# \fBnot\fR match \fIpattern\fR. The \fBif\fR..\fBendif\fR can nest.
-# matches \fIpattern\fR. The \fBif\fR..\fBendif\fR can nest.
# .sp
# Note: do not prepend whitespace to patterns inside
# \fBif\fR..\fBendif\fR.
sys_exits.c timed_ipc.c tok822_find.c tok822_node.c tok822_parse.c \
tok822_resolve.c tok822_rewrite.c tok822_tree.c trace.c \
user_acl.c valid_mailhost_addr.c verify.c verify_clnt.c \
- verp_sender.c wildcard_inet_addr.c xtext.c
+ verp_sender.c wildcard_inet_addr.c xtext.c delivered_hdr.c
OBJS = abounce.o anvil_clnt.o been_here.o bounce.o bounce_log.o \
canon_addr.o cfg_parser.o cleanup_strerror.o cleanup_strflags.o \
clnt_stream.o conv_time.o db_common.o debug_peer.o debug_process.o \
sys_exits.o timed_ipc.o tok822_find.o tok822_node.o tok822_parse.o \
tok822_resolve.o tok822_rewrite.o tok822_tree.o trace.o \
user_acl.o valid_mailhost_addr.o verify.o verify_clnt.o \
- verp_sender.o wildcard_inet_addr.o xtext.o
+ verp_sender.o wildcard_inet_addr.o xtext.o delivered_hdr.o
HDRS = abounce.h anvil_clnt.h been_here.h bounce.h bounce_log.h \
canon_addr.h cfg_parser.h cleanup_user.h clnt_stream.h config.h \
conv_time.h db_common.h debug_peer.h debug_process.h defer.h \
rewrite_clnt.h scache.h sent.h smtp_stream.h split_addr.h \
string_list.h strip_addr.h sys_exits.h timed_ipc.h tok822.h \
trace.h user_acl.h valid_mailhost_addr.h verify.h verify_clnt.h \
- verp_sender.h wildcard_inet_addr.h xtext.h
+ verp_sender.h wildcard_inet_addr.h xtext.h delivered_hdr.h
TESTSRC = rec2stream.c stream2rec.c recdump.c
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
CFLAGS = $(DEBUG) $(OPT) $(DEFS)
deliver_request.o: msg_stats.h
deliver_request.o: rcpt_buf.h
deliver_request.o: recipient_list.h
+delivered_hdr.o: ../../include/htable.h
+delivered_hdr.o: ../../include/msg.h
+delivered_hdr.o: ../../include/mymalloc.h
+delivered_hdr.o: ../../include/stringops.h
+delivered_hdr.o: ../../include/sys_defs.h
+delivered_hdr.o: ../../include/vbuf.h
+delivered_hdr.o: ../../include/vstream.h
+delivered_hdr.o: ../../include/vstring.h
+delivered_hdr.o: ../../include/vstring_vstream.h
+delivered_hdr.o: delivered_hdr.c
+delivered_hdr.o: delivered_hdr.h
+delivered_hdr.o: header_opts.h
+delivered_hdr.o: is_header.h
+delivered_hdr.o: quote_822_local.h
+delivered_hdr.o: quote_flags.h
+delivered_hdr.o: rec_type.h
+delivered_hdr.o: record.h
dict_ldap.o: ../../include/argv.h
dict_ldap.o: ../../include/binhash.h
dict_ldap.o: ../../include/dict.h
--- /dev/null
+/*++
+/* NAME
+/* delivered_hdr 3
+/* SUMMARY
+/* process Delivered-To: headers
+/* SYNOPSIS
+/* #include <delivered_hdr.h>
+/*
+/* DELIVERED_HDR_INFO *delivered_hdr_init(stream, offset)
+/* VSTREAM *stream;
+/* off_t offset;
+/*
+/* int delivered_hdr_find(info, address)
+/* DELIVERED_HDR_INFO *info;
+/* const char *address;
+/*
+/* void delivered_hdr_free(info)
+/* DELIVERED_HDR_INFO *info;
+/* DESCRIPTION
+/* This module processes addresses in Delivered-To: headers.
+/* These headers are added by some mail delivery systems, for the
+/* purpose of breaking mail forwarding loops. N.B. This solves
+/* a different problem than the Received: hop count limit. Hop
+/* counts are used to limit the impact of mail routing problems.
+/*
+/* delivered_hdr_init() extracts Delivered-To: header addresses
+/* from the specified message, and returns a table with the
+/* result. The file seek pointer is changed.
+/*
+/* delivered_hdr_find() looks up the address in the lookup table,
+/* and returns non-zero when the address was found. The
+/* address argument must be in internalized form.
+/*
+/* delivered_hdr_free() releases storage that was allocated by
+/* delivered_hdr_init().
+/*
+/* Arguments:
+/* .IP stream
+/* The open queue file.
+/* .IP offset
+/* Offset of the first message content record.
+/* .IP info
+/* Extracted Delivered-To: addresses information.
+/* .IP address
+/* A recipient address, internal form.
+/* DIAGNOSTICS
+/* Fatal errors: out of memory.
+/* SEE ALSO
+/* mail_copy(3), producer of Delivered-To: and other headers.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <mymalloc.h>
+#include <htable.h>
+#include <vstring.h>
+#include <vstream.h>
+#include <vstring_vstream.h>
+#include <stringops.h>
+
+/* Global library. */
+
+#include <record.h>
+#include <rec_type.h>
+#include <is_header.h>
+#include <quote_822_local.h>
+#include <header_opts.h>
+#include <delivered_hdr.h>
+
+ /*
+ * Application-specific.
+ */
+struct DELIVERED_HDR_INFO {
+ VSTRING *buf;
+ HTABLE *table;
+};
+
+#define STR(x) vstring_str(x)
+
+/* delivered_hdr_init - extract delivered-to information from the message */
+
+DELIVERED_HDR_INFO *delivered_hdr_init(VSTREAM *fp, off_t offset)
+{
+ char *cp;
+ DELIVERED_HDR_INFO *info;
+ HEADER_OPTS *hdr;
+
+ info = (DELIVERED_HDR_INFO *) mymalloc(sizeof(*info));
+ info->buf = vstring_alloc(10);
+ info->table = htable_create(0);
+
+ if (vstream_fseek(fp, offset, SEEK_SET) < 0)
+ msg_fatal("seek queue file %s: %m", VSTREAM_PATH(fp));
+
+ /*
+ * XXX Assume that mail_copy() produces delivered-to headers that fit in
+ * a REC_TYPE_NORM record. Lowercase the delivered-to addresses for
+ * consistency.
+ *
+ * XXX Don't get bogged down by gazillions of delivered-to headers.
+ */
+#define DELIVERED_HDR_LIMIT 1000
+
+ while (rec_get(fp, info->buf, 0) == REC_TYPE_NORM
+ && info->table->used < DELIVERED_HDR_LIMIT) {
+ if (is_header(STR(info->buf))) {
+ if ((hdr = header_opts_find(STR(info->buf))) != 0
+ && hdr->type == HDR_DELIVERED_TO) {
+ cp = STR(info->buf) + strlen(hdr->name) + 1;
+ while (ISSPACE(*cp))
+ cp++;
+ lowercase(cp);
+ if (msg_verbose)
+ msg_info("delivered_hdr_init: %s", cp);
+ htable_enter(info->table, cp, (char *) 0);
+ }
+ } else if (ISSPACE(STR(info->buf)[0])) {
+ continue;
+ } else {
+ break;
+ }
+ }
+ return (info);
+}
+
+/* delivered_hdr_find - look up recipient in delivered table */
+
+int delivered_hdr_find(DELIVERED_HDR_INFO *info, const char *address)
+{
+ HTABLE_INFO *ht;
+
+ /*
+ * mail_copy() uses quote_822_local() when writing the Delivered-To:
+ * header. We must therefore apply the same transformation when looking
+ * up the recipient. Lowercase the delivered-to address for consistency.
+ */
+ quote_822_local(info->buf, address);
+ lowercase(STR(info->buf));
+ ht = htable_locate(info->table, STR(info->buf));
+ return (ht != 0);
+}
+
+/* delivered_hdr_free - destructor */
+
+void delivered_hdr_free(DELIVERED_HDR_INFO *info)
+{
+ vstring_free(info->buf);
+ htable_free(info->table, (void (*) (char *)) 0);
+ myfree((char *) info);
+}
--- /dev/null
+#ifndef _DELIVERED_HDR_H_INCLUDED_
+#define _DELIVERED_HDR_H_INCLUDED_
+
+/*++
+/* NAME
+/* delivered_hdr 3h
+/* SUMMARY
+/* process Delivered-To: headers
+/* SYNOPSIS
+/* #include <delivered_hdr.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * Utility library.
+ */
+#include <vstream.h>
+
+ /*
+ * External interface.
+ */
+typedef struct DELIVERED_HDR_INFO DELIVERED_HDR_INFO;
+extern DELIVERED_HDR_INFO *delivered_hdr_init(VSTREAM *, off_t);
+extern int delivered_hdr_find(DELIVERED_HDR_INFO *, const char *);
+extern void delivered_hdr_free(DELIVERED_HDR_INFO *);
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+#endif
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20070402"
+#define MAIL_RELEASE_DATE "20070422"
#define MAIL_VERSION_NUMBER "2.5"
#ifdef SNAPSHOT
*/
extern CLNT_STREAM *rewrite_clnt_stream;
+static time_t last_expire;
static VSTRING *last_class;
static VSTRING *last_sender;
static VSTRING *last_addr;
*/
#define IFSET(flag, text) ((reply->flags & (flag)) ? (text) : "")
- if (*addr && strcmp(addr, STR(last_addr)) == 0
+ if (event_time() < last_expire
+ && *addr && strcmp(addr, STR(last_addr)) == 0
&& strcmp(class, STR(last_class)) == 0
&& strcmp(sender, STR(last_sender)) == 0) {
vstring_strcpy(reply->transport, STR(last_reply.transport));
vstring_strcpy(last_reply.nexthop, STR(reply->nexthop));
vstring_strcpy(last_reply.recipient, STR(reply->recipient));
last_reply.flags = reply->flags;
+ last_expire = event_time() + 30; /* XXX make configurable */
}
/* resolve_clnt_free - destroy reply */
*/
CLNT_STREAM *rewrite_clnt_stream = 0;
+static time_t last_expire;
static VSTRING *last_rule;
static VSTRING *last_addr;
static VSTRING *last_result;
/*
* Peek at the cache.
*/
- if (strcmp(addr, STR(last_addr)) == 0
+ if (event_time() < last_expire
+ && strcmp(addr, STR(last_addr)) == 0
&& strcmp(rule, STR(last_rule)) == 0) {
vstring_strcpy(result, STR(last_result));
if (msg_verbose)
vstring_strcpy(last_rule, rule);
vstring_strcpy(last_addr, addr);
vstring_strcpy(last_result, STR(result));
+ last_expire = event_time() + 30; /* XXX make configurable */
return (result);
}
SHELL = /bin/sh
-SRCS = alias.c command.c delivered.c dotforward.c file.c forward.c \
+SRCS = alias.c command.c dotforward.c file.c forward.c \
include.c indirect.c local.c mailbox.c recipient.c resolve.c token.c \
deliver_attr.c maildir.c biff_notify.c unknown.c \
local_expand.c
-OBJS = alias.o command.o delivered.o dotforward.o file.o forward.o \
+OBJS = alias.o command.o dotforward.o file.o forward.o \
include.o indirect.o local.o mailbox.o recipient.o resolve.o token.o \
deliver_attr.o maildir.o biff_notify.o unknown.o \
local_expand.o
alias.o: ../../include/canon_addr.h
alias.o: ../../include/defer.h
alias.o: ../../include/deliver_request.h
+alias.o: ../../include/delivered_hdr.h
alias.o: ../../include/dict.h
alias.o: ../../include/dsn.h
alias.o: ../../include/dsn_buf.h
command.o: ../../include/bounce.h
command.o: ../../include/defer.h
command.o: ../../include/deliver_request.h
+command.o: ../../include/delivered_hdr.h
command.o: ../../include/dict.h
command.o: ../../include/dsn.h
command.o: ../../include/dsn_buf.h
deliver_attr.o: ../../include/attr.h
deliver_attr.o: ../../include/been_here.h
deliver_attr.o: ../../include/deliver_request.h
+deliver_attr.o: ../../include/delivered_hdr.h
deliver_attr.o: ../../include/dict.h
deliver_attr.o: ../../include/dsn.h
deliver_attr.o: ../../include/dsn_buf.h
deliver_attr.o: ../../include/vstring.h
deliver_attr.o: deliver_attr.c
deliver_attr.o: local.h
-delivered.o: ../../include/argv.h
-delivered.o: ../../include/attr.h
-delivered.o: ../../include/been_here.h
-delivered.o: ../../include/deliver_request.h
-delivered.o: ../../include/dict.h
-delivered.o: ../../include/dsn.h
-delivered.o: ../../include/dsn_buf.h
-delivered.o: ../../include/header_opts.h
-delivered.o: ../../include/htable.h
-delivered.o: ../../include/is_header.h
-delivered.o: ../../include/maps.h
-delivered.o: ../../include/mbox_conf.h
-delivered.o: ../../include/msg.h
-delivered.o: ../../include/msg_stats.h
-delivered.o: ../../include/quote_822_local.h
-delivered.o: ../../include/quote_flags.h
-delivered.o: ../../include/rec_type.h
-delivered.o: ../../include/recipient_list.h
-delivered.o: ../../include/record.h
-delivered.o: ../../include/resolve_clnt.h
-delivered.o: ../../include/stringops.h
-delivered.o: ../../include/sys_defs.h
-delivered.o: ../../include/tok822.h
-delivered.o: ../../include/vbuf.h
-delivered.o: ../../include/vstream.h
-delivered.o: ../../include/vstring.h
-delivered.o: ../../include/vstring_vstream.h
-delivered.o: delivered.c
-delivered.o: local.h
dotforward.o: ../../include/argv.h
dotforward.o: ../../include/attr.h
dotforward.o: ../../include/been_here.h
dotforward.o: ../../include/bounce.h
dotforward.o: ../../include/deliver_request.h
+dotforward.o: ../../include/delivered_hdr.h
dotforward.o: ../../include/dict.h
dotforward.o: ../../include/dsn.h
dotforward.o: ../../include/dsn_buf.h
file.o: ../../include/defer.h
file.o: ../../include/deliver_flock.h
file.o: ../../include/deliver_request.h
+file.o: ../../include/delivered_hdr.h
file.o: ../../include/dict.h
file.o: ../../include/dsn.h
file.o: ../../include/dsn_buf.h
forward.o: ../../include/bounce.h
forward.o: ../../include/cleanup_user.h
forward.o: ../../include/deliver_request.h
+forward.o: ../../include/delivered_hdr.h
forward.o: ../../include/dict.h
forward.o: ../../include/dsn.h
forward.o: ../../include/dsn_buf.h
include.o: ../../include/bounce.h
include.o: ../../include/defer.h
include.o: ../../include/deliver_request.h
+include.o: ../../include/delivered_hdr.h
include.o: ../../include/dict.h
include.o: ../../include/dsn.h
include.o: ../../include/dsn_buf.h
indirect.o: ../../include/bounce.h
indirect.o: ../../include/defer.h
indirect.o: ../../include/deliver_request.h
+indirect.o: ../../include/delivered_hdr.h
indirect.o: ../../include/dict.h
indirect.o: ../../include/dsn.h
indirect.o: ../../include/dsn_buf.h
local.o: ../../include/been_here.h
local.o: ../../include/deliver_completed.h
local.o: ../../include/deliver_request.h
+local.o: ../../include/delivered_hdr.h
local.o: ../../include/dict.h
local.o: ../../include/dsn.h
local.o: ../../include/dsn_buf.h
local_expand.o: ../../include/attr.h
local_expand.o: ../../include/been_here.h
local_expand.o: ../../include/deliver_request.h
+local_expand.o: ../../include/delivered_hdr.h
local_expand.o: ../../include/dict.h
local_expand.o: ../../include/dsn.h
local_expand.o: ../../include/dsn_buf.h
mailbox.o: ../../include/defer.h
mailbox.o: ../../include/deliver_pass.h
mailbox.o: ../../include/deliver_request.h
+mailbox.o: ../../include/delivered_hdr.h
mailbox.o: ../../include/dict.h
mailbox.o: ../../include/dsn.h
mailbox.o: ../../include/dsn_buf.h
maildir.o: ../../include/bounce.h
maildir.o: ../../include/defer.h
maildir.o: ../../include/deliver_request.h
+maildir.o: ../../include/delivered_hdr.h
maildir.o: ../../include/dict.h
maildir.o: ../../include/dsn.h
maildir.o: ../../include/dsn_buf.h
recipient.o: ../../include/canon_addr.h
recipient.o: ../../include/defer.h
recipient.o: ../../include/deliver_request.h
+recipient.o: ../../include/delivered_hdr.h
recipient.o: ../../include/dict.h
recipient.o: ../../include/dsn.h
recipient.o: ../../include/dsn_buf.h
resolve.o: ../../include/bounce.h
resolve.o: ../../include/defer.h
resolve.o: ../../include/deliver_request.h
+resolve.o: ../../include/delivered_hdr.h
resolve.o: ../../include/dict.h
resolve.o: ../../include/dsn.h
resolve.o: ../../include/dsn_buf.h
token.o: ../../include/bounce.h
token.o: ../../include/defer.h
token.o: ../../include/deliver_request.h
+token.o: ../../include/delivered_hdr.h
token.o: ../../include/dict.h
token.o: ../../include/dsn.h
token.o: ../../include/dsn_buf.h
unknown.o: ../../include/bounce.h
unknown.o: ../../include/deliver_pass.h
unknown.o: ../../include/deliver_request.h
+unknown.o: ../../include/delivered_hdr.h
unknown.o: ../../include/dict.h
unknown.o: ../../include/dsn.h
unknown.o: ../../include/dsn_buf.h
+++ /dev/null
-/*++
-/* NAME
-/* delivered 3
-/* SUMMARY
-/* process Delivered-To: headers
-/* SYNOPSIS
-/* #include "local.h"
-/*
-/* HTABLE *delivered_init(attr)
-/* DELIVER_ATTR attr;
-/*
-/* int delivered_find(table, address)
-/* HTABLE *table;
-/* const char *address;
-/*
-/* void delivered_free(table)
-/* HTABLE *table;
-/* DESCRIPTION
-/* This module processes addresses in Delivered-To: headers.
-/* These headers are added by some mail delivery systems, for the
-/* purpose of breaking mail forwarding loops. N.B. This solves
-/* a different problem than the Received: hop count limit. Hop
-/* counts are used to limit the impact of mail routing problems.
-/*
-/* delivered_init() extracts Delivered-To: header addresses
-/* from the specified message, and returns a table with the
-/* result.
-/*
-/* delivered_find() looks up the address in the lookup table,
-/* and returns non-zero when the address was found. The
-/* address argument must be in internalized form.
-/*
-/* delivered_free() releases storage that was allocated by
-/* delivered_init().
-/*
-/* Arguments:
-/* .IP state
-/* The attributes that specify the message, recipient and more.
-/* .IP table
-/* A table with extracted Delivered-To: addresses.
-/* .IP address
-/* A recipient address, internal form.
-/* DIAGNOSTICS
-/* Fatal errors: out of memory.
-/* SEE ALSO
-/* LICENSE
-/* .ad
-/* .fi
-/* The Secure Mailer license must be distributed with this software.
-/* AUTHOR(S)
-/* Wietse Venema
-/* IBM T.J. Watson Research
-/* P.O. Box 704
-/* Yorktown Heights, NY 10598, USA
-/*--*/
-
-/* System library. */
-
-#include <sys_defs.h>
-#include <unistd.h>
-#include <string.h>
-#include <ctype.h>
-
-/* Utility library. */
-
-#include <msg.h>
-#include <htable.h>
-#include <vstring.h>
-#include <vstream.h>
-#include <vstring_vstream.h>
-#include <stringops.h>
-
-/* Global library. */
-
-#include <record.h>
-#include <rec_type.h>
-#include <is_header.h>
-#include <quote_822_local.h>
-#include <header_opts.h>
-
-/* Application-specific. */
-
-#include "local.h"
-
-static VSTRING *buf;
-
-/* delivered_init - extract delivered-to information from the message */
-
-HTABLE *delivered_init(DELIVER_ATTR attr)
-{
- char *cp;
- HTABLE *table = htable_create(0);
- HEADER_OPTS *hdr;
-
- if (buf == 0)
- buf = vstring_alloc(10);
-
- if (vstream_fseek(attr.fp, attr.offset, SEEK_SET) < 0)
- msg_fatal("seek queue file %s: %m", VSTREAM_PATH(attr.fp));
-
- /*
- * XXX Assume that normal mail systems produce headers that fit in a
- * REC_TYPE_NORM record. Lowercase the delivered-to addresses for
- * consistency.
- */
- while (rec_get(attr.fp, buf, 0) == REC_TYPE_NORM) {
- if (is_header(STR(buf))) {
- if ((hdr = header_opts_find(STR(buf))) != 0
- && hdr->type == HDR_DELIVERED_TO) {
- cp = STR(buf) + strlen(hdr->name) + 1;
- while (ISSPACE(*cp))
- cp++;
- lowercase(cp);
- if (msg_verbose)
- msg_info("delivered_init: %s", cp);
- htable_enter(table, cp, (char *) 0);
- }
- } else if (ISSPACE(STR(buf)[0])) {
- continue;
- } else {
- break;
- }
- }
- return (table);
-}
-
-/* delivered_find - look up recipient in delivered table */
-
-int delivered_find(HTABLE *table, const char *address)
-{
- HTABLE_INFO *ht;
-
- /*
- * mail_copy() uses quote_822_local() when writing the Delivered-To:
- * header. We must therefore apply the same transformation when looking
- * up the recipient. Lowercase the delivered-to address for consistency.
- */
- quote_822_local(buf, address);
- lowercase(STR(buf));
- ht = htable_locate(table, STR(buf));
- return (ht != 0);
-}
state.msg_attr.request = rqst;
RESET_OWNER_ATTR(state.msg_attr, state.level);
RESET_USER_ATTR(usr_attr, state.level);
- state.loop_info = delivered_init(state.msg_attr); /* delivered-to */
+ state.loop_info = delivered_hdr_init(rqst->fp, rqst->data_offset);
state.request = rqst;
/*
/*
* Clean up.
*/
- delivered_free(state.loop_info);
+ delivered_hdr_free(state.loop_info);
deliver_attr_free(&state.msg_attr);
return (msg_stat);
#include <maps.h>
#include <dsn_buf.h>
#include <dsn.h>
+#include <delivered_hdr.h>
/*
* User attributes: these control the privileges for delivery to external
int level; /* nesting level, for logging */
DELIVER_ATTR msg_attr; /* message attributes */
BH_TABLE *dup_filter; /* internal duplicate filter */
- HTABLE *loop_info; /* external loop filter */
+ DELIVERED_HDR_INFO *loop_info; /* external loop filter */
DELIVER_REQUEST *request; /* as from queue manager */
} LOCAL_STATE;
extern int local_deliver_hdr_mask;
- /*
- * delivered.c
- */
-extern HTABLE *delivered_init(DELIVER_ATTR);
-extern int delivered_find(HTABLE *, const char *);
-
-#define delivered_free(t) htable_free((t), (void (*) (char *)) 0)
-
/*
* forward.c
*/
* need for VERP specific bouncing code, at the cost of complicating the
* normal bounce sending procedure, but would simplify the code below.
*/
- if (delivered_find(state.loop_info, state.msg_attr.rcpt.address)) {
+ if (delivered_hdr_find(state.loop_info, state.msg_attr.rcpt.address)) {
VSTRING *canon_owner = 0;
if (var_ownreq_special) {
pipe.o: ../../include/defer.h
pipe.o: ../../include/deliver_completed.h
pipe.o: ../../include/deliver_request.h
+pipe.o: ../../include/delivered_hdr.h
pipe.o: ../../include/dict.h
pipe.o: ../../include/dsn.h
pipe.o: ../../include/dsn_buf.h
/* SINGLE-RECIPIENT DELIVERY
/* .ad
/* .fi
-/* Some external commands cannot handle more than one recipient
-/* per delivery request. Examples of such transports are pagers
-/* or fax machines.
+/* Some destinations cannot handle more than one recipient per
+/* delivery request. Examples are pagers or fax machines.
+/* In addition, multi-recipient delivery is undesirable when
+/* prepending a \fBDelivered-to:\fR or \fBX-Original-To:\fR
+/* message header.
/*
/* To prevent Postfix from sending multiple recipients per delivery
/* request, specify
/* .IP \fBD\fR
/* Prepend a "\fBDelivered-To: \fIrecipient\fR" message header with the
/* envelope recipient address. Note: for this to work, the
-/* \fItransport\fB_destination_recipient_limit\fR must be 1.
+/* \fItransport\fB_destination_recipient_limit\fR must be 1
+/* (see SINGLE-RECIPIENT DELIVERY above for details).
+/* .sp
+/* This code also enforces loop detection (Postfix 2.5 and later).
+/* If a message already contains a \fBDelivered-To:\fR header
+/* with the same recipient address, then the message is
+/* returned as undeliverable.
/* .sp
/* This feature is available as of Postfix 2.0.
/* .IP \fBF\fR
/* .IP \fBO\fR
/* Prepend an "\fBX-Original-To: \fIrecipient\fR" message header
/* with the recipient address as given to Postfix. Note: for this to
-/* work, the \fItransport\fB_destination_recipient_limit\fR must be 1.
+/* work, the \fItransport\fB_destination_recipient_limit\fR must be 1
+/* (see SINGLE-RECIPIENT DELIVERY above for details).
/* .sp
/* This feature is available as of Postfix 2.0.
/* .IP \fBR\fR
/* Prepend a \fBReturn-Path:\fR message header with the envelope sender
/* address.
/* .IP \fBh\fR
-/* Fold the command-line \fB$recipient\fR domain name and \fB$nexthop\fR
-/* host name to lower case.
+/* Fold the command-line \fB$recipient\fR address domain part
+/* (text to the right of the right-most \fB@\fR character) to
+/* lower case; fold the entire command-line \fB$domain\fR and
+/* \fB$nexthop\fR host or domain information to lower case.
/* This is recommended for delivery via \fBUUCP\fR.
/* .IP \fBq\fR
/* Quote white space and other special characters in the command-line
/* command -f $sender -- $recipient (\fIgood\fR)
/* .fi
/* .IP
-/* This feature is available with Postfix 2.3 and later.
+/* This feature is available as of Postfix 2.3.
/* .IP "\fBsize\fR=\fIsize_limit\fR (optional)"
/* Messages greater in size than this limit (in bytes) will
/* be returned to the sender as undeliverable.
/* This macro expands to the remote client protocol.
/* .sp
/* This is available in Postfix 2.2 and later.
+/* .IP \fB${\fBdomain\fR}\fR
+/* This macro expands to the domain portion of the recipient
+/* address. For example, with an address \fIuser+foo@domain\fR
+/* the domain is \fIdomain\fR.
+/* .sp
+/* This information is modified by the \fBh\fR flag for case folding.
+/* .sp
+/* This is available in Postfix 2.5 and later.
/* .IP \fB${\fBextension\fR}\fR
/* This macro expands to the extension part of a recipient address.
/* For example, with an address \fIuser+foo@domain\fR the extension is
#include <dsn_util.h>
#include <dsn_buf.h>
#include <sys_exits.h>
+#include <delivered_hdr.h>
/* Single server skeleton. */
#define PIPE_DICT_USER "user" /* key */
#define PIPE_DICT_EXTENSION "extension" /* key */
#define PIPE_DICT_MAILBOX "mailbox" /* key */
+#define PIPE_DICT_DOMAIN "domain"/* key */
#define PIPE_DICT_SIZE "size" /* key */
#define PIPE_DICT_CLIENT_ADDR "client_address" /* key */
#define PIPE_DICT_CLIENT_NAME "client_hostname" /* key */
#define PIPE_FLAG_USER (1<<1)
#define PIPE_FLAG_EXTENSION (1<<2)
#define PIPE_FLAG_MAILBOX (1<<3)
+#define PIPE_FLAG_DOMAIN (1<<4)
/*
* Additional flags. These are colocated with mail_copy() flags. Allow some
PIPE_DICT_USER, PIPE_FLAG_USER,
PIPE_DICT_EXTENSION, PIPE_FLAG_EXTENSION,
PIPE_DICT_MAILBOX, PIPE_FLAG_MAILBOX,
+ PIPE_DICT_DOMAIN, PIPE_FLAG_DOMAIN,
PIPE_DICT_SIZE, 0,
PIPE_DICT_CLIENT_ADDR, 0,
PIPE_DICT_CLIENT_NAME, 0,
PIPE_STATE state;
int i;
char *ext;
+ char *dom;
/*
* This appears to be simple operation (replace $name by its expansion).
dict_update(PIPE_DICT_TABLE, PIPE_DICT_MAILBOX, STR(buf));
}
+ /*
+ * This argument contains $domain. Extract the domain name:
+ * anything to the right of the rightmost @.
+ */
+ if (state.expand_flag & PIPE_FLAG_DOMAIN) {
+ morph_recipient(buf, rcpt_list->info[i].address,
+ flags & PIPE_OPT_FOLD_FLAGS);
+ dom = split_at_right(STR(buf), '@');
+ if (dom == 0) {
+ msg_warn("no @ in recipient address: %s",
+ rcpt_list->info[i].address);
+ dom = ""; /* insert null arg */
+ }
+ dict_update(PIPE_DICT_TABLE, PIPE_DICT_DOMAIN, dom);
+ }
+
/*
* Done.
*/
return (deliver_status);
}
+ /*
+ * Report mail delivery loops. By definition, this requires
+ * single-recipient delivery. Don't silently lose recipients.
+ */
+ if (attr.flags & MAIL_COPY_DELIVERED) {
+ DELIVERED_HDR_INFO *info;
+ RECIPIENT *rcpt;
+ int loop_found;
+
+ if (request->rcpt_list.len > 1)
+ msg_panic("%s: delivered-to enabled with multi-recipient request",
+ myname);
+ info = delivered_hdr_init(request->fp, request->data_offset);
+ rcpt = request->rcpt_list.info;
+ loop_found = delivered_hdr_find(info, rcpt->address);
+ delivered_hdr_free(info);
+ if (loop_found) {
+ dsb_simple(why, "5.4.6", "mail forwarding loop for %s",
+ rcpt->address);
+ deliver_status = eval_command_status(PIPE_STAT_BOUNCE, service,
+ request, request->fp, why);
+ DELIVER_MSG_CLEANUP();
+ return (deliver_status);
+ }
+ }
+
/*
* Deliver. Set the nexthop and sender variables, and expand the command
* argument vector. Recipients will be expanded on the fly. XXX Rewrite
myfree(state->saved_redirect);
state->saved_redirect = 0;
}
+ if (state->saved_bcc) {
+ myfree(state->saved_bcc);
+ state->saved_bcc = 0;
+ }
state->saved_flags = 0;
#ifdef DELAY_ACTION
state->saved_delay = 0;
if (state->saved_redirect)
rec_fprintf(state->cleanup, REC_TYPE_RDR, "%s",
state->saved_redirect);
+ if (state->saved_bcc) {
+ rec_fprintf(state->cleanup, REC_TYPE_RCPT, "%s",
+ state->saved_bcc);
+ rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%d",
+ MAIL_ATTR_DSN_NOTIFY, DSN_NOTIFY_NEVER);
+ }
if (state->saved_flags)
rec_fprintf(state->cleanup, REC_TYPE_FLGS, "%d",
state->saved_flags);
int discard; /* discard message */
char *saved_filter; /* postponed filter action */
char *saved_redirect; /* postponed redirect action */
+ char *saved_bcc; /* postponed bcc action */
int saved_flags; /* postponed hold/discard */
#ifdef DELAY_ACTION
int saved_delay; /* postponed deferred delay */
}
}
+ /*
+ * BCC means deliver to designated recipient. But we may still
+ * change our mind, and reject/discard the message for other reasons.
+ */
+#ifdef SNAPSHOT
+ if (STREQUAL(value, "BCC", cmd_len)) {
+#ifndef TEST
+ if (can_delegate_action(state, table, "BCC", reply_class) == 0)
+ return (SMTPD_CHECK_DUNNO);
+#endif
+ if (strchr(cmd_text, '@') == 0) {
+ msg_warn("access table %s entry \"%s\" requires user@domain target",
+ table, datum);
+ return (SMTPD_CHECK_DUNNO);
+ } else {
+ vstring_sprintf(error_text, "<%s>: %s triggers BCC %s",
+ reply_name, reply_class, cmd_text);
+ log_whatsup(state, "bcc", STR(error_text));
+#ifndef TEST
+ UPDATE_STRING(state->saved_bcc, cmd_text);
+#endif
+ return (SMTPD_CHECK_DUNNO);
+ }
+ }
+#endif
+
/*
* DEFER_IF_PERMIT changes "permit" into "maybe". Use optional text or
* generate a generic error response.
state->proxy_xforward_features = 0;
state->saved_filter = 0;
state->saved_redirect = 0;
+ state->saved_bcc = 0;
state->saved_flags = 0;
#ifdef DELAY_ACTION
state->saved_delay = 0;
transport.o: ../../include/argv.h
transport.o: ../../include/attr.h
transport.o: ../../include/dict.h
+transport.o: ../../include/events.h
transport.o: ../../include/iostuff.h
transport.o: ../../include/mail_params.h
transport.o: ../../include/mail_proto.h
#include <vstring.h>
#include <split_at.h>
#include <dict.h>
+#include <events.h>
/* Global library. */
tp->transport_path = maps_create(transport_maps_name, transport_maps,
DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
| DICT_FLAG_NO_REGSUB);
- tp->wildcard_channel = tp->wildcard_nexthop = 0;
+ tp->wildcard_channel = vstring_alloc(10);
+ tp->wildcard_nexthop = vstring_alloc(10);
tp->transport_errno = 0;
+ tp->expire = 0;
return (tp);
}
static void transport_wildcard_init(TRANSPORT_INFO *tp)
{
- VSTRING *channel = vstring_alloc(10);
- VSTRING *nexthop = vstring_alloc(10);
/*
* Technically, the wildcard lookup pattern is redundant. A static map
#define FULL 0
#define PARTIAL DICT_FLAG_FIXED
- if (find_transport_entry(tp, WILDCARD, "", FULL, channel, nexthop)) {
+ if (find_transport_entry(tp, WILDCARD, "", FULL,
+ tp->wildcard_channel,
+ tp->wildcard_nexthop)) {
tp->transport_errno = 0;
- if (tp->wildcard_channel)
- vstring_free(tp->wildcard_channel);
- tp->wildcard_channel = channel;
- if (tp->wildcard_nexthop)
- vstring_free(tp->wildcard_nexthop);
- tp->wildcard_nexthop = nexthop;
if (msg_verbose)
msg_info("wildcard_{chan:hop}={%s:%s}",
- vstring_str(channel), vstring_str(nexthop));
+ vstring_str(tp->wildcard_channel),
+ vstring_str(tp->wildcard_nexthop));
} else {
tp->transport_errno = dict_errno;
- vstring_free(channel);
- vstring_free(nexthop);
+ VSTRING_RESET(tp->wildcard_channel);
+ VSTRING_RESET(tp->wildcard_nexthop);
}
+ tp->expire = event_time() + 30; /* XXX make configurable */
}
/* transport_lookup - map a transport domain */
/*
* Fall back to the wild-card entry.
*/
- if (tp->transport_errno)
+ if (tp->transport_errno || event_time() > tp->expire)
transport_wildcard_init(tp);
if (tp->transport_errno) {
dict_errno = tp->transport_errno;
return (NOTFOUND);
- } else if (tp->wildcard_channel) {
+ } else if (tp->wildcard_channel && VSTRING_LEN(tp->wildcard_channel)) {
update_entry(STR(tp->wildcard_channel), STR(tp->wildcard_nexthop),
rcpt_domain, channel, nexthop);
return (FOUND);
/* DESCRIPTION
/* .nf
+ /*
+ * System library.
+ */
+#include <time.h>
+
/*
* Utility library.
*/
VSTRING *wildcard_channel;
VSTRING *wildcard_nexthop;
int transport_errno;
+ time_t expire;
} TRANSPORT_INFO;
extern TRANSPORT_INFO *transport_pre_init(const char *, const char *);