2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-30 13:48:06 +00:00

snapshot-20010709

This commit is contained in:
Wietse Venema
2001-07-09 00:00:00 -05:00
committed by Viktor Dukhovni
parent 7e8044da83
commit a94bf41134
44 changed files with 987 additions and 116 deletions

1
postfix/.indent.pro vendored
View File

@@ -1,3 +1,4 @@
-TABOUNCE
-TALIAS_TOKEN -TALIAS_TOKEN
-TARGV -TARGV
-TBH_TABLE -TBH_TABLE

View File

@@ -25,7 +25,7 @@ lmtp support yes (client)
m4 config no m4 config no
mail to command yes (configurable for .forward, aliases, :include:) mail to command yes (configurable for .forward, aliases, :include:)
mail to file yes (configurable for .forward, aliases, :include:) mail to file yes (configurable for .forward, aliases, :include:)
maildir yes (with procmail) maildir yes
mailertable yes (it's called transport) mailertable yes (it's called transport)
mailq yes mailq yes
majordomo yes (edit approve script to delete /delivered-to/i) majordomo yes (edit approve script to delete /delivered-to/i)
@@ -38,6 +38,7 @@ nis tables yes
nis+ tables not yet nis+ tables not yet
pipeline option yes (server and client) pipeline option yes (server and client)
pop/imap yes (with third-party daemons that use /var[/spool]/mail) pop/imap yes (with third-party daemons that use /var[/spool]/mail)
qmqp server yes (with verp support)
rbl support yes rbl support yes
return-receipt: not yet return-receipt: not yet
sasl support yes (compile time option) sasl support yes (compile time option)
@@ -55,5 +56,6 @@ user+extension yes (also: .forward+extension)
user-extension yes (also: .forward-extension) user-extension yes (also: .forward-extension)
user.lock yes (runtime configurable) user.lock yes (runtime configurable)
uucp support yes (sends user@domain recipients) uucp support yes (sends user@domain recipients)
verp support yes (delimiters are configurable)
virtual domains yes virtual domains yes
year 2000 safe yes year 2000 safe yes

View File

@@ -5292,13 +5292,12 @@ Apologies for any names omitted.
Cleanup: the virtual delivery agent was poorly integrated Cleanup: the virtual delivery agent was poorly integrated
so that the SMTP server and queue manager did not reject so that the SMTP server and queue manager did not reject
mail for unknown users. Files: smtpd/smtpd_check.c, mail for unknown users. Files: smtpd/smtpd_check.c.
*qmgr/qmgr_message.c.
20010705 20010705
Feature: QMQP server for compatibility with the ezmlm list Feature: QMQP server, compatible with qmail and the ezmlm
manager. Files: util/netstring.[hc], qmqpd/qmqpd*.c. list manager. Files: util/netstring.[hc], qmqpd/qmqpd*.c.
20010706 20010706
@@ -5309,3 +5308,17 @@ Apologies for any names omitted.
Bugfix: with disable_dns=yes, the SMTP client treated all Bugfix: with disable_dns=yes, the SMTP client treated all
host lookup errors as permanent. File: smtp/smtp_addr.c. host lookup errors as permanent. File: smtp/smtp_addr.c.
20010709
Feature: VERP support, based on a patch by Peng Yong, and
with the missing parts filled in so that the Postfix bounce
daemon can send one VERP bounce per undeliverable recipient.
Files: , sendmail/sendmail.c, smtpd/smtpd.c, qmgr/qmgr_deliver.c,
bounce/bounce_notify_verp.c, qmqpd/qmqpd.c, plus a couple
support routines in the global library.
Cleanup: with recipient_delimiter=+ (or any character other
than -) Postfix will now recognize address extensions even
with owner-foo+extension addresses. This is necessary to
make VERP work for mailing lists.

View File

@@ -145,7 +145,7 @@ expect to run more than 1000 delivery processes, you may need to
override the definition of the FD_SETSIZE macro to make select() override the definition of the FD_SETSIZE macro to make select()
work correctly: work correctly:
% make makefiles CCARGS=-FD_SETSIZE=2048 % make makefiles CCARGS=-DFD_SETSIZE=2048
In any case, if the command In any case, if the command

View File

@@ -6,8 +6,8 @@ that Postfix can be used as a backend for the Ezmlm-idx mailing
list manager. This support includes qmqp-source and qmqp-sink list manager. This support includes qmqp-source and qmqp-sink
programs for protocol stress testing. programs for protocol stress testing.
Turning on the QMQP service Turning on the Postfix QMQP service
=========================== ===================================
To enable QMQP server support on an existing Postfix system you To enable QMQP server support on an existing Postfix system you
have to add the following line to /etc/postfix/master.cf: have to add the following line to /etc/postfix/master.cf:
@@ -15,8 +15,8 @@ have to add the following line to /etc/postfix/master.cf:
628 inet n - n - - qmqpd 628 inet n - n - - qmqpd
QMQP server access control Postfix QMQP server access control
========================== ==================================
By default, the QMQP server does not accept mail from any client. By default, the QMQP server does not accept mail from any client.
This is because the QMQP server relays mail to any destination This is because the QMQP server relays mail to any destination
@@ -37,3 +37,9 @@ instead.
Patterns are separated by whitespace and/or commas. In order to Patterns are separated by whitespace and/or commas. In order to
reverse the result, precede a non-file name pattern with an reverse the result, precede a non-file name pattern with an
exclamation point (!). exclamation point (!).
Setting up Ezmlm-idx to use Postfix QMQP support
================================================
You need to list the Postfix IP address in a suitable configuration
file. See the ezmlm-idx documentation for details.

View File

@@ -1,17 +1,33 @@
Incompatible changes with snapshot-20010707 Incompatible changes with snapshot-20010709
=========================================== ===========================================
The SMTP client by default breaks lines > 2048 characters, in order This release introduces a new queue file record type that is used
to avoid problems with mail delivery to fragile SMTP server software. only for messages that actually use VERP (variable envelope return
To get the old behavior, specify "smtp_break_lines = no" in the path) support. With this sole exception, the queue file format is
Postfix main.cf file. entirely backwards compatible with previous Postfix releases.
Major changes with snapshot-20010707 The SMTP client now by default breaks lines > 2048 characters, to
avoid mail delivery problems with fragile SMTP server software.
To get the old behavior back, specify "smtp_break_lines = no" in
the Postfix main.cf file.
With recipient_delimiter=+ (or any character other than -) Postfix
will now recognize address extensions even with owner-foo+extension
addresses. This change was necessary to make VERP useful for mailing
list bounce processing.
Major changes with snapshot-20010709
==================================== ====================================
QMQP server support, so that Postfix can be used as a backend mailer QMQP server support, so that Postfix can be used as a backend mailer
for the Ezmlm-idx mailing list manager. The service is disabled by for the ezmlm-idx mailing list manager. You still need qmail to
default. To enable, follow instructions in the README_QMQP file. drive ezmlm and to process mailing list bounces. The QMQP service
is disabled by default. To enable, follow the instructions in the
QMQP_README file.
VERP (variable envelope return path) support. This is enabled by
default. See the VERP_README file for instructions. These instructions
need more examples for how to process bounces automatically.
You can now reject unknown virtual(8) recipients at the SMTP port You can now reject unknown virtual(8) recipients at the SMTP port
by specifying a "domain.name whatever" entry in the tables specified by specifying a "domain.name whatever" entry in the tables specified

96
postfix/VERP_README Normal file
View File

@@ -0,0 +1,96 @@
Postfix VERP support
====================
Postfix supports variable envelope return path addresses, which
means that each recipient receives a customized copy of the message,
with the recipient address encoded in the envelope sender address.
This concept was popularized by the qmail MTA and by the ezmlm
mailing list manager.
When VERP style delivery is requested, Postfix delivers mail with
sender address prefix@origin for a recipient user@domain, with a
sender address that encodes the recipient as follows:
prefix+user=domain@origin
so that undeliverable mail reveals what address was undeliverable.
The + and = are the default VERP delimiters. You can specify non-
default delimiters in main.cf with the default_verp_delimiters
configuration parameter (default value: +=). Specify two characters;
the first delimiter should match the $recipient_delimiter setting.
Using VERP with majordomo etc. mailing lists
============================================
In order to make VERP useful with majordomo etc. mailing lists,
you would configure the list manager to submit mail as:
sendmail -V -f owner-listname other-arguments...
This text assumes that you have set up an owner-listname alias that
routes undeliverable mail to a real person:
/etc/aliases:
owner-listname: yourname+listname
In order to process bounces we are going to make extensive use of
address extension tricks.
You need to tell Postfix that + is the separator between an address
and its optional address extension, that address extensions are
appended to .forward file names, and that address extensions are
to be discarded when doing alias expansions:
/etc/postfix/main.cf:
recipient_delimiter = +
forward_path = $home/.forward${recipient_delimiter}${extension},$home/.forward
propagate_unmatched_extensions = canonical, virtual
(the last two parameter settings are default settings).
You need to set up a file named .forward+listname with the commands
that process all the mail that is sent to the owner-listname address:
~/.forward+listname:
"|/some/where/command ..."
With this set up, undeliverable mail for user@domain will be returned
to the following address:
owner-listname+user=domain@your.domain
which is processed by the command in your .forward+listname file.
It is left as an exercise for the reader to parse the To: header
line and to pull out the user=domain part from the recipient address.
VERP support in the Postfix SMTP server
=======================================
The Postfix SMTP server has a new command XVERP to enable VERP
style delivery. The syntax allows two forms:
MAIL FROM:<sender@domain> XVERP
MAIL FROM:<sender@domain> XVERP=xy
where x and y are the VERP delimiters. When no VERP delimiters
are specified, Postfix uses the two characters specified with the
default_verp_delimiters configuration parameter.
VERP support in the Postfix sendmail command
============================================
The Postfix sendmail command has a -V flag to request VERP style
delivery. It is not possible to override the default VERP delimiters.
VERP support in the Postfix QMQP server
=======================================
When the Postfix QMQP server receives mail with a an envelope sender
address of the form:
prefix-@origin-@[]
Postfix generates VERP sender addresses using prefix@domain as the
original sender address, and using "-=" as the VERP delimiters.

View File

@@ -94,33 +94,38 @@ SENDMAIL(1) SENDMAIL(1)
<b>-U</b> (ignored) <b>-U</b> (ignored)
Initial user submission. Initial user submission.
<b>-bd</b> Go into daemon mode. This mode of operation is <b>-V</b> Variable Envelope Return Path. Given an envelope
sender address <i>prefix</i>-@<i>origin</i>, each recipient
<i>user@domain</i> receives mail with a personalized enve-
lope sender address <i>prefix</i><b>-</b><i>user=domain</i>@<i>origin</i>.
<b>-bd</b> Go into daemon mode. This mode of operation is
implemented by executing the <b>postfix</b> <b>start</b> command. implemented by executing the <b>postfix</b> <b>start</b> command.
<b>-bi</b> Initialize alias database. See the <b>newaliases</b> com- <b>-bi</b> Initialize alias database. See the <b>newaliases</b> com-
mand above. mand above.
<b>-bm</b> Read mail from standard input and arrange for <b>-bm</b> Read mail from standard input and arrange for
delivery. This is the default mode of operation. delivery. This is the default mode of operation.
<b>-bp</b> List the mail queue. See the <b>mailq</b> command above. <b>-bp</b> List the mail queue. See the <b>mailq</b> command above.
<b>-bs</b> Stand-alone SMTP server mode. Read SMTP commands <b>-bs</b> Stand-alone SMTP server mode. Read SMTP commands
from standard input, and write responses to stan- from standard input, and write responses to stan-
dard output. This mode of operation is implemented dard output. This mode of operation is implemented
by running the <a href="smtpd.8.html"><b>smtpd</b>(8)</a> daemon. by running the <a href="smtpd.8.html"><b>smtpd</b>(8)</a> daemon.
<b>-f</b> <i>sender</i> <b>-f</b> <i>sender</i>
Set the envelope sender address. This is the Set the envelope sender address. This is the
address where delivery problems are sent to, unless address where delivery problems are sent to, unless
the message contains an <b>Errors-To:</b> message header. the message contains an <b>Errors-To:</b> message header.
<b>-h</b> <i>hop_count</i> (ignored) <b>-h</b> <i>hop_count</i> (ignored)
Hop count limit. Use the <b>hopcount</b><i>_</i><b>limit</b> configura- Hop count limit. Use the <b>hopcount</b><i>_</i><b>limit</b> configura-
tion parameter instead. tion parameter instead.
<b>-i</b> When reading a message from standard input, don't <b>-i</b> When reading a message from standard input, don't
treat a line with only a <b>.</b> character as the end of treat a line with only a <b>.</b> character as the end of
input. input.
<b>-m</b> (ignored) <b>-m</b> (ignored)
@@ -130,68 +135,68 @@ SENDMAIL(1) SENDMAIL(1)
Backwards compatibility. Backwards compatibility.
<b>-oA</b><i>alias_database</i> <b>-oA</b><i>alias_database</i>
Non-default alias database. Specify <i>pathname</i> or Non-default alias database. Specify <i>pathname</i> or
<i>type</i>:<i>pathname</i>. See <a href="postalias.1.html"><b>postalias</b>(1)</a> for details. <i>type</i>:<i>pathname</i>. See <a href="postalias.1.html"><b>postalias</b>(1)</a> for details.
<b>-o7</b> (ignored) <b>-o7</b> (ignored)
<b>-o8</b> (ignored) <b>-o8</b> (ignored)
The message body type. Currently, Postfix imple- The message body type. Currently, Postfix imple-
ments <b>just-send-eight</b>. ments <b>just-send-eight</b>.
<b>-oi</b> When reading a message from standard input, don't <b>-oi</b> When reading a message from standard input, don't
treat a line with only a <b>.</b> character as the end of treat a line with only a <b>.</b> character as the end of
input. input.
<b>-om</b> (ignored) <b>-om</b> (ignored)
The sender is never eliminated from alias etc. The sender is never eliminated from alias etc.
expansions. expansions.
<b>-o</b> <i>x</i> <i>value</i> (ignored) <b>-o</b> <i>x</i> <i>value</i> (ignored)
Set option <i>x</i> to <i>value</i>. Use the equivalent configu- Set option <i>x</i> to <i>value</i>. Use the equivalent configu-
ration parameter in <b>main.cf</b> instead. ration parameter in <b>main.cf</b> instead.
<b>-r</b> <i>sender</i> <b>-r</b> <i>sender</i>
Set the envelope sender address. This is the Set the envelope sender address. This is the
address where delivery problems are sent to, unless address where delivery problems are sent to, unless
the message contains an <b>Errors-To:</b> message header. the message contains an <b>Errors-To:</b> message header.
<b>-q</b> Attempt to deliver all queued mail. This is imple- <b>-q</b> Attempt to deliver all queued mail. This is imple-
mented by kicking the <a href="qmgr.8.html"><b>qmgr</b>(8)</a> daemon. mented by kicking the <a href="qmgr.8.html"><b>qmgr</b>(8)</a> daemon.
<b>-q</b><i>interval</i> (ignored) <b>-q</b><i>interval</i> (ignored)
The interval between queue runs. Use the The interval between queue runs. Use the
<b>queue</b><i>_</i><b>run</b><i>_</i><b>delay</b> configuration parameter instead. <b>queue</b><i>_</i><b>run</b><i>_</i><b>delay</b> configuration parameter instead.
<b>-qR</b><i>site</i> <b>-qR</b><i>site</i>
Schedule immediate delivery of all mail that is Schedule immediate delivery of all mail that is
queued for the named <i>site</i>. Depending on the desti- queued for the named <i>site</i>. Depending on the desti-
nation, this uses "fast flush" service, or it has nation, this uses "fast flush" service, or it has
the same effect as <b>sendmail</b> <b>-q</b>. This is imple- the same effect as <b>sendmail</b> <b>-q</b>. This is imple-
mented by connecting to the local SMTP server. See mented by connecting to the local SMTP server. See
<a href="smtpd.8.html"><b>smtpd</b>(8)</a> for more information about the "fast <a href="smtpd.8.html"><b>smtpd</b>(8)</a> for more information about the "fast
flush" service. flush" service.
<b>-qS</b><i>site</i> <b>-qS</b><i>site</i>
This command is not implemented. Use the slower This command is not implemented. Use the slower
<b>sendmail</b> <b>-q</b> command instead. <b>sendmail</b> <b>-q</b> command instead.
<b>-t</b> Extract recipients from message headers. This <b>-t</b> Extract recipients from message headers. This
requires that no recipients be specified on the requires that no recipients be specified on the
command line. command line.
<b>-v</b> Enable verbose logging for debugging purposes. Mul- <b>-v</b> Enable verbose logging for debugging purposes. Mul-
tiple <b>-v</b> options make the software increasingly tiple <b>-v</b> options make the software increasingly
verbose. verbose.
<b>SECURITY</b> <b>SECURITY</b>
By design, this program is not set-user (or group) id. By design, this program is not set-user (or group) id.
However, it must handle data from untrusted users or However, it must handle data from untrusted users or
untrusted machines. Thus, the usual precautions need to untrusted machines. Thus, the usual precautions need to
be taken against malicious inputs. be taken against malicious inputs.
<b>DIAGNOSTICS</b> <b>DIAGNOSTICS</b>
Problems are logged to <b>syslogd</b>(8) and to the standard Problems are logged to <b>syslogd</b>(8) and to the standard
error stream. error stream.
<b>ENVIRONMENT</b> <b>ENVIRONMENT</b>
@@ -203,7 +208,7 @@ SENDMAIL(1) SENDMAIL(1)
<b>MAIL</b><i>_</i><b>DEBUG</b> <b>MAIL</b><i>_</i><b>DEBUG</b>
Enable debugging with an external command, as spec- Enable debugging with an external command, as spec-
ified with the <b>debugger</b><i>_</i><b>command</b> configuration ified with the <b>debugger</b><i>_</i><b>command</b> configuration
parameter. parameter.
<b>FILES</b> <b>FILES</b>
@@ -211,13 +216,13 @@ SENDMAIL(1) SENDMAIL(1)
/etc/postfix, configuration files /etc/postfix, configuration files
<b>CONFIGURATION</b> <b>PARAMETERS</b> <b>CONFIGURATION</b> <b>PARAMETERS</b>
See the Postfix <b>main.cf</b> file for syntax details and for See the Postfix <b>main.cf</b> file for syntax details and for
default values. Use the <b>postfix</b> <b>reload</b> command after a default values. Use the <b>postfix</b> <b>reload</b> command after a
configuration change. configuration change.
<b>alias</b><i>_</i><b>database</b> <b>alias</b><i>_</i><b>database</b>
Default alias database(s) for <b>newaliases</b>. The Default alias database(s) for <b>newaliases</b>. The
default value for this parameter is system-spe- default value for this parameter is system-spe-
cific. cific.
<b>bounce</b><i>_</i><b>size</b><i>_</i><b>limit</b> <b>bounce</b><i>_</i><b>size</b><i>_</i><b>limit</b>
@@ -233,55 +238,55 @@ SENDMAIL(1) SENDMAIL(1)
initialized. initialized.
<b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b> <b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b>
Increment in verbose logging level when a remote Increment in verbose logging level when a remote
host matches a pattern in the <b>debug</b><i>_</i><b>peer</b><i>_</i><b>list</b> host matches a pattern in the <b>debug</b><i>_</i><b>peer</b><i>_</i><b>list</b>
parameter. parameter.
<b>debug</b><i>_</i><b>peer</b><i>_</i><b>list</b> <b>debug</b><i>_</i><b>peer</b><i>_</i><b>list</b>
List of domain or network patterns. When a remote List of domain or network patterns. When a remote
host matches a pattern, increase the verbose log- host matches a pattern, increase the verbose log-
ging level by the amount specified in the ging level by the amount specified in the
<b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b> parameter. <b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b> parameter.
<b>fast</b><i>_</i><b>flush</b><i>_</i><b>domains</b> <b>fast</b><i>_</i><b>flush</b><i>_</i><b>domains</b>
List of domains that will receive "fast flush" ser- List of domains that will receive "fast flush" ser-
vice (default: all domains that this system is vice (default: all domains that this system is
willing to relay mail to). This greatly improves willing to relay mail to). This greatly improves
the performance of the SMTP <b>ETRN</b> request, and of the performance of the SMTP <b>ETRN</b> request, and of
the <b>sendmail</b> <b>-qR</b> command. For domains not in the the <b>sendmail</b> <b>-qR</b> command. For domains not in the
list, Postfix simply attempts to deliver all queued list, Postfix simply attempts to deliver all queued
mail. mail.
<b>fork</b><i>_</i><b>attempts</b> <b>fork</b><i>_</i><b>attempts</b>
Number of attempts to <b>fork</b>() a process before giv- Number of attempts to <b>fork</b>() a process before giv-
ing up. ing up.
<b>fork</b><i>_</i><b>delay</b> <b>fork</b><i>_</i><b>delay</b>
Delay in seconds between successive <b>fork</b>() Delay in seconds between successive <b>fork</b>()
attempts. attempts.
<b>hopcount</b><i>_</i><b>limit</b> <b>hopcount</b><i>_</i><b>limit</b>
Limit the number of <b>Received:</b> message headers. Limit the number of <b>Received:</b> message headers.
<b>mail</b><i>_</i><b>owner</b> <b>mail</b><i>_</i><b>owner</b>
The owner of the mail queue and of most Postfix The owner of the mail queue and of most Postfix
processes. processes.
<b>command</b><i>_</i><b>directory</b> <b>command</b><i>_</i><b>directory</b>
Directory with Postfix support commands (default: Directory with Postfix support commands (default:
<b>$program</b><i>_</i><b>directory</b>). <b>$program</b><i>_</i><b>directory</b>).
<b>daemon</b><i>_</i><b>directory</b> <b>daemon</b><i>_</i><b>directory</b>
Directory with Postfix daemon programs (default: Directory with Postfix daemon programs (default:
<b>$program</b><i>_</i><b>directory</b>). <b>$program</b><i>_</i><b>directory</b>).
<b>queue</b><i>_</i><b>directory</b> <b>queue</b><i>_</i><b>directory</b>
Top-level directory of the Postfix queue. This is Top-level directory of the Postfix queue. This is
also the root directory of Postfix daemons that run also the root directory of Postfix daemons that run
chrooted. chrooted.
<b>queue</b><i>_</i><b>run</b><i>_</i><b>delay</b> <b>queue</b><i>_</i><b>run</b><i>_</i><b>delay</b>
The time between successive scans of the deferred The time between successive scans of the deferred
queue. queue.
<b>SEE</b> <b>ALSO</b> <b>SEE</b> <b>ALSO</b>
@@ -297,7 +302,7 @@ SENDMAIL(1) SENDMAIL(1)
syslogd(8) system logging syslogd(8) system logging
<b>LICENSE</b> <b>LICENSE</b>
The Secure Mailer license must be distributed with this The Secure Mailer license must be distributed with this
software. software.
<b>AUTHOR(S)</b> <b>AUTHOR(S)</b>

View File

@@ -35,8 +35,8 @@ SMTPD(8) SMTPD(8)
<b>STANDARDS</b> <b>STANDARDS</b>
<a href="http://www.faqs.org/rfcs/rfc821.html">RFC 821</a> (SMTP protocol) <a href="http://www.faqs.org/rfcs/rfc821.html">RFC 821</a> (SMTP protocol)
<a href="http://www.faqs.org/rfcs/rfc1123.html">RFC 1123</a> (Host requirements) <a href="http://www.faqs.org/rfcs/rfc1123.html">RFC 1123</a> (Host requirements)
<a href="http://www.faqs.org/rfcs/rfc1651.html">RFC 1651</a> (SMTP service extensions)
<a href="http://www.faqs.org/rfcs/rfc1652.html">RFC 1652</a> (8bit-MIME transport) <a href="http://www.faqs.org/rfcs/rfc1652.html">RFC 1652</a> (8bit-MIME transport)
<a href="http://www.faqs.org/rfcs/rfc1869.html">RFC 1869</a> (SMTP service extensions)
<a href="http://www.faqs.org/rfcs/rfc1854.html">RFC 1854</a> (SMTP Pipelining) <a href="http://www.faqs.org/rfcs/rfc1854.html">RFC 1854</a> (SMTP Pipelining)
<a href="http://www.faqs.org/rfcs/rfc1870.html">RFC 1870</a> (Message Size Declaration) <a href="http://www.faqs.org/rfcs/rfc1870.html">RFC 1870</a> (Message Size Declaration)
<a href="http://www.faqs.org/rfcs/rfc1985.html">RFC 1985</a> (ETRN command) <a href="http://www.faqs.org/rfcs/rfc1985.html">RFC 1985</a> (ETRN command)

View File

@@ -82,6 +82,11 @@ Log mailer traffic. Use the \fBdebug_peer_list\fR and
\fBdebug_peer_level\fR configuration parameters instead. \fBdebug_peer_level\fR configuration parameters instead.
.IP "\fB-U\fR (ignored)" .IP "\fB-U\fR (ignored)"
Initial user submission. Initial user submission.
.IP \fB-V\fR
Variable Envelope Return Path. Given an envelope sender address
\fIprefix\fR-@\fIorigin\fR, each recipient \fIuser@domain\fR
receives mail with a personalized envelope sender address
\fIprefix\fB-\fIuser=domain\fR@\fIorigin\fR.
.IP \fB-bd\fR .IP \fB-bd\fR
Go into daemon mode. This mode of operation is implemented by Go into daemon mode. This mode of operation is implemented by
executing the \fBpostfix start\fR command. executing the \fBpostfix start\fR command.

View File

@@ -42,8 +42,8 @@ run chrooted at fixed low privilege.
.nf .nf
RFC 821 (SMTP protocol) RFC 821 (SMTP protocol)
RFC 1123 (Host requirements) RFC 1123 (Host requirements)
RFC 1651 (SMTP service extensions)
RFC 1652 (8bit-MIME transport) RFC 1652 (8bit-MIME transport)
RFC 1869 (SMTP service extensions)
RFC 1854 (SMTP Pipelining) RFC 1854 (SMTP Pipelining)
RFC 1870 (Message Size Declaration) RFC 1870 (Message Size Declaration)
RFC 1985 (ETRN command) RFC 1985 (ETRN command)

View File

@@ -1,8 +1,8 @@
SHELL = /bin/sh SHELL = /bin/sh
SRCS = bounce.c bounce_append_service.c bounce_notify_service.c \ SRCS = bounce.c bounce_append_service.c bounce_notify_service.c \
bounce_cleanup.c bounce_notify_util.c bounce_cleanup.c bounce_notify_util.c bounce_notify_verp.c
OBJS = bounce.o bounce_append_service.o bounce_notify_service.o \ OBJS = bounce.o bounce_append_service.o bounce_notify_service.o \
bounce_cleanup.o bounce_notify_util.o bounce_cleanup.o bounce_notify_util.o bounce_notify_verp.o
HDRS = HDRS =
TESTSRC = TESTSRC =
WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \
@@ -69,6 +69,7 @@ bounce.o: ../../include/mail_queue.h
bounce.o: ../../include/mail_params.h bounce.o: ../../include/mail_params.h
bounce.o: ../../include/mail_conf.h bounce.o: ../../include/mail_conf.h
bounce.o: ../../include/bounce.h bounce.o: ../../include/bounce.h
bounce.o: ../../include/mail_addr.h
bounce.o: ../../include/mail_server.h bounce.o: ../../include/mail_server.h
bounce.o: bounce_service.h bounce.o: bounce_service.h
bounce.o: ../../include/bounce_log.h bounce.o: ../../include/bounce_log.h
@@ -133,3 +134,18 @@ bounce_notify_util.o: ../../include/name_mask.h
bounce_notify_util.o: ../../include/bounce_log.h bounce_notify_util.o: ../../include/bounce_log.h
bounce_notify_util.o: ../../include/mail_date.h bounce_notify_util.o: ../../include/mail_date.h
bounce_notify_util.o: bounce_service.h bounce_notify_util.o: bounce_service.h
bounce_notify_verp.o: bounce_notify_verp.c
bounce_notify_verp.o: ../../include/sys_defs.h
bounce_notify_verp.o: ../../include/msg.h
bounce_notify_verp.o: ../../include/vstream.h
bounce_notify_verp.o: ../../include/vbuf.h
bounce_notify_verp.o: ../../include/name_mask.h
bounce_notify_verp.o: ../../include/mail_params.h
bounce_notify_verp.o: ../../include/mail_queue.h
bounce_notify_verp.o: ../../include/vstring.h
bounce_notify_verp.o: ../../include/post_mail.h
bounce_notify_verp.o: ../../include/cleanup_user.h
bounce_notify_verp.o: ../../include/mail_addr.h
bounce_notify_verp.o: ../../include/mail_error.h
bounce_notify_verp.o: bounce_service.h
bounce_notify_verp.o: ../../include/bounce_log.h

View File

@@ -80,6 +80,11 @@
/* System library. */ /* System library. */
#include <sys_defs.h> #include <sys_defs.h>
#include <string.h>
#ifdef STRCASECMP_IN_STRINGS_H
#include <strings.h>
#endif
/* Utility library. */ /* Utility library. */
@@ -95,6 +100,7 @@
#include <mail_params.h> #include <mail_params.h>
#include <mail_conf.h> #include <mail_conf.h>
#include <bounce.h> #include <bounce.h>
#include <mail_addr.h>
/* Single-threaded server skeleton. */ /* Single-threaded server skeleton. */
@@ -122,6 +128,7 @@ static VSTRING *queue_id;
static VSTRING *queue_name; static VSTRING *queue_name;
static VSTRING *recipient; static VSTRING *recipient;
static VSTRING *sender; static VSTRING *sender;
static VSTRING *verp_delims;
static VSTRING *why; static VSTRING *why;
#define STR vstring_str #define STR vstring_str
@@ -199,7 +206,62 @@ static int bounce_notify_proto(char *service_name, VSTREAM *client, int flush)
* Execute the request. * Execute the request.
*/ */
return (bounce_notify_service(service_name, STR(queue_name), return (bounce_notify_service(service_name, STR(queue_name),
STR(queue_id), STR(sender), flush)); STR(queue_id), STR(sender), flush));
}
/* bounce_verp_proto - bounce_notify server protocol, VERP style */
static int bounce_verp_proto(char *service_name, VSTREAM *client, int flush)
{
char *myname="bounce_verp_proto";
int flags;
/*
* Read and validate the client request.
*/
if (mail_command_read(client, "%d %s %s %s %s",
&flags, queue_name, queue_id,
sender, verp_delims) != 5) {
msg_warn("malformed request");
return (-1);
}
if (mail_queue_name_ok(STR(queue_name)) == 0) {
msg_warn("malformed queue name: %s", printable(STR(queue_name), '?'));
return (-1);
}
if (mail_queue_id_ok(STR(queue_id)) == 0) {
msg_warn("malformed queue id: %s", printable(STR(queue_id), '?'));
return (-1);
}
if (strlen(STR(verp_delims)) != 2) {
msg_warn("malformed verp delimiter string: %s",
printable(STR(verp_delims), '?'));
return (-1);
}
if (msg_verbose)
msg_info("%s: service=%s queue=%s id=%s sender=%s delim=%s",
myname, service_name, STR(queue_name), STR(queue_id),
STR(sender), STR(verp_delims));
/*
* On request by the client, set up a trap to delete the log file in case
* of errors.
*/
if (flags & BOUNCE_FLAG_CLEAN)
bounce_cleanup_register(service_name, STR(queue_id));
/*
* Execute the request. Fall back to traditional notification if a bounce
* was returned as undeliverable, because we don't want to VERPify those.
*/
if (!*STR(sender) || !strcasecmp(STR(sender), mail_addr_double_bounce())) {
msg_warn("request to send VERP-style notification of bounced mail");
return (bounce_notify_service(service_name, STR(queue_name),
STR(queue_id), STR(sender), flush));
} else
return (bounce_notify_verp(service_name, STR(queue_name),
STR(queue_id), STR(sender),
STR(verp_delims), flush));
} }
/* bounce_service - parse bounce command type and delegate */ /* bounce_service - parse bounce command type and delegate */
@@ -228,6 +290,8 @@ static void bounce_service(VSTREAM *client, char *service_name, char **argv)
if (mail_scan(client, "%d", &command) != 1) { if (mail_scan(client, "%d", &command) != 1) {
msg_warn("malformed request"); msg_warn("malformed request");
status = -1; status = -1;
} else if (command == BOUNCE_CMD_VERP) {
status = bounce_verp_proto(service_name, client, REALLY_BOUNCE);
} else if (command == BOUNCE_CMD_FLUSH) { } else if (command == BOUNCE_CMD_FLUSH) {
status = bounce_notify_proto(service_name, client, REALLY_BOUNCE); status = bounce_notify_proto(service_name, client, REALLY_BOUNCE);
} else if (command == BOUNCE_CMD_WARN) { } else if (command == BOUNCE_CMD_WARN) {
@@ -271,6 +335,7 @@ static void post_jail_init(char *unused_name, char **unused_argv)
queue_name = vstring_alloc(10); queue_name = vstring_alloc(10);
recipient = vstring_alloc(10); recipient = vstring_alloc(10);
sender = vstring_alloc(10); sender = vstring_alloc(10);
verp_delims = vstring_alloc(10);
why = vstring_alloc(10); why = vstring_alloc(10);
} }

View File

@@ -199,7 +199,7 @@ BOUNCE_INFO *bounce_mail_init(const char *service, const char *queue_name,
*/ */
if ((bounce_info->log_handle = bounce_log_open(bounce_info->service, if ((bounce_info->log_handle = bounce_log_open(bounce_info->service,
bounce_info->queue_id, bounce_info->queue_id,
O_RDONLY, 0)) == 0 O_RDWR, 0)) == 0
&& errno != ENOENT) && errno != ENOENT)
msg_fatal("open %s %s: %m", bounce_info->service, msg_fatal("open %s %s: %m", bounce_info->service,
bounce_info->queue_id); bounce_info->queue_id);

View File

@@ -0,0 +1,210 @@
/*++
/* NAME
/* bounce_notify_verp 3
/* SUMMARY
/* send non-delivery report to sender, server side
/* SYNOPSIS
/* #include "bounce_service.h"
/*
/* int bounce_notify_verp(service, queue_name, queue_id, sender,
/* verp_delims, flush)
/* char *queue_name;
/* char *queue_id;
/* char *sender;
/* char *verp_delims;
/* int flush;
/* DESCRIPTION
/* This module implements the server side of the bounce_notify()
/* (send bounce message) request. If flush is zero, the logfile
/* is not removed, and a warning is sent instead of a bounce.
/* The bounce recipient address is encoded in VERP format.
/* This routine must be used for single bounces only.
/*
/* When a message bounces, a full copy is sent to the originator,
/* and an optional copy of the diagnostics with message headers is
/* sent to the postmaster. The result is non-zero when the operation
/* should be tried again.
/*
/* When a bounce is sent, the sender address is the empty
/* address.
/* DIAGNOSTICS
/* Fatal error: error opening existing file. Warnings: corrupt
/* message file. A corrupt message is saved to the "corrupt"
/* queue for further inspection.
/* SEE ALSO
/* bounce(3) basic bounce service client interface
/* 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 <fcntl.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
#ifdef STRCASECMP_IN_STRINGS_H
#include <strings.h>
#endif
/* Utility library. */
#include <msg.h>
#include <vstream.h>
#include <name_mask.h>
/* Global library. */
#include <mail_params.h>
#include <mail_queue.h>
#include <post_mail.h>
#include <mail_addr.h>
#include <mail_error.h>
#include <verp_sender.h>
/* Application-specific. */
#include "bounce_service.h"
#define STR vstring_str
/* bounce_notify_verp - send a bounce */
int bounce_notify_verp(char *service, char *queue_name,
char *queue_id, char *recipient,
char *verp_delims, int flush)
{
char *myname = "bounce_notify_verp";
BOUNCE_INFO *bounce_info;
int bounce_status = 0;
int postmaster_status;
VSTREAM *bounce;
int notify_mask = name_mask(VAR_NOTIFY_CLASSES, mail_error_masks,
var_notify_classes);
char *postmaster;
VSTRING *verp_buf = vstring_alloc(100);
/*
* Sanity checks. We must be called only for undeliverable non-bounce
* messages.
*/
if (*recipient == 0)
msg_panic("%s: attempt to bounce a single bounce", myname);
if (strcasecmp(recipient, mail_addr_double_bounce()) == 0)
msg_panic("%s: attempt to bounce a double bounce", myname);
/*
* Initialize. Open queue file, bounce log, etc.
*/
bounce_info = bounce_mail_init(service, queue_name, queue_id, flush);
#define NULL_SENDER MAIL_ADDR_EMPTY /* special address */
#define NULL_CLEANUP_FLAGS 0
#define BOUNCE_HEADERS 1
#define BOUNCE_ALL 0
/*
* A non-bounce message was returned. Send a single bounce, one per
* recipient.
*/
while (bounce_log_read(bounce_info->log_handle) != 0) {
/*
* Notify the originator.
*/
verp_sender(verp_buf, verp_delims, recipient,
bounce_info->log_handle->recipient);
if ((bounce = post_mail_fopen_nowait(NULL_SENDER, STR(verp_buf),
NULL_CLEANUP_FLAGS)) != 0) {
/*
* Send the bounce message header, some boilerplate text that
* pretends that we are a polite mail system, the text with
* reason for the bounce, and a copy of the original message.
*/
if (bounce_header(bounce, bounce_info, STR(verp_buf)) == 0
&& bounce_boilerplate(bounce, bounce_info) == 0
&& bounce_recipient_log(bounce, bounce_info) == 0
&& bounce_header_dsn(bounce, bounce_info) == 0
&& bounce_recipient_dsn(bounce, bounce_info) == 0)
bounce_original(bounce, bounce_info, flush ?
BOUNCE_ALL : BOUNCE_HEADERS);
bounce_status = post_mail_fclose(bounce);
} else
bounce_status = 1;
/*
* Stop at the first sign of trouble, instead of making the problem
* worse.
*/
if (bounce_status != 0)
break;
/*
* Mark this recipient as done.
*/
bounce_log_delrcpt(bounce_info->log_handle);
/*
* Optionally, send a postmaster notice.
*
* This postmaster notice is not critical, so if it fails don't
* retransmit the bounce that we just generated, just log a warning.
*/
#define WANT_IF_BOUNCE (flush == 1 && (notify_mask & MAIL_ERROR_BOUNCE))
#define WANT_IF_DELAY (flush == 0 && (notify_mask & MAIL_ERROR_DELAY))
if (WANT_IF_BOUNCE || WANT_IF_DELAY) {
/*
* Send the text with reason for the bounce, and the headers of
* the original message. Don't bother sending the boiler-plate
* text. This postmaster notice is not critical, so if it fails
* don't retransmit the bounce that we just generated, just log a
* warning.
*/
postmaster = flush ? var_bounce_rcpt : var_delay_rcpt;
if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(),
postmaster,
NULL_CLEANUP_FLAGS)) != 0) {
if (bounce_header(bounce, bounce_info, postmaster) == 0
&& bounce_recipient_log(bounce, bounce_info) == 0
&& bounce_header_dsn(bounce, bounce_info) == 0
&& bounce_recipient_dsn(bounce, bounce_info) == 0)
bounce_original(bounce, bounce_info, BOUNCE_HEADERS);
postmaster_status = post_mail_fclose(bounce);
} else
postmaster_status = 1;
if (postmaster_status)
msg_warn("postmaster notice failed while bouncing to %s",
recipient);
}
}
/*
* Examine the completion status. Delete the bounce log file only when
* the bounce was posted successfully, and only if we are bouncing for
* real, not just warning.
*/
if (flush != 0 && bounce_status == 0 && mail_queue_remove(service, queue_id)
&& errno != ENOENT)
msg_fatal("remove %s %s: %m", service, queue_id);
/*
* Cleanup.
*/
bounce_mail_free(bounce_info);
vstring_free(verp_buf);
return (bounce_status);
}

View File

@@ -28,6 +28,11 @@ extern int bounce_append_service(char *, char *, char *, char *);
*/ */
extern int bounce_notify_service(char *, char *, char *, char *, int); extern int bounce_notify_service(char *, char *, char *, char *, int);
/*
* bounce_notify_verp.c
*/
extern int bounce_notify_verp(char *, char *, char *, char *, char *, int);
/* /*
* bounce_cleanup.c * bounce_cleanup.c
*/ */
@@ -51,7 +56,7 @@ typedef struct {
VSTREAM *orig_fp; /* open queue file */ VSTREAM *orig_fp; /* open queue file */
long orig_offs; /* start of content */ long orig_offs; /* start of content */
time_t arrival_time; /* time of arrival */ time_t arrival_time; /* time of arrival */
BOUNCE_LOG *log_handle; /* open logfile */ BOUNCE_LOG *log_handle; /* open logfile */
} BOUNCE_INFO; } BOUNCE_INFO;
extern BOUNCE_INFO *bounce_mail_init(const char *, const char *, const char *, int); extern BOUNCE_INFO *bounce_mail_init(const char *, const char *, const char *, int);

View File

@@ -179,6 +179,20 @@ static void cleanup_envelope_process(CLEANUP_STATE *state, int type, char *buf,
state->errs |= CLEANUP_STAT_BAD; state->errs |= CLEANUP_STAT_BAD;
return; return;
} }
} else if (type == REC_TYPE_VERP) {
if (state->sender == 0 || *state->sender == 0) {
state->errs |= CLEANUP_STAT_BAD;
return;
}
if (len == 0) {
buf = var_verp_delim;
len = strlen(buf);
}
if (len == 2) {
cleanup_out(state, type, buf, len);
} else {
state->errs |= CLEANUP_STAT_BAD;
}
} else { } else {
cleanup_out(state, type, buf, len); cleanup_out(state, type, buf, len);
} }

View File

@@ -106,6 +106,7 @@ char *var_prop_extension; /* propagate unmatched extension */
char *var_always_bcc; /* big brother */ char *var_always_bcc; /* big brother */
int var_extra_rcpt_limit; /* recipient extract limit */ int var_extra_rcpt_limit; /* recipient extract limit */
char *var_rcpt_witheld; /* recipients not disclosed */ char *var_rcpt_witheld; /* recipients not disclosed */
char *var_verp_delim; /* default VERP delimiters */
CONFIG_INT_TABLE cleanup_int_table[] = { CONFIG_INT_TABLE cleanup_int_table[] = {
VAR_HOPCOUNT_LIMIT, DEF_HOPCOUNT_LIMIT, &var_hopcount_limit, 1, 0, VAR_HOPCOUNT_LIMIT, DEF_HOPCOUNT_LIMIT, &var_hopcount_limit, 1, 0,
@@ -133,6 +134,7 @@ CONFIG_STR_TABLE cleanup_str_table[] = {
VAR_PROP_EXTENSION, DEF_PROP_EXTENSION, &var_prop_extension, 0, 0, VAR_PROP_EXTENSION, DEF_PROP_EXTENSION, &var_prop_extension, 0, 0,
VAR_ALWAYS_BCC, DEF_ALWAYS_BCC, &var_always_bcc, 0, 0, VAR_ALWAYS_BCC, DEF_ALWAYS_BCC, &var_always_bcc, 0, 0,
VAR_RCPT_WITHELD, DEF_RCPT_WITHELD, &var_rcpt_witheld, 1, 0, VAR_RCPT_WITHELD, DEF_RCPT_WITHELD, &var_rcpt_witheld, 1, 0,
VAR_VERP_DELIM, DEF_VERP_DELIM, &var_verp_delim, 2, 2,
0, 0,
}; };

View File

@@ -18,7 +18,8 @@ SRCS = been_here.c bounce.c canon_addr.c cleanup_strerror.c clnt_stream.c \
sent.c smtp_stream.c split_addr.c string_list.c sys_exits.c \ sent.c smtp_stream.c split_addr.c string_list.c sys_exits.c \
timed_ipc.c tok822_find.c tok822_node.c tok822_parse.c \ timed_ipc.c tok822_find.c tok822_node.c tok822_parse.c \
tok822_resolve.c tok822_rewrite.c tok822_tree.c xtext.c bounce_log.c \ tok822_resolve.c tok822_rewrite.c tok822_tree.c xtext.c bounce_log.c \
flush_clnt.c mail_conf_time.c mbox_conf.c mbox_open.c abounce.c flush_clnt.c mail_conf_time.c mbox_conf.c mbox_open.c abounce.c \
verp_sender.c
OBJS = been_here.o bounce.o canon_addr.o cleanup_strerror.o clnt_stream.o \ OBJS = been_here.o bounce.o canon_addr.o cleanup_strerror.o clnt_stream.o \
debug_peer.o debug_process.o defer.o deliver_completed.o \ debug_peer.o debug_process.o defer.o deliver_completed.o \
deliver_flock.o deliver_pass.o deliver_request.o domain_list.o \ deliver_flock.o deliver_pass.o deliver_request.o domain_list.o \
@@ -38,7 +39,8 @@ OBJS = been_here.o bounce.o canon_addr.o cleanup_strerror.o clnt_stream.o \
sent.o smtp_stream.o split_addr.o string_list.o sys_exits.o \ sent.o smtp_stream.o split_addr.o string_list.o sys_exits.o \
timed_ipc.o tok822_find.o tok822_node.o tok822_parse.o \ timed_ipc.o tok822_find.o tok822_node.o tok822_parse.o \
tok822_resolve.o tok822_rewrite.o tok822_tree.o xtext.o bounce_log.o \ tok822_resolve.o tok822_rewrite.o tok822_tree.o xtext.o bounce_log.o \
flush_clnt.o mail_conf_time.o mbox_conf.o mbox_open.o abounce.o flush_clnt.o mail_conf_time.o mbox_conf.o mbox_open.o abounce.o \
verp_sender.o
HDRS = been_here.h bounce.h canon_addr.h cleanup_user.h clnt_stream.h \ HDRS = been_here.h bounce.h canon_addr.h cleanup_user.h clnt_stream.h \
config.h debug_peer.h debug_process.h defer.h deliver_completed.h \ config.h debug_peer.h debug_process.h defer.h deliver_completed.h \
deliver_flock.h deliver_pass.h deliver_request.h domain_list.h \ deliver_flock.h deliver_pass.h deliver_request.h domain_list.h \
@@ -54,7 +56,7 @@ HDRS = been_here.h bounce.h canon_addr.h cleanup_user.h clnt_stream.h \
recipient_list.h record.h resolve_clnt.h resolve_local.h \ recipient_list.h record.h resolve_clnt.h resolve_local.h \
rewrite_clnt.h sent.h smtp_stream.h split_addr.h string_list.h \ rewrite_clnt.h sent.h smtp_stream.h split_addr.h string_list.h \
sys_exits.h timed_ipc.h tok822.h xtext.h bounce_log.h flush_clnt.h \ sys_exits.h timed_ipc.h tok822.h xtext.h bounce_log.h flush_clnt.h \
mbox_conf.h mbox_open.h abounce.h qmqp_proto.h mbox_conf.h mbox_open.h abounce.h qmqp_proto.h verp_sender.h
TESTSRC = rec2stream.c stream2rec.c recdump.c TESTSRC = rec2stream.c stream2rec.c recdump.c
WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \
-Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \
@@ -1036,6 +1038,11 @@ tok822_tree.o: ../../include/vstring.h
tok822_tree.o: ../../include/vbuf.h tok822_tree.o: ../../include/vbuf.h
tok822_tree.o: tok822.h tok822_tree.o: tok822.h
tok822_tree.o: resolve_clnt.h tok822_tree.o: resolve_clnt.h
verp_sender.o: verp_sender.c
verp_sender.o: ../../include/sys_defs.h
verp_sender.o: ../../include/vstring.h
verp_sender.o: ../../include/vbuf.h
verp_sender.o: verp_sender.h
xtext.o: xtext.c xtext.o: xtext.c
xtext.o: ../../include/sys_defs.h xtext.o: ../../include/sys_defs.h
xtext.o: ../../include/vstream.h xtext.o: ../../include/vstream.h

View File

@@ -14,6 +14,15 @@
/* void (*callback)(int status, char *context); /* void (*callback)(int status, char *context);
/* char *context; /* char *context;
/* /*
/* void abounce_flush_verp(flags, queue, id, sender, verp, callback, context)
/* int flags;
/* const char *queue;
/* const char *id;
/* const char *sender;
/* const char *verp;
/* void (*callback)(int status, char *context);
/* char *context;
/*
/* void adefer_flush(flags, queue, id, sender, callback, context) /* void adefer_flush(flags, queue, id, sender, callback, context)
/* int flags; /* int flags;
/* const char *queue; /* const char *queue;
@@ -22,6 +31,15 @@
/* void (*callback)(int status, char *context); /* void (*callback)(int status, char *context);
/* char *context; /* char *context;
/* /*
/* void adefer_flush_verp(flags, queue, id, sender, verp, callback, context)
/* int flags;
/* const char *queue;
/* const char *id;
/* const char *sender;
/* const char *verp;
/* void (*callback)(int status, char *context);
/* char *context;
/*
/* void adefer_warn(flags, queue, id, sender, callback, context) /* void adefer_warn(flags, queue, id, sender, callback, context)
/* int flags; /* int flags;
/* const char *queue; /* const char *queue;
@@ -38,10 +56,16 @@
/* the specified sender, including the bounce log that was /* the specified sender, including the bounce log that was
/* built with bounce_append(). /* built with bounce_append().
/* /*
/* abounce_flush_verp() is like abounce_flush() but sends
/* one VERP style notification per undeliverable recipient.
/*
/* adefer_flush() bounces the specified message to /* adefer_flush() bounces the specified message to
/* the specified sender, including the defer log that was /* the specified sender, including the defer log that was
/* built with defer_append(). /* built with defer_append().
/* /*
/* adefer_flush_verp() is like adefer_flush() but sends
/* one VERP style notification per undeliverable recipient.
/*
/* adefer_warn() sends a "mail is delayed" notification to /* adefer_warn() sends a "mail is delayed" notification to
/* the specified sender, including the defer log that was /* the specified sender, including the defer log that was
/* built with defer_append(). /* built with defer_append().
@@ -64,6 +88,8 @@
/* file has the same name as the original message file. /* file has the same name as the original message file.
/* .IP sender /* .IP sender
/* The sender envelope address. /* The sender envelope address.
/* .IP verp
/* VERP delimiter characters.
/* .IP callback /* .IP callback
/* Name of a routine that receives the notification status as /* Name of a routine that receives the notification status as
/* documented for bounce_flush() or defer_flush(). /* documented for bounce_flush() or defer_flush().
@@ -148,6 +174,60 @@ static void abounce_event(int unused_event, char *context)
abounce_done(ap, mail_scan(ap->fp, "%d", &status) == 1 ? status : -1); abounce_done(ap, mail_scan(ap->fp, "%d", &status) == 1 ? status : -1);
} }
/* abounce_request_verp - suspend pseudo thread until server reply event */
static void abounce_request_verp(const char *class, const char *service,
int command, int flags,
const char *queue, const char *id,
const char *sender, const char *verp,
ABOUNCE_FN callback,
char *context)
{
ABOUNCE *ap;
/*
* Save pseudo thread state. Connect to the server. Send the request and
* suspend the pseudo thread until the server replies (or dies).
*/
ap = (ABOUNCE *) mymalloc(sizeof(*ap));
ap->command = command;
ap->flags = flags;
ap->id = mystrdup(id);
ap->callback = callback;
ap->context = context;
ap->fp = mail_connect_wait(class, service);
if (mail_print(ap->fp, "%d %d %s %s %s %s %s", command,
flags, queue, id, sender, verp, MAIL_EOF) == 0
&& vstream_fflush(ap->fp) == 0) {
event_enable_read(vstream_fileno(ap->fp), abounce_event, (char *) ap);
} else {
abounce_done(ap, -1);
}
}
/* abounce_flush_verp - asynchronous bounce flush */
void abounce_flush_verp(int flags, const char *queue, const char *id,
const char *sender, const char *verp,
ABOUNCE_FN callback, char *context)
{
abounce_request_verp(MAIL_CLASS_PRIVATE, MAIL_SERVICE_BOUNCE,
BOUNCE_CMD_VERP, flags, queue, id, sender, verp,
callback, context);
}
/* adefer_flush_verp - asynchronous defer flush */
void adefer_flush_verp(int flags, const char *queue, const char *id,
const char *sender, const char *verp,
ABOUNCE_FN callback, char *context)
{
abounce_request_verp(MAIL_CLASS_PRIVATE, MAIL_SERVICE_DEFER,
BOUNCE_CMD_VERP, flags, queue, id, sender, verp,
callback, context);
}
/* abounce_request - suspend pseudo thread until server reply event */ /* abounce_request - suspend pseudo thread until server reply event */
static void abounce_request(const char *class, const char *service, static void abounce_request(const char *class, const char *service,

View File

@@ -25,6 +25,9 @@ extern void abounce_flush(int, const char *, const char *, const char *, ABOUNCE
extern void adefer_flush(int, const char *, const char *, const char *, ABOUNCE_FN, char *); extern void adefer_flush(int, const char *, const char *, const char *, ABOUNCE_FN, char *);
extern void adefer_warn(int, const char *, const char *, const char *, ABOUNCE_FN, char *); extern void adefer_warn(int, const char *, const char *, const char *, ABOUNCE_FN, char *);
extern void abounce_flush_verp(int, const char *, const char *, const char *, const char *, ABOUNCE_FN, char *);
extern void adefer_flush_verp(int, const char *, const char *, const char *, const char *, ABOUNCE_FN, char *);
/* LICENSE /* LICENSE
/* .ad /* .ad
/* .fi /* .fi

View File

@@ -40,8 +40,8 @@ extern int vbounce_recip(int, const char *, const char *, const char *,
*/ */
#define BOUNCE_CMD_APPEND 0 /* append log */ #define BOUNCE_CMD_APPEND 0 /* append log */
#define BOUNCE_CMD_FLUSH 1 /* send log */ #define BOUNCE_CMD_FLUSH 1 /* send log */
#define BOUNCE_CMD_WARN 2 /* send warning bounce, don't delete #define BOUNCE_CMD_WARN 2 /* send warning, don't delete log */
* log */ #define BOUNCE_CMD_VERP 3 /* send log, verp style */
/* /*
* Flags. * Flags.

View File

@@ -24,6 +24,9 @@
/* BOUNCE_LOG *bounce_log_read(bp) /* BOUNCE_LOG *bounce_log_read(bp)
/* BOUNCE_LOG *bp; /* BOUNCE_LOG *bp;
/* /*
/* BOUNCE_LOG *bounce_log_delrcpt(bp)
/* BOUNCE_LOG *bp;
/*
/* void bounce_log_rewind(bp) /* void bounce_log_rewind(bp)
/* BOUNCE_LOG *bp; /* BOUNCE_LOG *bp;
/* /*
@@ -31,8 +34,7 @@
/* BOUNCE_LOG *bp; /* BOUNCE_LOG *bp;
/* DESCRIPTION /* DESCRIPTION
/* This module implements a bounce/defer logfile API. Information /* This module implements a bounce/defer logfile API. Information
/* is sanitized for control and non-ASCII characters. Currently, /* is sanitized for control and non-ASCII characters.
/* only the reading end is implemented.
/* /*
/* bounce_log_open() opens the named bounce or defer logfile /* bounce_log_open() opens the named bounce or defer logfile
/* and returns a handle that must be used for further access. /* and returns a handle that must be used for further access.
@@ -47,6 +49,9 @@
/* bounce_log_read() returns a null pointer when no recipient was read, /* bounce_log_read() returns a null pointer when no recipient was read,
/* otherwise it returns its argument. /* otherwise it returns its argument.
/* /*
/* bounce_log_delrcpt() marks the last accessed recipient record as
/* "deleted". This requires that the logfile is opened for update.
/*
/* bounce_log_rewind() is a helper that seeks to the first recipient /* bounce_log_rewind() is a helper that seeks to the first recipient
/* in an open bounce or defer logfile (skipping over recipients that /* in an open bounce or defer logfile (skipping over recipients that
/* are marked as done). The result is 0 in case of success, -1 in case /* are marked as done). The result is 0 in case of success, -1 in case
@@ -92,6 +97,7 @@
#include <sys_defs.h> #include <sys_defs.h>
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#include <unistd.h>
/* Utility library. */ /* Utility library. */
@@ -133,6 +139,7 @@ BOUNCE_LOG *bounce_log_open(const char *queue_name, const char *queue_id,
bp->fp = fp; bp->fp = fp;
bp->buf = vstring_alloc(100); bp->buf = vstring_alloc(100);
bp->status = STREQ(queue_name, MAIL_QUEUE_DEFER) ? "4.0.0" : "5.0.0"; bp->status = STREQ(queue_name, MAIL_QUEUE_DEFER) ? "4.0.0" : "5.0.0";
bp->offset = 0;
return (bp); return (bp);
} }
} }
@@ -145,7 +152,8 @@ BOUNCE_LOG *bounce_log_read(BOUNCE_LOG *bp)
char *text; char *text;
char *cp; char *cp;
while (vstring_get_nonl(bp->buf, bp->fp) != VSTREAM_EOF) { while ((bp->offset = vstream_ftell(bp->fp)),
(vstring_get_nonl(bp->buf, bp->fp) != VSTREAM_EOF)) {
if (STR(bp->buf)[0] == 0) if (STR(bp->buf)[0] == 0)
continue; continue;
@@ -155,6 +163,12 @@ BOUNCE_LOG *bounce_log_read(BOUNCE_LOG *bp)
*/ */
cp = printable(STR(bp->buf), '?'); cp = printable(STR(bp->buf), '?');
/*
* Skip over deleted recipients.
*/
if (*cp == BOUNCE_LOG_STAT_DELETED)
continue;
/* /*
* Find the recipient address. * Find the recipient address.
*/ */
@@ -185,6 +199,21 @@ BOUNCE_LOG *bounce_log_read(BOUNCE_LOG *bp)
return (0); return (0);
} }
/* bounce_log_delrcpt - mark recipient record as deleted */
BOUNCE_LOG *bounce_log_delrcpt(BOUNCE_LOG *bp)
{
long current_offset;
current_offset = vstream_ftell(bp->fp);
if (vstream_fseek(bp->fp, bp->offset, SEEK_SET) < 0)
msg_fatal("bounce logfile %s seek error: %m", VSTREAM_PATH(bp->fp));
VSTREAM_PUTC(BOUNCE_LOG_STAT_DELETED, bp->fp);
if (vstream_fseek(bp->fp, current_offset, SEEK_SET) < 0)
msg_fatal("bounce logfile %s seek error: %m", VSTREAM_PATH(bp->fp));
return (bp);
}
/* bounce_log_close - close bounce reader stream */ /* bounce_log_close - close bounce reader stream */
int bounce_log_close(BOUNCE_LOG *bp) int bounce_log_close(BOUNCE_LOG *bp)

View File

@@ -28,14 +28,18 @@ typedef struct {
const char *recipient; /* final recipient */ const char *recipient; /* final recipient */
const char *status; /* recipient status */ const char *status; /* recipient status */
const char *text; /* why undeliverable */ const char *text; /* why undeliverable */
long offset; /* start of current record */
} BOUNCE_LOG; } BOUNCE_LOG;
extern BOUNCE_LOG *bounce_log_open(const char *, const char *, int, int); extern BOUNCE_LOG *bounce_log_open(const char *, const char *, int, int);
extern BOUNCE_LOG *bounce_log_read(BOUNCE_LOG *); extern BOUNCE_LOG *bounce_log_read(BOUNCE_LOG *);
extern BOUNCE_LOG *bounce_log_delrcpt(BOUNCE_LOG *);
extern int bounce_log_close(BOUNCE_LOG *); extern int bounce_log_close(BOUNCE_LOG *);
#define bounce_log_rewind(bp) vstream_fseek((bp)->fp, 0L, SEEK_SET) #define bounce_log_rewind(bp) vstream_fseek((bp)->fp, 0L, SEEK_SET)
#define BOUNCE_LOG_STAT_DELETED 'D' /* deleted record */
/* LICENSE /* LICENSE
/* .ad /* .ad
/* .fi /* .fi

View File

@@ -1271,6 +1271,14 @@ extern int var_qmqpd_timeout;
#define DEF_QMTPD_ERR_SLEEP "5s" #define DEF_QMTPD_ERR_SLEEP "5s"
extern int var_qmqpd_err_sleep; extern int var_qmqpd_err_sleep;
/*
* VERP, more DJB intellectual cross-pollination. However, we prefer + as
* the default recipient delimiter.
*/
#define VAR_VERP_DELIM "default_verp_delimiters"
#define DEF_VERP_DELIM "+="
extern char *var_verp_delim;
/* LICENSE /* LICENSE
/* .ad /* .ad
/* .fi /* .fi

View File

@@ -15,7 +15,7 @@
* Version of this program. * Version of this program.
*/ */
#define VAR_MAIL_VERSION "mail_version" #define VAR_MAIL_VERSION "mail_version"
#define DEF_MAIL_VERSION "Snapshot-20010707" #define DEF_MAIL_VERSION "Snapshot-20010709"
extern char *var_mail_version; extern char *var_mail_version;
/* LICENSE /* LICENSE

View File

@@ -56,6 +56,7 @@ REC_TYPE_NAME rec_type_names[] = {
REC_TYPE_RRTO, "return_receipt", REC_TYPE_RRTO, "return_receipt",
REC_TYPE_ERTO, "errors_to", REC_TYPE_ERTO, "errors_to",
REC_TYPE_PRIO, "priority", REC_TYPE_PRIO, "priority",
REC_TYPE_VERP, "verp_delimiters",
REC_TYPE_END, "message_end", REC_TYPE_END, "message_end",
0, 0, 0, 0,
}; };

View File

@@ -45,6 +45,7 @@
#define REC_TYPE_RRTO 'r' /* return-receipt, from headers */ #define REC_TYPE_RRTO 'r' /* return-receipt, from headers */
#define REC_TYPE_ERTO 'e' /* errors-to, from headers */ #define REC_TYPE_ERTO 'e' /* errors-to, from headers */
#define REC_TYPE_PRIO 'P' /* priority */ #define REC_TYPE_PRIO 'P' /* priority */
#define REC_TYPE_VERP 'V' /* VERP delimiters */
#define REC_TYPE_END 'E' /* terminator, required */ #define REC_TYPE_END 'E' /* terminator, required */
@@ -53,7 +54,7 @@
* record groups. The first member in each set is the record type that * record groups. The first member in each set is the record type that
* indicates the end of that record group. * indicates the end of that record group.
*/ */
#define REC_TYPE_ENVELOPE "MCTFILSDRW" #define REC_TYPE_ENVELOPE "MCTFILSDRWV"
#define REC_TYPE_CONTENT "XLN" #define REC_TYPE_CONTENT "XLN"
#define REC_TYPE_EXTRACT "EDRPre" #define REC_TYPE_EXTRACT "EDRPre"
#define REC_TYPE_NOEXTRACT "E" #define REC_TYPE_NOEXTRACT "E"

View File

@@ -67,7 +67,7 @@ char *split_addr(char *localpart, int delimiter)
/* /*
* Backwards compatibility: don't split owner-foo or foo-request. * Backwards compatibility: don't split owner-foo or foo-request.
*/ */
if (var_ownreq_special != 0) { if (delimiter == '-' && var_ownreq_special != 0) {
if (strncasecmp(localpart, "owner-", 6) == 0) if (strncasecmp(localpart, "owner-", 6) == 0)
return (0); return (0);
if ((len = strlen(localpart) - 8) > 0 if ((len = strlen(localpart) - 8) > 0

View File

@@ -0,0 +1,83 @@
/*++
/* NAME
/* verp_sender 3
/* SUMMARY
/* quote local part of mailbox
/* SYNOPSIS
/* #include <verp_sender.h>
/*
/* VSTRING *verp_sender(dst, delims, sender, recipient)
/* VSTRING *dst;
/* const char *delims;
/* const char *sender;
/* const char *recipient;
/* DESCRIPTION
/* verp_sender() encodes the recipient address in the sender
/* address, using the specified delimiters. For example,
/* with delims +=, sender \fIprefix@origin\fR, and
/* recipient \fIuser@domain\fR the result is
/* \fIprefix+user=domain@origin\fR.
/*
/* Arguments:
/* .IP dst
/* The result. The buffer is null terminated.
/* .IP delims
/* VERP formatting characters.
/* .IP sender
/* Sender envelope address.
/* .IP recipient
/* Recipient envelope address.
/* 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 <string.h>
/* Utility library. */
#include <vstring.h>
/* Global library. */
#include <verp_sender.h>
/* verp_sender - encode recipient into envelope sender address */
VSTRING *verp_sender(VSTRING *buf, const char *delimiters,
const char *sender, const char *recipient)
{
int send_local_len;
int rcpt_local_len;
const char *cp;
/*
* Change prefix@origin into prefix+user=domain@origin.
*/
send_local_len = ((cp = strrchr(sender, '@')) ?
cp - sender : strlen(sender));
rcpt_local_len = ((cp = strrchr(recipient, '@')) ?
cp - recipient : strlen(recipient));
vstring_strncpy(buf, sender, send_local_len);
VSTRING_ADDCH(buf, delimiters[0] & 0xff);
vstring_strncat(buf, recipient, rcpt_local_len);
if (recipient[rcpt_local_len] && recipient[rcpt_local_len + 1]) {
VSTRING_ADDCH(buf, delimiters[1] & 0xff);
vstring_strcat(buf, recipient + rcpt_local_len + 1);
}
if (sender[send_local_len] && sender[send_local_len + 1]) {
VSTRING_ADDCH(buf, '@');
vstring_strcat(buf, sender + send_local_len + 1);
}
VSTRING_TERMINATE(buf);
return (buf);
}

View File

@@ -0,0 +1,35 @@
#ifndef _VERP_SENDER_H_INCLUDED_
#define _VERP_SENDER_H_INCLUDED_
/*++
/* NAME
/* verp_sender 3h
/* SUMMARY
/* encode recipient into sender, VERP style
/* SYNOPSIS
/* #include "verp_sender.h"
/* DESCRIPTION
/* .nf
/*
* Utility library.
*/
#include <vstring.h>
/*
* External interface.
*/
extern VSTRING *verp_sender(VSTRING *, const char *, const char *, const char *);
/* 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

View File

@@ -267,6 +267,7 @@ struct QMGR_MESSAGE {
char *queue_name; /* queue name */ char *queue_name; /* queue name */
char *queue_id; /* queue file */ char *queue_id; /* queue file */
char *sender; /* complete address */ char *sender; /* complete address */
char *verp_delims; /* VERP delimiters */
char *errors_to; /* error report address */ char *errors_to; /* error report address */
char *return_receipt; /* confirm receipt address */ char *return_receipt; /* confirm receipt address */
char *filter_xport; /* filtering transport */ char *filter_xport; /* filtering transport */

View File

@@ -275,12 +275,21 @@ void qmgr_active_done(QMGR_MESSAGE *message)
} else { } else {
if (msg_verbose) if (msg_verbose)
msg_info("%s: bounce %s", myname, message->queue_id); msg_info("%s: bounce %s", myname, message->queue_id);
abounce_flush(BOUNCE_FLAG_KEEP, if (message->verp_delims == 0)
message->queue_name, abounce_flush(BOUNCE_FLAG_KEEP,
message->queue_id, message->queue_name,
message->errors_to, message->queue_id,
qmgr_active_done_2_bounce_flush, message->errors_to,
(char *) message); qmgr_active_done_2_bounce_flush,
(char *) message);
else
abounce_flush_verp(BOUNCE_FLAG_KEEP,
message->queue_name,
message->queue_id,
message->errors_to,
message->verp_delims,
qmgr_active_done_2_bounce_flush,
(char *) message);
return; return;
} }
} }
@@ -353,12 +362,21 @@ static void qmgr_active_done_2_generic(QMGR_MESSAGE *message)
if (event_time() > message->arrival_time + var_max_queue_time) { if (event_time() > message->arrival_time + var_max_queue_time) {
if (msg_verbose) if (msg_verbose)
msg_info("%s: too old, bouncing %s", myname, message->queue_id); msg_info("%s: too old, bouncing %s", myname, message->queue_id);
adefer_flush(BOUNCE_FLAG_KEEP, if (message->verp_delims == 0)
message->queue_name, adefer_flush(BOUNCE_FLAG_KEEP,
message->queue_id, message->queue_name,
message->errors_to, message->queue_id,
qmgr_active_done_3_defer_flush, message->errors_to,
(char *) message); qmgr_active_done_3_defer_flush,
(char *) message);
else
adefer_flush_verp(BOUNCE_FLAG_KEEP,
message->queue_name,
message->queue_id,
message->errors_to,
message->verp_delims,
qmgr_active_done_3_defer_flush,
(char *) message);
return; return;
} else if (message->warn_time > 0 } else if (message->warn_time > 0
&& event_time() > message->warn_time) { && event_time() > message->warn_time) {

View File

@@ -68,6 +68,7 @@
#include <recipient_list.h> #include <recipient_list.h>
#include <mail_params.h> #include <mail_params.h>
#include <deliver_request.h> #include <deliver_request.h>
#include <verp_sender.h>
/* Application-specific. */ /* Application-specific. */
@@ -124,6 +125,22 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream)
QMGR_RCPT *recipient; QMGR_RCPT *recipient;
QMGR_MESSAGE *message = entry->message; QMGR_MESSAGE *message = entry->message;
char *cp; char *cp;
VSTRING *sender_buf = 0;
char *sender;
/*
* If variable envelope return path is requested, change prefix+@origin
* into prefix+user=domain@origin. Note that with VERP there is only one
* recipient per delivery.
*/
if (message->verp_delims == 0) {
sender = message->sender;
} else {
sender_buf = vstring_alloc(100);
verp_sender(sender_buf, message->verp_delims,
message->sender, list.info->address);
sender = vstring_str(sender_buf);
}
/* /*
* With mail transports that accept only one recipient per delivery, the * With mail transports that accept only one recipient per delivery, the
@@ -136,9 +153,11 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream)
message->queue_name, message->queue_id, message->queue_name, message->queue_id,
message->data_offset, message->data_size, message->data_offset, message->data_size,
(cp = strrchr(entry->queue->name, '@')) != 0 && cp[1] ? cp + 1 : (cp = strrchr(entry->queue->name, '@')) != 0 && cp[1] ? cp + 1 :
entry->queue->name, message->sender, entry->queue->name, sender,
message->errors_to, message->return_receipt, message->errors_to, message->return_receipt,
message->arrival_time); message->arrival_time);
if (sender_buf != 0)
vstring_free(sender_buf);
for (recipient = list.info; recipient < list.info + list.len; recipient++) for (recipient = list.info; recipient < list.info + list.len; recipient++)
mail_print(stream, "%ld %s", recipient->offset, recipient->address); mail_print(stream, "%ld %s", recipient->offset, recipient->address);
mail_print(stream, "%s", "0"); mail_print(stream, "%s", "0");

View File

@@ -161,6 +161,7 @@ static QMGR_MESSAGE *qmgr_message_create(const char *queue_name,
message->warn_offset = 0; message->warn_offset = 0;
message->warn_time = 0; message->warn_time = 0;
message->rcpt_offset = 0; message->rcpt_offset = 0;
message->verp_delims = 0;
message->unread_offset = 0; message->unread_offset = 0;
qmgr_rcpt_list_init(&message->rcpt_list); qmgr_rcpt_list_init(&message->rcpt_list);
message->rcpt_count = 0; message->rcpt_count = 0;
@@ -423,6 +424,14 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
message->warn_offset = curr_offset; message->warn_offset = curr_offset;
message->warn_time = atol(start); message->warn_time = atol(start);
} }
} else if (rec_type == REC_TYPE_VERP) {
if (strlen(start) != 2) {
msg_warn("%s: bad VERP record length: \"%s\"",
message->queue_id, start);
} else {
message->single_rcpt = 1;
message->verp_delims = mystrdup(start);
}
} }
} while (rec_type > 0 && rec_type != REC_TYPE_END); } while (rec_type > 0 && rec_type != REC_TYPE_END);
@@ -902,6 +911,8 @@ void qmgr_message_free(QMGR_MESSAGE *message)
myfree(message->queue_name); myfree(message->queue_name);
if (message->sender) if (message->sender)
myfree(message->sender); myfree(message->sender);
if (message->verp_delims)
myfree(message->verp_delims);
if (message->errors_to) if (message->errors_to)
myfree(message->errors_to); myfree(message->errors_to);
if (message->return_receipt) if (message->return_receipt)

View File

@@ -136,6 +136,7 @@ qmgr_deliver.o: ../../include/mail_proto.h
qmgr_deliver.o: ../../include/recipient_list.h qmgr_deliver.o: ../../include/recipient_list.h
qmgr_deliver.o: ../../include/mail_params.h qmgr_deliver.o: ../../include/mail_params.h
qmgr_deliver.o: ../../include/deliver_request.h qmgr_deliver.o: ../../include/deliver_request.h
qmgr_deliver.o: ../../include/verp_sender.h
qmgr_deliver.o: qmgr.h qmgr_deliver.o: qmgr.h
qmgr_deliver.o: ../../include/scan_dir.h qmgr_deliver.o: ../../include/scan_dir.h
qmgr_deliver.o: ../../include/maps.h qmgr_deliver.o: ../../include/maps.h

View File

@@ -227,6 +227,7 @@ struct QMGR_MESSAGE {
char *queue_name; /* queue name */ char *queue_name; /* queue name */
char *queue_id; /* queue file */ char *queue_id; /* queue file */
char *sender; /* complete address */ char *sender; /* complete address */
char *verp_delims; /* VERP delimiters */
char *errors_to; /* error report address */ char *errors_to; /* error report address */
char *return_receipt; /* confirm receipt address */ char *return_receipt; /* confirm receipt address */
char *filter_xport; /* filtering transport */ char *filter_xport; /* filtering transport */

View File

@@ -275,12 +275,21 @@ void qmgr_active_done(QMGR_MESSAGE *message)
} else { } else {
if (msg_verbose) if (msg_verbose)
msg_info("%s: bounce %s", myname, message->queue_id); msg_info("%s: bounce %s", myname, message->queue_id);
abounce_flush(BOUNCE_FLAG_KEEP, if (message->verp_delims == 0)
message->queue_name, abounce_flush(BOUNCE_FLAG_KEEP,
message->queue_id, message->queue_name,
message->errors_to, message->queue_id,
qmgr_active_done_2_bounce_flush, message->errors_to,
(char *) message); qmgr_active_done_2_bounce_flush,
(char *) message);
else
abounce_flush_verp(BOUNCE_FLAG_KEEP,
message->queue_name,
message->queue_id,
message->errors_to,
message->verp_delims,
qmgr_active_done_2_bounce_flush,
(char *) message);
return; return;
} }
} }
@@ -353,12 +362,21 @@ static void qmgr_active_done_2_generic(QMGR_MESSAGE *message)
if (event_time() > message->arrival_time + var_max_queue_time) { if (event_time() > message->arrival_time + var_max_queue_time) {
if (msg_verbose) if (msg_verbose)
msg_info("%s: too old, bouncing %s", myname, message->queue_id); msg_info("%s: too old, bouncing %s", myname, message->queue_id);
adefer_flush(BOUNCE_FLAG_KEEP, if (message->verp_delims == 0)
message->queue_name, adefer_flush(BOUNCE_FLAG_KEEP,
message->queue_id, message->queue_name,
message->errors_to, message->queue_id,
qmgr_active_done_3_defer_flush, message->errors_to,
(char *) message); qmgr_active_done_3_defer_flush,
(char *) message);
else
adefer_flush_verp(BOUNCE_FLAG_KEEP,
message->queue_name,
message->queue_id,
message->errors_to,
message->verp_delims,
qmgr_active_done_3_defer_flush,
(char *) message);
return; return;
} else if (message->warn_time > 0 } else if (message->warn_time > 0
&& event_time() > message->warn_time) { && event_time() > message->warn_time) {

View File

@@ -63,6 +63,7 @@
#include <recipient_list.h> #include <recipient_list.h>
#include <mail_params.h> #include <mail_params.h>
#include <deliver_request.h> #include <deliver_request.h>
#include <verp_sender.h>
/* Application-specific. */ /* Application-specific. */
@@ -119,6 +120,22 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream)
QMGR_RCPT *recipient; QMGR_RCPT *recipient;
QMGR_MESSAGE *message = entry->message; QMGR_MESSAGE *message = entry->message;
char *cp; char *cp;
VSTRING *sender_buf = 0;
char *sender;
/*
* If variable envelope return path is requested, change prefix+@origin
* into prefix+user=domain@origin. Note that with VERP there is only one
* recipient per delivery.
*/
if (message->verp_delims == 0) {
sender = message->sender;
} else {
sender_buf = vstring_alloc(100);
verp_sender(sender_buf, message->verp_delims,
message->sender, list.info->address);
sender = vstring_str(sender_buf);
}
/* /*
* With mail transports that accept only one recipient per delivery, the * With mail transports that accept only one recipient per delivery, the
@@ -131,9 +148,11 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream)
message->queue_name, message->queue_id, message->queue_name, message->queue_id,
message->data_offset, message->data_size, message->data_offset, message->data_size,
(cp = strrchr(entry->queue->name, '@')) != 0 && cp[1] ? cp + 1 : (cp = strrchr(entry->queue->name, '@')) != 0 && cp[1] ? cp + 1 :
entry->queue->name, message->sender, entry->queue->name, sender,
message->errors_to, message->return_receipt, message->errors_to, message->return_receipt,
message->arrival_time); message->arrival_time);
if (sender_buf != 0)
vstring_free(sender_buf);
for (recipient = list.info; recipient < list.info + list.len; recipient++) for (recipient = list.info; recipient < list.info + list.len; recipient++)
mail_print(stream, "%ld %s", recipient->offset, recipient->address); mail_print(stream, "%ld %s", recipient->offset, recipient->address);
mail_print(stream, "%s", "0"); mail_print(stream, "%s", "0");

View File

@@ -151,6 +151,7 @@ static QMGR_MESSAGE *qmgr_message_create(const char *queue_name,
message->warn_offset = 0; message->warn_offset = 0;
message->warn_time = 0; message->warn_time = 0;
message->rcpt_offset = 0; message->rcpt_offset = 0;
message->verp_delims = 0;
qmgr_rcpt_list_init(&message->rcpt_list); qmgr_rcpt_list_init(&message->rcpt_list);
return (message); return (message);
} }
@@ -303,6 +304,14 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
message->warn_offset = curr_offset; message->warn_offset = curr_offset;
message->warn_time = atol(start); message->warn_time = atol(start);
} }
} else if (rec_type == REC_TYPE_VERP) {
if (strlen(start) != 2) {
msg_warn("%s: bad VERP record length: \"%s\"",
message->queue_id, start);
} else {
message->single_rcpt = 1;
message->verp_delims = mystrdup(start);
}
} }
} while (rec_type > 0 && rec_type != REC_TYPE_END); } while (rec_type > 0 && rec_type != REC_TYPE_END);
@@ -737,6 +746,8 @@ void qmgr_message_free(QMGR_MESSAGE *message)
myfree(message->queue_name); myfree(message->queue_name);
if (message->sender) if (message->sender)
myfree(message->sender); myfree(message->sender);
if (message->verp_delims)
myfree(message->verp_delims);
if (message->errors_to) if (message->errors_to)
myfree(message->errors_to); myfree(message->errors_to);
if (message->return_receipt) if (message->return_receipt)

View File

@@ -210,11 +210,34 @@ static void qmqpd_read_content(QMQPD_STATE *state)
static void qmqpd_copy_sender(QMQPD_STATE *state) static void qmqpd_copy_sender(QMQPD_STATE *state)
{ {
char *end_prefix;
char *end_origin;
int verp_requested;
/*
* If the sender address looks like prefix-@origin-@[], then request
* variable envelope return path delivery, with an envelope sender
* address of prefix@origin, and with VERP delimiters of - and =. This
* way, the recipients will see envelope sender addresses that look like:
* prefix-user=domain@origin.
*/
state->where = "receiving sender address"; state->where = "receiving sender address";
netstring_get(state->client, state->buf, var_line_limit); netstring_get(state->client, state->buf, var_line_limit);
verp_requested = ((end_prefix = strstr(STR(state->buf), "-@")) != 0
&& (end_origin = strstr(end_prefix + 2, "-@")) != 0
&& strncmp(end_origin + 2, "[]", 2) == 0
&& vstring_end(state->buf) == end_origin + 4);
if (verp_requested) {
memcpy(end_prefix, end_prefix + 1, end_origin - end_prefix - 1);
vstring_truncate(state->buf, end_origin - STR(state->buf) - 1);
}
if (state->err == CLEANUP_STAT_OK if (state->err == CLEANUP_STAT_OK
&& REC_PUT_BUF(state->cleanup, REC_TYPE_FROM, state->buf) < 0) && REC_PUT_BUF(state->cleanup, REC_TYPE_FROM, state->buf) < 0)
state->err = CLEANUP_STAT_WRITE; state->err = CLEANUP_STAT_WRITE;
if (verp_requested)
if (state->err == CLEANUP_STAT_OK
&& rec_put(state->cleanup, REC_TYPE_VERP, "-=", 2) < 0)
state->err = CLEANUP_STAT_WRITE;
state->sender = mystrndup(STR(state->buf), LEN(state->buf)); state->sender = mystrndup(STR(state->buf), LEN(state->buf));
} }

View File

@@ -76,6 +76,11 @@
/* \fBdebug_peer_level\fR configuration parameters instead. /* \fBdebug_peer_level\fR configuration parameters instead.
/* .IP "\fB-U\fR (ignored)" /* .IP "\fB-U\fR (ignored)"
/* Initial user submission. /* Initial user submission.
/* .IP \fB-V\fR
/* Variable Envelope Return Path. Given an envelope sender address
/* \fIprefix\fR-@\fIorigin\fR, each recipient \fIuser@domain\fR
/* receives mail with a personalized envelope sender address
/* \fIprefix\fB-\fIuser=domain\fR@\fIorigin\fR.
/* .IP \fB-bd\fR /* .IP \fB-bd\fR
/* Go into daemon mode. This mode of operation is implemented by /* Go into daemon mode. This mode of operation is implemented by
/* executing the \fBpostfix start\fR command. /* executing the \fBpostfix start\fR command.
@@ -319,6 +324,11 @@ static void sendmail_cleanup(void);
#define SM_FLAG_DEFAULT (SM_FLAG_AEOF) #define SM_FLAG_DEFAULT (SM_FLAG_AEOF)
/*
* VERP support.
*/
char *verp_delims;
/* /*
* Silly little macros (SLMs). * Silly little macros (SLMs).
*/ */
@@ -414,6 +424,10 @@ static void enqueue(const int flags, const char *sender, const char *full_name,
if (full_name || (full_name = fullname()) != 0) if (full_name || (full_name = fullname()) != 0)
rec_fputs(dst, REC_TYPE_FULL, full_name); rec_fputs(dst, REC_TYPE_FULL, full_name);
rec_fputs(dst, REC_TYPE_FROM, saved_sender); rec_fputs(dst, REC_TYPE_FROM, saved_sender);
if (verp_delims && *saved_sender == 0)
msg_fatal("-V option requires non-null sender address");
if (verp_delims)
rec_fputs(dst, REC_TYPE_VERP, verp_delims);
if (recipients) { if (recipients) {
for (cpp = recipients; *cpp != 0; cpp++) { for (cpp = recipients; *cpp != 0; cpp++) {
tree = tok822_parse(*cpp); tree = tok822_parse(*cpp);
@@ -794,7 +808,7 @@ int main(int argc, char **argv)
optind++; optind++;
continue; continue;
} }
if ((c = GETOPT(argc, argv, "B:C:F:GIN:R:UX:b:ce:f:h:imno:p:r:q:tvx")) <= 0) if ((c = GETOPT(argc, argv, "B:C:F:GIN:R:UVX:b:ce:f:h:imno:p:r:q:tvx")) <= 0)
break; break;
switch (c) { switch (c) {
default: default:
@@ -817,6 +831,9 @@ int main(int argc, char **argv)
break; break;
case 'R': /* DSN */ case 'R': /* DSN */
break; break;
case 'V': /* VERP */
verp_delims = "";
break;
case 'b': case 'b':
switch (*optarg) { switch (*optarg) {
default: default:

View File

@@ -32,8 +32,8 @@
/* STANDARDS /* STANDARDS
/* RFC 821 (SMTP protocol) /* RFC 821 (SMTP protocol)
/* RFC 1123 (Host requirements) /* RFC 1123 (Host requirements)
/* RFC 1651 (SMTP service extensions)
/* RFC 1652 (8bit-MIME transport) /* RFC 1652 (8bit-MIME transport)
/* RFC 1869 (SMTP service extensions)
/* RFC 1854 (SMTP Pipelining) /* RFC 1854 (SMTP Pipelining)
/* RFC 1870 (Message Size Declaration) /* RFC 1870 (Message Size Declaration)
/* RFC 1985 (ETRN command) /* RFC 1985 (ETRN command)
@@ -363,6 +363,12 @@ char *smtpd_path;
#define STR(x) vstring_str(x) #define STR(x) vstring_str(x)
#define LEN(x) VSTRING_LEN(x) #define LEN(x) VSTRING_LEN(x)
/*
* VERP command name.
*/
#define VERP_CMD "XVERP"
#define VERP_CMD_LEN 5
/* /*
* Forward declarations. * Forward declarations.
*/ */
@@ -459,6 +465,7 @@ static int ehlo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
smtpd_chat_reply(state, "250-AUTH=%s", state->sasl_mechanism_list); smtpd_chat_reply(state, "250-AUTH=%s", state->sasl_mechanism_list);
} }
#endif #endif
smtpd_chat_reply(state, "250-%s", VERP_CMD);
smtpd_chat_reply(state, "250 8BITMIME"); smtpd_chat_reply(state, "250 8BITMIME");
return (0); return (0);
} }
@@ -626,6 +633,7 @@ static int mail_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
char *err; char *err;
int narg; int narg;
char *arg; char *arg;
char *verp_delims = 0;
state->msg_size = 0; state->msg_size = 0;
@@ -680,12 +688,27 @@ static int mail_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
return (-1); return (-1);
} }
#endif #endif
} else if (strcasecmp(arg, VERP_CMD) == 0) {
verp_delims = "";
} else if (strncasecmp(arg, VERP_CMD, VERP_CMD_LEN) == 0
&& arg[VERP_CMD_LEN] == '=') {
verp_delims = arg + VERP_CMD_LEN + 1;
if (strlen(verp_delims) != 2) {
state->error_mask |= MAIL_ERROR_PROTOCOL;
smtpd_chat_reply(state, "501 Bad %s parameter: %s",
VERP_CMD, arg);
return (-1);
}
} else { } else {
state->error_mask |= MAIL_ERROR_PROTOCOL; state->error_mask |= MAIL_ERROR_PROTOCOL;
smtpd_chat_reply(state, "555 Unsupported option: %s", arg); smtpd_chat_reply(state, "555 Unsupported option: %s", arg);
return (-1); return (-1);
} }
} }
if (verp_delims && argv[2].strval[0] == 0) {
smtpd_chat_reply(state, "503 Error: XVERP requires non-null sender");
return (-1);
}
state->time = time((time_t *) 0); state->time = time((time_t *) 0);
if (SMTPD_STAND_ALONE(state) == 0 if (SMTPD_STAND_ALONE(state) == 0
&& var_smtpd_delay_reject == 0 && var_smtpd_delay_reject == 0
@@ -718,6 +741,8 @@ static int mail_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
if (*var_filter_xport) if (*var_filter_xport)
rec_fprintf(state->cleanup, REC_TYPE_FILT, "%s", var_filter_xport); rec_fprintf(state->cleanup, REC_TYPE_FILT, "%s", var_filter_xport);
rec_fputs(state->cleanup, REC_TYPE_FROM, argv[2].strval); rec_fputs(state->cleanup, REC_TYPE_FROM, argv[2].strval);
if (verp_delims)
rec_fputs(state->cleanup, REC_TYPE_VERP, verp_delims);
state->sender = mystrdup(argv[2].strval); state->sender = mystrdup(argv[2].strval);
smtpd_chat_reply(state, "250 Ok"); smtpd_chat_reply(state, "250 Ok");
return (0); return (0);

View File

@@ -8,7 +8,7 @@
/* \fBqmqp-sink\fR [\fB-cv\fR] [\fB-x \fItime\fR] /* \fBqmqp-sink\fR [\fB-cv\fR] [\fB-x \fItime\fR]
/* [\fBinet:\fR][\fIhost\fR]:\fIport\fR \fIbacklog\fR /* [\fBinet:\fR][\fIhost\fR]:\fIport\fR \fIbacklog\fR
/* /*
/* \fBqmqp-sink\fR [\fB-cv\fR] /* \fBqmqp-sink\fR [\fB-cv\fR] [\fB-x \fItime\fR]
/* \fBunix:\fR\fIpathname\fR \fIbacklog\fR /* \fBunix:\fR\fIpathname\fR \fIbacklog\fR
/* DESCRIPTION /* DESCRIPTION
/* \fIqmqp-sink\fR listens on the named host (or address) and port. /* \fIqmqp-sink\fR listens on the named host (or address) and port.