20201022
Bugfix (introduced: Postfix 2.2): after processing an
- XCCLIENT command, the smtps service was waiting for a TLS
+ XCLIENT command, the smtps service was waiting for a TLS
handshake. Found by Aki Tuomi. File: smtpd/smtpd.c.
20201025
smtp/smtp_proto.c.
Added missing employer attributions to .c and .h files.
+
+20201116
+
+ Documentation: document that check_mumble_mx_access will
+ look up A or AAAA records when a domain name has no MX
+ record, just like the Postfix SMTP client would. File:
+ proto/postconf.proto.
+
+20201122
+
+ Cleanup: log "Application error" instead of "Success" or
+ "Unknown error: 0" when an operation fails with errno ==
+ 0. File: util/vbuf_print.c.
+
+20201125
+
+ Documentation: in the cleanup(8) description of message
+ transformations, mention how some transformations are
+ controlled with the local_header_rewrite_clients,
+ always_add_missing_headers, and message_drop_headers parameter
+ settings. File: cleanup/cleanup.c.
+
+20201129
+
+ Cleanup: future-proofing a condition in delivered_hdr_init().
+ The code was not wrong, but the new code is more consistent
+ with new code in the bounce daemon where the difference does
+ matter. File: global/delivered_hdr.c
+
+20201205
+
+ Testing: generic test_main() routine to initialize configuration
+ parameters before running a test routine. Files:
+ global/test_main.[hc].
+
+ Feature: specify "enable_threaded_bounces = yes" to enable
+ bounce messages that link to the original message with a
+ References: and In-Reply_to: header. Based on code by Andreas
+ Thienemann. See RELEASE_NOTES for caveats. Files:
+ proto/postconf.proto, bounce/bounce_notify_tester.c, many
+ test data files to exercise corner cases.
the software under the license of their choice. Those who are more
comfortable with the IPL can continue with that license.
+Major changes with snapshot 20201205
+====================================
+
+Support for threaded bounces. This allows mail readers to present
+a non-delivery notification in the same email thread as the original
+message.
+
+Unfortunately, this also makes it easy for users to mistakenly delete
+the whole email thread (all related messages), instead of deleting
+only the non-delivery notification.
+
+To enable, specify "enable_threaded_bounces = yes".
+
Major changes with snapshot 20201025
====================================
Wish list:
- Does tlsproxy terminate to soon after 'postfix reload'?
- like, while a session is still im progress? Does it depend
- on the server or client role?
-
Eliminate duplicate user_acl check from sendmail, and pass
the result through the postdrop-to-sendmail protocol. This
requires that postdrop reads all inputs before responding.
Then we can also consider to save input to dead.letter (drop
setgid privilege, use safe_open() to avoid clobbering files).
+ Allow '}' at the beginning of a line. This would make
+ multi-line configuration settings easier to enter.
+
Understand what happens with DNSSEC related status fields
in posttls-finger when resolv.conf points to a host that
runs no DNS server.
parameter. For example:
http://postfix.1071664.n5.nabble.com/Relay-attempt-questions-td103646.html
- Document that check_mumble_mx_access generates synthetic
- MX records i.e. A/AAAA where no MX exists.
-
- Someone suggested adding References: and In-Reply-To: headers
- in bounce messages. Downside: that will make it harder to
- delete a bounce without deleting other mail. Therefore do
- not enable by default.
-
Hardening the half-dane behavior: some sites may rely on
current behavior which allows original MX domain name for
certificate matches. Requires a new (compatibility) parameter
setting?
Code deduplication: migrate multi_server applications to
- event_server. In addition to the default event_server
- accept() handler, also register a read event callback for
- handling post_accept events. But the currrent multi_server
- API foits typical usage better.
-
- Maybe expand %m to "application error" when errno == 0.
+ event_server, because the multi_server and event_server
+ skeletons are much more similar than other skeletons. In
+ addition to the default event_server accept() handler, also
+ register a read event callback for handling post_accept
+ events. But the currrent multi_server API fits typical usage
+ better.
smtp_sasl_tls_security_options = noanonymous, and make
smtp_sasl_security_options default dependent on the
<b><a href="postconf.5.html#service_name">service_name</a> (read-only)</b>
The <a href="master.5.html">master.cf</a> service name of a Postfix daemon process.
+ Available in Postfix 3.6 and later:
+
+ <b><a href="postconf.5.html#enable_threaded_bounces">enable_threaded_bounces</a> (no)</b>
+ Enable non-delivery notifications (bounce messages) that link to
+ the original message by including a References: and In-Reply_to:
+ header with the original Message-ID value.
+
<b>FILES</b>
/var/spool/postfix/bounce/* non-delivery records
/var/spool/postfix/defer/* non-delivery records
The <a href="cleanup.8.html"><b>cleanup</b>(8)</a> daemon processes inbound mail, inserts it into the
<b>incoming</b> mail queue, and informs the queue manager of its arrival.
- The <a href="cleanup.8.html"><b>cleanup</b>(8)</a> daemon always performs the following transformations:
+ The <a href="cleanup.8.html"><b>cleanup</b>(8)</a> daemon performs the following transformations:
<b>o</b> Insert missing message headers: (<b>Resent-</b>) <b>From:</b>, <b>To:</b>, <b>Mes-</b>
<b>sage-Id:</b>, and <b>Date:</b>.
+ This is enabled with the <b><a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a></b> and
+ <b><a href="postconf.5.html#always_add_missing_headers">always_add_missing_headers</a></b> parameter settings.
- <b>o</b> Transform envelope and header addresses to the standard
+ <b>o</b> Transform envelope and header addresses to the standard
<i>user@fully-qualified-domain</i> form that is expected by other Post-
- fix programs. This task is delegated to the <a href="trivial-rewrite.8.html"><b>trivial-rewrite</b>(8)</a>
- daemon.
+ fix programs. This task depends on the <a href="trivial-rewrite.8.html"><b>trivial-rewrite</b>(8)</a> dae-
+ mon.
+ The header transformation is enabled with the <b><a href="postconf.5.html#local_header_rewrite_clients">local_header_re</a>-</b>
+ <b><a href="postconf.5.html#local_header_rewrite_clients">write_clients</a></b> parameter setting.
<b>o</b> Eliminate duplicate envelope recipient addresses.
+ This is enabled with the <b><a href="postconf.5.html#duplicate_filter_limit">duplicate_filter_limit</a></b> parameter set-
+ ting.
- <b>o</b> Remove message headers: <b>Bcc</b>, <b>Content-Length</b>, <b>Resent-Bcc</b>,
+ <b>o</b> Remove message headers: <b>Bcc</b>, <b>Content-Length</b>, <b>Resent-Bcc</b>,
<b>Return-Path</b>.
-
- The following address transformations are optional:
+ This is enabled with the <a href="postconf.5.html#message_drop_headers">message_drop_headers</a> parameter setting.
<b>o</b> Optionally, rewrite all envelope and header addresses according
to the mappings specified in the <a href="canonical.5.html"><b>canonical</b>(5)</a> lookup tables.
+ The header transformation is enabled with the <b><a href="postconf.5.html#local_header_rewrite_clients">local_header_re</a>-</b>
+ <b><a href="postconf.5.html#local_header_rewrite_clients">write_clients</a></b> parameter setting.
- <b>o</b> Optionally, masquerade envelope sender addresses and message
- header addresses (i.e. strip host or domain information below
- all domains listed in the <b><a href="postconf.5.html#masquerade_domains">masquerade_domains</a></b> parameter, except
- for user names listed in <b><a href="postconf.5.html#masquerade_exceptions">masquerade_exceptions</a></b>). By default,
+ <b>o</b> Optionally, masquerade envelope sender addresses and message
+ header addresses (i.e. strip host or domain information below
+ all domains listed in the <b><a href="postconf.5.html#masquerade_domains">masquerade_domains</a></b> parameter, except
+ for user names listed in <b><a href="postconf.5.html#masquerade_exceptions">masquerade_exceptions</a></b>). By default,
address masquerading does not affect envelope recipients.
+ The header transformation is enabled with the <b><a href="postconf.5.html#local_header_rewrite_clients">local_header_re</a>-</b>
+ <b><a href="postconf.5.html#local_header_rewrite_clients">write_clients</a></b> parameter setting.
<b>o</b> Optionally, expand envelope recipients according to information
- found in the <a href="virtual.5.html"><b>virtual</b>(5)</a> lookup tables.
+ found in the <b><a href="postconf.5.html#virtual_alias_maps">virtual_alias_maps</a></b> lookup tables.
The <a href="cleanup.8.html"><b>cleanup</b>(8)</a> daemon performs sanity checks on the content of each
message. When it finds a problem, by default it returns a diagnostic
- status to the client, and leaves it up to the client to deal with the
- problem. Alternatively, the client can request the <a href="cleanup.8.html"><b>cleanup</b>(8)</a> daemon to
- bounce the message back to the sender in case of trouble.
+ status to the cleanup service client, and leaves it up to the client to
+ deal with the problem. Alternatively, the client can request the
+ <a href="cleanup.8.html"><b>cleanup</b>(8)</a> daemon to bounce the message back to the sender in case of
+ trouble.
<b>STANDARDS</b>
<a href="http://tools.ietf.org/html/rfc822">RFC 822</a> (ARPA Internet Text Messages)
Problems and transactions are logged to <b>syslogd</b>(8) or <a href="postlogd.8.html"><b>postlogd</b>(8)</a>.
<b>BUGS</b>
- Table-driven rewriting rules make it hard to express <b>if then else</b> and
+ Table-driven rewriting rules make it hard to express <b>if then else</b> and
other logical relationships.
<b>CONFIGURATION PARAMETERS</b>
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 <a href="postconf.5.html"><b>postconf</b>(5)</a> for
+ 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>COMPATIBILITY CONTROLS</b>
Available in Postfix version 2.1 only:
<b><a href="postconf.5.html#enable_errors_to">enable_errors_to</a> (no)</b>
- Report mail delivery errors to the address specified with the
- non-standard Errors-To: message header, instead of the envelope
- sender address (this feature is removed with Postfix version
- 2.2, is turned off by default with Postfix version 2.1, and is
+ Report mail delivery errors to the address specified with the
+ non-standard Errors-To: message header, instead of the envelope
+ sender address (this feature is removed with Postfix version
+ 2.2, is turned off by default with Postfix version 2.1, and is
always turned on with older Postfix versions).
Available in Postfix version 2.6 and later:
<b><a href="postconf.5.html#always_add_missing_headers">always_add_missing_headers</a> (no)</b>
- Always add (Resent-) From:, To:, Date: or Message-ID: headers
+ Always add (Resent-) From:, To:, Date: or Message-ID: headers
when not present.
Available in Postfix version 2.9 and later:
Available in Postfix version 3.0 and later:
<b><a href="postconf.5.html#message_drop_headers">message_drop_headers</a> (bcc, content-length, resent-bcc, return-path)</b>
- Names of message headers that the <a href="cleanup.8.html"><b>cleanup</b>(8)</a> daemon will remove
+ Names of message headers that the <a href="cleanup.8.html"><b>cleanup</b>(8)</a> daemon will remove
after applying <a href="header_checks.5.html"><b>header_checks</b>(5)</a> and before invoking Milter
applications.
viruses. It is not a general content filter.
<b><a href="postconf.5.html#body_checks">body_checks</a> (empty)</b>
- Optional lookup tables for content inspection as specified in
+ Optional lookup tables for content inspection as specified in
the <a href="header_checks.5.html"><b>body_checks</b>(5)</a> manual page.
<b><a href="postconf.5.html#header_checks">header_checks</a> (empty)</b>
- Optional lookup tables for content inspection of primary
- non-MIME message headers, as specified in the <a href="header_checks.5.html"><b>header_checks</b>(5)</a>
+ Optional lookup tables for content inspection of primary
+ non-MIME message headers, as specified in the <a href="header_checks.5.html"><b>header_checks</b>(5)</a>
manual page.
Available in Postfix version 2.0 and later:
<b><a href="postconf.5.html#body_checks_size_limit">body_checks_size_limit</a> (51200)</b>
- How much text in a message body segment (or attachment, if you
+ How much text in a message body segment (or attachment, if you
prefer to use that term) is subjected to <a href="postconf.5.html#body_checks">body_checks</a> inspection.
<b><a href="postconf.5.html#mime_header_checks">mime_header_checks</a> ($<a href="postconf.5.html#header_checks">header_checks</a>)</b>
- Optional lookup tables for content inspection of MIME related
- message headers, as described in the <a href="header_checks.5.html"><b>header_checks</b>(5)</a> manual
+ Optional lookup tables for content inspection of MIME related
+ message headers, as described in the <a href="header_checks.5.html"><b>header_checks</b>(5)</a> manual
page.
<b><a href="postconf.5.html#nested_header_checks">nested_header_checks</a> ($<a href="postconf.5.html#header_checks">header_checks</a>)</b>
- Optional lookup tables for content inspection of non-MIME mes-
- sage headers in attached messages, as described in the
+ Optional lookup tables for content inspection of non-MIME mes-
+ sage headers in attached messages, as described in the
<a href="header_checks.5.html"><b>header_checks</b>(5)</a> manual page.
Available in Postfix version 2.3 and later:
<b><a href="postconf.5.html#message_reject_characters">message_reject_characters</a> (empty)</b>
- The set of characters that Postfix will reject in message con-
+ The set of characters that Postfix will reject in message con-
tent.
<b><a href="postconf.5.html#message_strip_characters">message_strip_characters</a> (empty)</b>
<b>BEFORE QUEUE MILTER CONTROLS</b>
As of version 2.3, Postfix supports the Sendmail version 8 Milter (mail
- filter) protocol. When mail is not received via the <a href="smtpd.8.html">smtpd(8)</a> server,
+ filter) protocol. When mail is not received via the <a href="smtpd.8.html">smtpd(8)</a> server,
the <a href="cleanup.8.html">cleanup(8)</a> server will simulate SMTP events to the extent that this
is possible. For details see the <a href="MILTER_README.html">MILTER_README</a> document.
<b><a href="postconf.5.html#non_smtpd_milters">non_smtpd_milters</a> (empty)</b>
- A list of Milter (mail filter) applications for new mail that
+ A list of Milter (mail filter) applications for new mail that
does not arrive via the Postfix <a href="smtpd.8.html"><b>smtpd</b>(8)</a> server.
<b><a href="postconf.5.html#milter_protocol">milter_protocol</a> (6)</b>
- The mail filter protocol version and optional protocol exten-
- sions for communication with a Milter application; prior to
+ The mail filter protocol version and optional protocol exten-
+ sions for communication with a Milter application; prior to
Postfix 2.6 the default protocol is 2.
<b><a href="postconf.5.html#milter_default_action">milter_default_action</a> (tempfail)</b>
- The default action when a Milter (mail filter) response is
- unavailable (for example, bad Postfix configuration or Milter
+ The default action when a Milter (mail filter) response is
+ unavailable (for example, bad Postfix configuration or Milter
failure).
<b><a href="postconf.5.html#milter_macro_daemon_name">milter_macro_daemon_name</a> ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
- The {daemon_name} macro value for Milter (mail filter) applica-
+ The {daemon_name} macro value for Milter (mail filter) applica-
tions.
<b><a href="postconf.5.html#milter_macro_v">milter_macro_v</a> ($<a href="postconf.5.html#mail_name">mail_name</a> $<a href="postconf.5.html#mail_version">mail_version</a>)</b>
tion, and for negotiating protocol options.
<b><a href="postconf.5.html#milter_command_timeout">milter_command_timeout</a> (30s)</b>
- The time limit for sending an SMTP command to a Milter (mail
+ The time limit for sending an SMTP command to a Milter (mail
filter) application, and for receiving the response.
<b><a href="postconf.5.html#milter_content_timeout">milter_content_timeout</a> (300s)</b>
- The time limit for sending message content to a Milter (mail
+ The time limit for sending message content to a Milter (mail
filter) application, and for receiving the response.
<b><a href="postconf.5.html#milter_connect_macros">milter_connect_macros</a> (see 'postconf -d' output)</b>
- The macros that are sent to Milter (mail filter) applications
+ The macros that are sent to Milter (mail filter) applications
after completion of an SMTP connection.
<b><a href="postconf.5.html#milter_helo_macros">milter_helo_macros</a> (see 'postconf -d' output)</b>
- The macros that are sent to Milter (mail filter) applications
+ The macros that are sent to Milter (mail filter) applications
after the SMTP HELO or EHLO command.
<b><a href="postconf.5.html#milter_mail_macros">milter_mail_macros</a> (see 'postconf -d' output)</b>
- The macros that are sent to Milter (mail filter) applications
+ The macros that are sent to Milter (mail filter) applications
after the SMTP MAIL FROM command.
<b><a href="postconf.5.html#milter_rcpt_macros">milter_rcpt_macros</a> (see 'postconf -d' output)</b>
- The macros that are sent to Milter (mail filter) applications
+ The macros that are sent to Milter (mail filter) applications
after the SMTP RCPT TO command.
<b><a href="postconf.5.html#milter_data_macros">milter_data_macros</a> (see 'postconf -d' output)</b>
- The macros that are sent to version 4 or higher Milter (mail
+ The macros that are sent to version 4 or higher Milter (mail
filter) applications after the SMTP DATA command.
<b><a href="postconf.5.html#milter_unknown_command_macros">milter_unknown_command_macros</a> (see 'postconf -d' output)</b>
- The macros that are sent to version 3 or higher Milter (mail
+ The macros that are sent to version 3 or higher Milter (mail
filter) applications after an unknown SMTP command.
<b><a href="postconf.5.html#milter_end_of_data_macros">milter_end_of_data_macros</a> (see 'postconf -d' output)</b>
- The macros that are sent to Milter (mail filter) applications
+ The macros that are sent to Milter (mail filter) applications
after the message end-of-data.
Available in Postfix version 2.5 and later:
<b><a href="postconf.5.html#milter_end_of_header_macros">milter_end_of_header_macros</a> (see 'postconf -d' output)</b>
- The macros that are sent to Milter (mail filter) applications
+ The macros that are sent to Milter (mail filter) applications
after the end of the message header.
Available in Postfix version 2.7 and later:
Available in Postfix version 3.1 and later:
<b><a href="postconf.5.html#milter_macro_defaults">milter_macro_defaults</a> (empty)</b>
- Optional list of <i>name=value</i> pairs that specify default values
- for arbitrary macros that Postfix may send to Milter applica-
+ Optional list of <i>name=value</i> pairs that specify default values
+ for arbitrary macros that Postfix may send to Milter applica-
tions.
<b>MIME PROCESSING CONTROLS</b>
ing information.
<b><a href="postconf.5.html#strict_mime_encoding_domain">strict_mime_encoding_domain</a> (no)</b>
- Reject mail with invalid Content-Transfer-Encoding: information
+ Reject mail with invalid Content-Transfer-Encoding: information
for the message/* or multipart/* MIME content types.
Available in Postfix version 2.5 and later:
<b><a href="postconf.5.html#detect_8bit_encoding_header">detect_8bit_encoding_header</a> (yes)</b>
- Automatically detect 8BITMIME body content by looking at Con-
- tent-Transfer-Encoding: message headers; historically, this
+ Automatically detect 8BITMIME body content by looking at Con-
+ tent-Transfer-Encoding: message headers; historically, this
behavior was hard-coded to be "always on".
<b>AUTOMATIC BCC RECIPIENT CONTROLS</b>
- Postfix can automatically add BCC (blind carbon copy) when mail enters
+ Postfix can automatically add BCC (blind carbon copy) when mail enters
the mail system:
<b><a href="postconf.5.html#always_bcc">always_bcc</a> (empty)</b>
- Optional address that receives a "blind carbon copy" of each
+ Optional address that receives a "blind carbon copy" of each
message that is received by the Postfix mail system.
Available in Postfix version 2.1 and later:
<b><a href="postconf.5.html#sender_bcc_maps">sender_bcc_maps</a> (empty)</b>
- Optional BCC (blind carbon-copy) address lookup tables, indexed
+ Optional BCC (blind carbon-copy) address lookup tables, indexed
by sender address.
<b><a href="postconf.5.html#recipient_bcc_maps">recipient_bcc_maps</a> (empty)</b>
- Optional BCC (blind carbon-copy) address lookup tables, indexed
+ Optional BCC (blind carbon-copy) address lookup tables, indexed
by recipient address.
<b>ADDRESS TRANSFORMATION CONTROLS</b>
- Address rewriting is delegated to the <a href="trivial-rewrite.8.html"><b>trivial-rewrite</b>(8)</a> daemon. The
+ Address rewriting is delegated to the <a href="trivial-rewrite.8.html"><b>trivial-rewrite</b>(8)</a> daemon. The
<a href="cleanup.8.html"><b>cleanup</b>(8)</a> server implements table driven address mapping.
<b><a href="postconf.5.html#empty_address_recipient">empty_address_recipient</a> (MAILER-DAEMON)</b>
The recipient of mail addressed to the null address.
<b><a href="postconf.5.html#canonical_maps">canonical_maps</a> (empty)</b>
- Optional address mapping lookup tables for message headers and
+ Optional address mapping lookup tables for message headers and
envelopes.
<b><a href="postconf.5.html#recipient_canonical_maps">recipient_canonical_maps</a> (empty)</b>
- Optional address mapping lookup tables for envelope and header
+ Optional address mapping lookup tables for envelope and header
recipient addresses.
<b><a href="postconf.5.html#sender_canonical_maps">sender_canonical_maps</a> (empty)</b>
- Optional address mapping lookup tables for envelope and header
+ Optional address mapping lookup tables for envelope and header
sender addresses.
<b><a href="postconf.5.html#masquerade_classes">masquerade_classes</a> (envelope_sender, header_sender, header_recipient)</b>
What addresses are subject to address masquerading.
<b><a href="postconf.5.html#masquerade_domains">masquerade_domains</a> (empty)</b>
- Optional list of domains whose subdomain structure will be
+ Optional list of domains whose subdomain structure will be
stripped off in email addresses.
<b><a href="postconf.5.html#masquerade_exceptions">masquerade_exceptions</a> (empty)</b>
- Optional list of user names that are not subjected to address
- masquerading, even when their addresses match $<a href="postconf.5.html#masquerade_domains">masquer</a>-
+ Optional list of user names that are not subjected to address
+ masquerading, even when their addresses match $<a href="postconf.5.html#masquerade_domains">masquer</a>-
<a href="postconf.5.html#masquerade_domains">ade_domains</a>.
<b><a href="postconf.5.html#propagate_unmatched_extensions">propagate_unmatched_extensions</a> (canonical, virtual)</b>
- What address lookup tables copy an address extension from the
+ What address lookup tables copy an address extension from the
lookup key to the lookup result.
Available before Postfix version 2.0:
<b><a href="postconf.5.html#virtual_maps">virtual_maps</a> (empty)</b>
- Optional lookup tables with a) names of domains for which all
- addresses are aliased to addresses in other local or remote
+ Optional lookup tables with a) names of domains for which all
+ addresses are aliased to addresses in other local or remote
domains, and b) addresses that are aliased to addresses in other
local or remote domains.
Available in Postfix version 2.0 and later:
<b><a href="postconf.5.html#virtual_alias_maps">virtual_alias_maps</a> ($<a href="postconf.5.html#virtual_maps">virtual_maps</a>)</b>
- Optional lookup tables that alias specific mail addresses or
+ Optional lookup tables that alias specific mail addresses or
domains to other local or remote address.
Available in Postfix version 2.2 and later:
- <b><a href="postconf.5.html#canonical_classes">canonical_classes</a> (envelope_sender, envelope_recipient, header_sender,</b>
+ <b><a href="postconf.5.html#canonical_classes">canonical_classes</a> (envelope_sender, envelope_recipient, header_sender,</b>
<b>header_recipient)</b>
What addresses are subject to <a href="postconf.5.html#canonical_maps">canonical_maps</a> address mapping.
<b><a href="postconf.5.html#recipient_canonical_classes">recipient_canonical_classes</a> (envelope_recipient, header_recipient)</b>
- What addresses are subject to <a href="postconf.5.html#recipient_canonical_maps">recipient_canonical_maps</a> address
+ What addresses are subject to <a href="postconf.5.html#recipient_canonical_maps">recipient_canonical_maps</a> address
mapping.
<b><a href="postconf.5.html#sender_canonical_classes">sender_canonical_classes</a> (envelope_sender, header_sender)</b>
ping.
<b><a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a> (empty)</b>
- Don't rewrite message headers from remote clients at all when
- this parameter is empty; otherwise, rewrite message headers and
+ Don't rewrite message headers from remote clients at all when
+ this parameter is empty; otherwise, rewrite message headers and
append the specified domain name to incomplete addresses.
<b>RESOURCE AND RATE CONTROLS</b>
<a href="showq.8.html"><b>showq</b>(8)</a> queue displays.
<b><a href="postconf.5.html#header_size_limit">header_size_limit</a> (102400)</b>
- The maximal amount of memory in bytes for storing a message
+ The maximal amount of memory in bytes for storing a message
header.
<b><a href="postconf.5.html#hopcount_limit">hopcount_limit</a> (50)</b>
in the primary message headers.
<b><a href="postconf.5.html#in_flow_delay">in_flow_delay</a> (1s)</b>
- Time to pause before accepting a new message, when the message
+ Time to pause before accepting a new message, when the message
arrival rate exceeds the message delivery rate.
<b><a href="postconf.5.html#message_size_limit">message_size_limit</a> (10240000)</b>
- The maximal size in bytes of a message, including envelope
+ The maximal size in bytes of a message, including envelope
information.
Available in Postfix version 2.0 and later:
<b><a href="postconf.5.html#header_address_token_limit">header_address_token_limit</a> (10240)</b>
- The maximal number of address tokens are allowed in an address
+ The maximal number of address tokens are allowed in an address
message header.
<b><a href="postconf.5.html#mime_boundary_length_limit">mime_boundary_length_limit</a> (2048)</b>
Available in Postfix version 2.1 and later:
<b><a href="postconf.5.html#virtual_alias_expansion_limit">virtual_alias_expansion_limit</a> (1000)</b>
- The maximal number of addresses that virtual alias expansion
+ The maximal number of addresses that virtual alias expansion
produces from each original recipient.
<b><a href="postconf.5.html#virtual_alias_recursion_limit">virtual_alias_recursion_limit</a> (1000)</b>
Available in Postfix version 3.0 and later:
<b><a href="postconf.5.html#virtual_alias_address_length_limit">virtual_alias_address_length_limit</a> (1000)</b>
- The maximal length of an email address after virtual alias
+ The maximal length of an email address after virtual alias
expansion.
<b>SMTPUTF8 CONTROLS</b>
Preliminary SMTPUTF8 support is introduced with Postfix 3.0.
<b><a href="postconf.5.html#smtputf8_enable">smtputf8_enable</a> (yes)</b>
- Enable preliminary SMTPUTF8 support for the protocols described
+ Enable preliminary SMTPUTF8 support for the protocols described
in <a href="http://tools.ietf.org/html/rfc6531">RFC 6531</a>..6533.
<b><a href="postconf.5.html#smtputf8_autodetect_classes">smtputf8_autodetect_classes</a> (sendmail, verify)</b>
- Detect that a message requires SMTPUTF8 support for the speci-
+ Detect that a message requires SMTPUTF8 support for the speci-
fied mail origin classes.
Available in Postfix version 3.2 and later:
<b><a href="postconf.5.html#enable_idna2003_compatibility">enable_idna2003_compatibility</a> (no)</b>
- Enable 'transitional' compatibility between IDNA2003 and
- IDNA2008, when converting UTF-8 domain names to/from the ASCII
+ Enable 'transitional' compatibility between IDNA2003 and
+ IDNA2008, when converting UTF-8 domain names to/from the ASCII
form that is used for DNS lookups.
<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 <a href="master.5.html">master.cf</a> con-
+ The default location of the Postfix <a href="postconf.5.html">main.cf</a> and <a href="master.5.html">master.cf</a> con-
figuration 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
+ 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 point when log-
+ The maximal number of digits after the decimal point when log-
ging sub-second delay values.
<b><a href="postconf.5.html#delay_warning_time">delay_warning_time</a> (0h)</b>
- The time after which the sender receives a copy of the message
+ The time after which the sender receives a copy of the message
headers of mail that is still queued.
<b><a href="postconf.5.html#ipc_timeout">ipc_timeout</a> (3600s)</b>
- The time limit for sending or receiving information over an
+ The time limit for sending or receiving information over an
internal communication channel.
<b><a href="postconf.5.html#max_idle">max_idle</a> (100s)</b>
- The maximum amount of time that an idle Postfix daemon process
+ 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 internet hostname of this mail system.
<b><a href="postconf.5.html#myorigin">myorigin</a> ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
- The domain name that locally-posted mail appears to come from,
+ The domain name that locally-posted mail appears to come from,
and that locally posted mail is delivered to.
<b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
The location of the Postfix top-level queue directory.
<b><a href="postconf.5.html#soft_bounce">soft_bounce</a> (no)</b>
- Safety net to keep mail queued that would otherwise be returned
+ Safety net to keep mail queued that would otherwise be returned
to the sender.
<b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
The syslog facility of Postfix logging.
<b><a href="postconf.5.html#syslog_name">syslog_name</a> (see 'postconf -d' output)</b>
- A prefix that is prepended to the process name in syslog
+ A prefix that is prepended to the process name in syslog
records, so that, for example, "smtpd" becomes "prefix/smtpd".
Available in Postfix version 2.1 and later:
<b><a href="postconf.5.html#enable_original_recipient">enable_original_recipient</a> (yes)</b>
- Enable support for the original recipient address after an
- address is rewritten to a different address (for example with
+ Enable support for the original recipient address after an
+ address is rewritten to a different address (for example with
aliasing or with canonical mapping).
Available in Postfix 3.3 and later:
Available in Postfix 3.5 and later:
<b><a href="postconf.5.html#info_log_address_format">info_log_address_format</a> (external)</b>
- The email address form that will be used in non-debug logging
+ The email address form that will be used in non-debug logging
(info, warning, etc.).
<b>FILES</b>
<b><a href="postconf.5.html#service_name">service_name</a> (read-only)</b>
The <a href="master.5.html">master.cf</a> service name of a Postfix daemon process.
+ Available in Postfix 3.6 and later:
+
+ <b><a href="postconf.5.html#enable_threaded_bounces">enable_threaded_bounces</a> (no)</b>
+ Enable non-delivery notifications (bounce messages) that link to
+ the original message by including a References: and In-Reply_to:
+ header with the original Message-ID value.
+
<b>FILES</b>
/var/spool/postfix/bounce/* non-delivery records
/var/spool/postfix/defer/* non-delivery records
address. </p>
+</DD>
+
+<DT><b><a name="enable_threaded_bounces">enable_threaded_bounces</a>
+(default: no)</b></DT><DD>
+
+<p> Enable non-delivery notifications (bounce messages) that link
+to the original message by including a References: and In-Reply_to:
+header with the original Message-ID value. There are advantages and
+disadvantages to consider. </p>
+
+<dl>
+
+<dt> <b> advantage </b> </dt> <dd> This allows mail readers to present
+a non-delivery notification in the same email thread as the original
+message. </dd>
+
+<dt> <b> disadvantage </b> </dt> <dd> This makes it easy for users to
+mistakenly delete the whole email thread (all related messages),
+instead of deleting only the non-delivery notification. </dd>
+
+</dl>
+
+<p> This feature is available in Postfix 3.6 and later. </p>
+
+
</DD>
<DT><b><a name="error_notice_recipient">error_notice_recipient</a>
<dl>
<dt><i>example.com</i></dt> <dd> Match the <i>example.com</i> domain,
-i.e. one of the names the server certificate must be <i>example.com</i>,
-upper and lower case distinctions are ignored. </dd>
+i.e. one of the names in the server certificate must be <i>example.com</i>.
+Upper and lower case distinctions are ignored. </dd>
<dt><i>.example.com</i></dt>
<dd> Match subdomains of the <i>example.com</i> domain, i.e. match
<dt><b><a name="check_client_mx_access">check_client_mx_access</a> <i><a href="DATABASE_README.html">type:table</a></i></b></dt>
<dd>Search the specified <a href="access.5.html">access(5)</a> database for the MX hosts for the
-client hostname, and execute the corresponding action. Note: a result
+client hostname, and execute the corresponding action. If no MX
+record is found, look up A or AAAA records, just like the Postfix
+SMTP client would. Note: a result
of "OK" is not allowed for safety reasons. Instead, use DUNNO in order
to exclude specific hosts from blacklists. This feature is available
in Postfix 2.7 and later. </dd>
<dd>Search the specified <a href="access.5.html">access(5)</a> database for the MX hosts for the
unverified reverse client hostname, and execute the corresponding
-action. Note: a result of "OK" is not allowed for safety reasons.
+action. If no MX record is found, look up A or AAAA records, just
+like the Postfix SMTP client would.
+Note: a result of "OK" is not allowed for safety reasons.
Instead, use DUNNO in order to exclude specific hosts from blacklists.
This feature is available in Postfix 2.7 and later. </dd>
<dd>Search the specified <a href="access.5.html">access(5)</a> database for the MX hosts for
the HELO or EHLO hostname, and execute the corresponding action.
+If no MX record is found, look up A or AAAA records, just like the
+Postfix SMTP client would.
Note 1: a result of "OK" is not allowed for safety reasons. Instead,
use DUNNO in order to exclude specific hosts from blacklists. Note
2: specify "<a href="postconf.5.html#smtpd_helo_required">smtpd_helo_required</a> = yes" to fully enforce this
<dt><b><a name="check_recipient_mx_access">check_recipient_mx_access</a> <i><a href="DATABASE_README.html">type:table</a></i></b></dt>
<dd>Search the specified <a href="access.5.html">access(5)</a> database for the MX hosts for
-the RCPT TO domain, and execute the corresponding action. Note:
+the RCPT TO domain, and execute the corresponding action. If no
+MX record is found, look up A or AAAA records, just like the Postfix
+SMTP client would. Note:
a result of "OK" is not allowed for safety reasons. Instead, use
DUNNO in order to exclude specific hosts from blacklists. This
feature is available in Postfix 2.1 and later. </dd>
<dt><b><a name="check_sender_mx_access">check_sender_mx_access</a> <i><a href="DATABASE_README.html">type:table</a></i></b></dt>
<dd>Search the specified <a href="access.5.html">access(5)</a> database for the MX hosts for
-the MAIL FROM domain, and execute the corresponding action. Note:
+the MAIL FROM domain, and execute the corresponding action. If no
+MX record is found, look up A or AAAA records, just like the Postfix
+SMTP client would. Note:
a result of "OK" is not allowed for safety reasons. Instead, use
DUNNO in order to exclude specific hosts from blacklists. This
feature is available in Postfix 2.1 and later. </dd>
<b><a href="postconf.5.html#service_name">service_name</a> (read-only)</b>
The <a href="master.5.html">master.cf</a> service name of a Postfix daemon process.
+ Available in Postfix 3.6 and later:
+
+ <b><a href="postconf.5.html#enable_threaded_bounces">enable_threaded_bounces</a> (no)</b>
+ Enable non-delivery notifications (bounce messages) that link to
+ the original message by including a References: and In-Reply_to:
+ header with the original Message-ID value.
+
<b>FILES</b>
/var/spool/postfix/bounce/* non-delivery records
/var/spool/postfix/defer/* non-delivery records
version 2.0 behaves as if this parameter is always set to \fByes\fR.
Postfix versions before 2.0 have no support for the original recipient
address.
+.SH enable_threaded_bounces (default: no)
+Enable non\-delivery notifications (bounce messages) that link
+to the original message by including a References: and In\-Reply_to:
+header with the original Message\-ID value. There are advantages and
+disadvantages to consider.
+.IP "\fB advantage \fR"
+This allows mail readers to present
+a non\-delivery notification in the same email thread as the original
+message.
+.br
+.IP "\fB disadvantage \fR"
+This makes it easy for users to
+mistakenly delete the whole email thread (all related messages),
+instead of deleting only the non\-delivery notification.
+.br
+.br
+.PP
+This feature is available in Postfix 3.6 and later.
.SH error_notice_recipient (default: postmaster)
The recipient of postmaster notifications about mail delivery
problems that are caused by policy, resource, software or protocol
Patterns specify domain names, or domain name suffixes:
.IP "\fIexample.com\fR"
Match the \fIexample.com\fR domain,
-i.e. one of the names the server certificate must be \fIexample.com\fR,
-upper and lower case distinctions are ignored.
+i.e. one of the names in the server certificate must be \fIexample.com\fR.
+Upper and lower case distinctions are ignored.
.br
.IP "\fI.example.com\fR"
Match subdomains of the \fIexample.com\fR domain, i.e. match
.br
.IP "\fBcheck_client_mx_access \fItype:table\fR\fR"
Search the specified \fBaccess\fR(5) database for the MX hosts for the
-client hostname, and execute the corresponding action. Note: a result
+client hostname, and execute the corresponding action. If no MX
+record is found, look up A or AAAA records, just like the Postfix
+SMTP client would. Note: a result
of "OK" is not allowed for safety reasons. Instead, use DUNNO in order
to exclude specific hosts from blacklists. This feature is available
in Postfix 2.7 and later.
.IP "\fBcheck_reverse_client_hostname_mx_access \fItype:table\fR\fR"
Search the specified \fBaccess\fR(5) database for the MX hosts for the
unverified reverse client hostname, and execute the corresponding
-action. Note: a result of "OK" is not allowed for safety reasons.
+action. If no MX record is found, look up A or AAAA records, just
+like the Postfix SMTP client would.
+Note: a result of "OK" is not allowed for safety reasons.
Instead, use DUNNO in order to exclude specific hosts from blacklists.
This feature is available in Postfix 2.7 and later.
.br
.IP "\fBcheck_helo_mx_access \fItype:table\fR\fR"
Search the specified \fBaccess\fR(5) database for the MX hosts for
the HELO or EHLO hostname, and execute the corresponding action.
+If no MX record is found, look up A or AAAA records, just like the
+Postfix SMTP client would.
Note 1: a result of "OK" is not allowed for safety reasons. Instead,
use DUNNO in order to exclude specific hosts from blacklists. Note
2: specify "smtpd_helo_required = yes" to fully enforce this
.br
.IP "\fBcheck_recipient_mx_access \fItype:table\fR\fR"
Search the specified \fBaccess\fR(5) database for the MX hosts for
-the RCPT TO domain, and execute the corresponding action. Note:
+the RCPT TO domain, and execute the corresponding action. If no
+MX record is found, look up A or AAAA records, just like the Postfix
+SMTP client would. Note:
a result of "OK" is not allowed for safety reasons. Instead, use
DUNNO in order to exclude specific hosts from blacklists. This
feature is available in Postfix 2.1 and later.
.br
.IP "\fBcheck_sender_mx_access \fItype:table\fR\fR"
Search the specified \fBaccess\fR(5) database for the MX hosts for
-the MAIL FROM domain, and execute the corresponding action. Note:
+the MAIL FROM domain, and execute the corresponding action. If no
+MX record is found, look up A or AAAA records, just like the Postfix
+SMTP client would. Note:
a result of "OK" is not allowed for safety reasons. Instead, use
DUNNO in order to exclude specific hosts from blacklists. This
feature is available in Postfix 2.1 and later.
Available in Postfix 3.3 and later:
.IP "\fBservice_name (read\-only)\fR"
The master.cf service name of a Postfix daemon process.
+.PP
+Available in Postfix 3.6 and later:
+.IP "\fBenable_threaded_bounces (no)\fR"
+Enable non\-delivery notifications (bounce messages) that link
+to the original message by including a References: and In\-Reply_to:
+header with the original Message\-ID value.
.SH "FILES"
.na
.nf
into the \fBincoming\fR mail queue, and informs the queue
manager of its arrival.
-The \fBcleanup\fR(8) daemon always performs the following transformations:
+The \fBcleanup\fR(8) daemon performs the following transformations:
.IP \(bu
Insert missing message headers: (\fBResent\-\fR) \fBFrom:\fR,
\fBTo:\fR, \fBMessage\-Id:\fR, and \fBDate:\fR.
+.br
+This is enabled with the \fBlocal_header_rewrite_clients\fR and
+\fBalways_add_missing_headers\fR parameter settings.
.IP \(bu
Transform envelope and header addresses to the standard
\fIuser@fully\-qualified\-domain\fR form that is expected by other
Postfix programs.
-This task is delegated to the \fBtrivial\-rewrite\fR(8) daemon.
+This task depends on the \fBtrivial\-rewrite\fR(8) daemon.
+.br
+The header transformation is enabled with the
+\fBlocal_header_rewrite_clients\fR parameter setting.
.IP \(bu
Eliminate duplicate envelope recipient addresses.
+.br
+This is enabled with the \fBduplicate_filter_limit\fR
+parameter setting.
.IP \(bu
Remove message headers: \fBBcc\fR, \fBContent\-Length\fR,
\fBResent\-Bcc\fR, \fBReturn\-Path\fR.
-.PP
-The following address transformations are optional:
+.br
+This is enabled with the message_drop_headers parameter
+setting.
.IP \(bu
Optionally, rewrite all envelope and header addresses according
to the mappings specified in the \fBcanonical\fR(5) lookup tables.
+.br
+The header transformation is enabled with the
+\fBlocal_header_rewrite_clients\fR parameter setting.
.IP \(bu
Optionally, masquerade envelope sender addresses and message
header addresses (i.e. strip host or domain information below
all domains listed in the \fBmasquerade_domains\fR parameter,
except for user names listed in \fBmasquerade_exceptions\fR).
By default, address masquerading does not affect envelope recipients.
+.br
+The header transformation is enabled with the
+\fBlocal_header_rewrite_clients\fR parameter setting.
.IP \(bu
Optionally, expand envelope recipients according to information
-found in the \fBvirtual\fR(5) lookup tables.
+found in the \fBvirtual_alias_maps\fR lookup tables.
.PP
The \fBcleanup\fR(8) daemon performs sanity checks on the content of
each message. When it finds a problem, by default it returns a
-diagnostic status to the client, and leaves it up to the client
+diagnostic status to the cleanup service client, and leaves
+it up to the client
to deal with the problem. Alternatively, the client can request
the \fBcleanup\fR(8) daemon to bounce the message back to the sender
in case of trouble.
s;\bfrozen_delivered_to\b;<a href="postconf.5.html#frozen_delivered_to">$&</a>;g;
s;\breset_owner_alias\b;<a href="postconf.5.html#reset_owner_alias">$&</a>;g;
s;\benable_long_queue_ids\b;<a href="postconf.5.html#enable_long_queue_ids">$&</a>;g;
+ s;\benable_threaded_bounces\b;<a href="postconf.5.html#enable_threaded_bounces">$&</a>;g;
# Transport-dependent magical parameters.
<dt><b><a name="check_client_mx_access">check_client_mx_access</a> <i><a href="DATABASE_README.html">type:table</a></i></b></dt>
<dd>Search the specified access(5) database for the MX hosts for the
-client hostname, and execute the corresponding action. Note: a result
+client hostname, and execute the corresponding action. If no MX
+record is found, look up A or AAAA records, just like the Postfix
+SMTP client would. Note: a result
of "OK" is not allowed for safety reasons. Instead, use DUNNO in order
to exclude specific hosts from blacklists. This feature is available
in Postfix 2.7 and later. </dd>
<dd>Search the specified access(5) database for the MX hosts for the
unverified reverse client hostname, and execute the corresponding
-action. Note: a result of "OK" is not allowed for safety reasons.
+action. If no MX record is found, look up A or AAAA records, just
+like the Postfix SMTP client would.
+Note: a result of "OK" is not allowed for safety reasons.
Instead, use DUNNO in order to exclude specific hosts from blacklists.
This feature is available in Postfix 2.7 and later. </dd>
<dd>Search the specified access(5) database for the MX hosts for
the HELO or EHLO hostname, and execute the corresponding action.
+If no MX record is found, look up A or AAAA records, just like the
+Postfix SMTP client would.
Note 1: a result of "OK" is not allowed for safety reasons. Instead,
use DUNNO in order to exclude specific hosts from blacklists. Note
2: specify "smtpd_helo_required = yes" to fully enforce this
<dt><b><a name="check_recipient_mx_access">check_recipient_mx_access</a> <i><a href="DATABASE_README.html">type:table</a></i></b></dt>
<dd>Search the specified access(5) database for the MX hosts for
-the RCPT TO domain, and execute the corresponding action. Note:
+the RCPT TO domain, and execute the corresponding action. If no
+MX record is found, look up A or AAAA records, just like the Postfix
+SMTP client would. Note:
a result of "OK" is not allowed for safety reasons. Instead, use
DUNNO in order to exclude specific hosts from blacklists. This
feature is available in Postfix 2.1 and later. </dd>
<dt><b><a name="check_sender_mx_access">check_sender_mx_access</a> <i><a href="DATABASE_README.html">type:table</a></i></b></dt>
<dd>Search the specified access(5) database for the MX hosts for
-the MAIL FROM domain, and execute the corresponding action. Note:
+the MAIL FROM domain, and execute the corresponding action. If no
+MX record is found, look up A or AAAA records, just like the Postfix
+SMTP client would. Note:
a result of "OK" is not allowed for safety reasons. Instead, use
DUNNO in order to exclude specific hosts from blacklists. This
feature is available in Postfix 2.1 and later. </dd>
<dl>
<dt><i>example.com</i></dt> <dd> Match the <i>example.com</i> domain,
-i.e. one of the names the server certificate must be <i>example.com</i>,
-upper and lower case distinctions are ignored. </dd>
+i.e. one of the names in the server certificate must be <i>example.com</i>.
+Upper and lower case distinctions are ignored. </dd>
<dt><i>.example.com</i></dt>
<dd> Match subdomains of the <i>example.com</i> domain, i.e. match
</p>
<p> This feature is available in Postfix 3.6 and later. </p>
+
+%PARAM enable_threaded_bounces no
+
+<p> Enable non-delivery notifications (bounce messages) that link
+to the original message by including a References: and In-Reply_to:
+header with the original Message-ID value. There are advantages and
+disadvantages to consider. </p>
+
+<dl>
+
+<dt> <b> advantage </b> </dt> <dd> This allows mail readers to present
+a non-delivery notification in the same email thread as the original
+message. </dd>
+
+<dt> <b> disadvantage </b> </dt> <dd> This makes it easy for users to
+mistakenly delete the whole email thread (all related messages),
+instead of deleting only the non-delivery notification. </dd>
+
+</dl>
+
+<p> This feature is available in Postfix 3.6 and later. </p>
TESTSRC =
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
CFLAGS = $(DEBUG) $(OPT) $(DEFS)
-TESTPROG=
+TESTPROG= bounce_notify_util_tester
PROG = bounce
SAMPLES = ../../conf/bounce.cf.default
INC_DIR = ../../include
rm -f $@
./annotate.sh <template_test.ref >$@
-main.cf:
- echo queue_directory=. >main.cf
- echo myhostname=example.com >>main.cf
-
$(OBJS): ../../conf/makedefs.out
Makefile: Makefile.in
test: $(TESTPROG)
-tests: update template_test 2template_test
+tests: update template_test 2template_test \
+ with-msgid-with-long-line_test \
+ with-msgid-with-eoh-event_test \
+ with-msgid-no-eoh-event_test \
+ no-msgid-with-eoh-event_test \
+ no-msgid-no-eoh-event_test \
+ with-msgid-with-filter_test
root_tests:
tidy: clean
+BOUNCE_NOTIFY_UTIL_TESTER_OBJS = bounce_notify_util_tester.o \
+ bounce_notify_util.o bounce_template.o bounce_templates.o
+
+bounce_notify_util_tester: $(BOUNCE_NOTIFY_UTIL_TESTER_OBJS) $(LIBS)
+ $(CC) -DTEST $(CFLAGS) -o $@ $(BOUNCE_NOTIFY_UTIL_TESTER_OBJS) \
+ $(LIBS) $(SYSLIBS)
+
# Avoid dependency on installed Postfix.
# XXX This still requires that default_privs, mail_owner etc. accounts exist.
-template_test: $(PROG) main.cf template_test.ref
+template_test: $(PROG) template_test.ref
+ echo queue_directory=. >main.cf
+ echo myhostname=example.com >>main.cf
+ touch -t 197101010000 main.cf
MAIL_CONFIG=. ./$(PROG) -SVzndump_templates >template_test.tmp
diff template_test.ref template_test.tmp
MAIL_CONFIG=. ./$(PROG) -SVzndump_templates \
-o bounce_template_file=template_test.ref > template_test.tmp
diff template_test.ref template_test.tmp
- rm -f template_test.tmp
+ rm -f template_test.tmp main.cf
-2template_test: $(PROG) main.cf template_test.ref 2template_test.in
+2template_test: $(PROG) template_test.ref 2template_test.in
+ echo queue_directory=. >main.cf
+ echo myhostname=example.com >>main.cf
+ touch -t 197101010000 main.cf
MAIL_CONFIG=. ./$(PROG) -SVzndump_templates \
-o bounce_template_file=2template_test.in > template_test.tmp
diff template_test.ref template_test.tmp
- rm -f template_test.tmp
+ rm -f template_test.tmp main.cf
+
+with-msgid-with-long-line_test: bounce_notify_util_tester \
+ msgfile-with-msgid-with-long-line logfile-with-msgid-with-long-line \
+ with-msgid-with-long-line-no-thread.ref \
+ with-msgid-with-long-line-with-thread.ref
+ rm -rf queue main.cf
+ echo 'enable_threaded_bounces = no' >main.cf
+ echo 'queue_directory = queue' >>main.cf
+ echo 'myhostname = mail.example' >>main.cf
+ touch -t 197101010000 main.cf
+ mkdir -p queue/active queue/bounce
+ cp logfile-with-msgid-with-long-line queue/bounce/msgid
+ cp msgfile-with-msgid-with-long-line queue/active/msgid
+ $(SHLIB_ENV) $(VALGRIND) ./bounce_notify_util_tester \
+ -c. bounce active msgid 2>&1 | \
+ sed 's;msgid.[0-9]*/mail.example;msgid.unix-time/mail.example;' \
+ > with-msgid-with-long-line-no-thread.tmp
+ diff with-msgid-with-long-line-no-thread.ref with-msgid-with-long-line-no-thread.tmp
+ rm -f with-msgid-with-long-line-no-thread.tmp
+ :
+ rm -rf queue main.cf
+ echo 'enable_threaded_bounces = yes' >main.cf
+ echo 'queue_directory = queue' >>main.cf
+ echo 'myhostname = mail.example' >>main.cf
+ touch -t 197101010000 main.cf
+ mkdir -p queue/active queue/bounce
+ cp logfile-with-msgid-with-long-line queue/bounce/msgid
+ cp msgfile-with-msgid-with-long-line queue/active/msgid
+ $(SHLIB_ENV) $(VALGRIND) ./bounce_notify_util_tester \
+ -c. bounce active msgid 2>&1 | \
+ sed 's;msgid.[0-9]*/mail.example;msgid.unix-time/mail.example;' \
+ > with-msgid-with-long-line-with-thread.tmp
+ diff with-msgid-with-long-line-with-thread.ref with-msgid-with-long-line-with-thread.tmp
+ rm -f with-msgid-with-long-line-with-thread.tmp
+ rm -rf queue main.cf
+
+with-msgid-with-eoh-event_test: bounce_notify_util_tester \
+ msgfile-with-msgid-with-eoh-event logfile-with-msgid-with-eoh-event \
+ with-msgid-with-eoh-event-no-thread.ref \
+ with-msgid-with-eoh-event-with-thread.ref
+ rm -rf queue main.cf
+ echo 'enable_threaded_bounces = no' >main.cf
+ echo 'queue_directory = queue' >>main.cf
+ echo 'myhostname = mail.example' >>main.cf
+ touch -t 197101010000 main.cf
+ mkdir -p queue/active queue/bounce
+ cp logfile-with-msgid-with-eoh-event queue/bounce/msgid
+ cp msgfile-with-msgid-with-eoh-event queue/active/msgid
+ $(SHLIB_ENV) $(VALGRIND) ./bounce_notify_util_tester \
+ -c. bounce active msgid 2>&1 | \
+ sed 's;msgid.[0-9]*/mail.example;msgid.unix-time/mail.example;' \
+ > with-msgid-with-eoh-event-no-thread.tmp
+ diff with-msgid-with-eoh-event-no-thread.ref with-msgid-with-eoh-event-no-thread.tmp
+ rm -f with-msgid-with-eoh-event-no-thread.tmp
+ :
+ rm -rf queue main.cf
+ echo 'enable_threaded_bounces = yes' >main.cf
+ echo 'queue_directory = queue' >>main.cf
+ echo 'myhostname = mail.example' >>main.cf
+ touch -t 197101010000 main.cf
+ mkdir -p queue/active queue/bounce
+ cp logfile-with-msgid-with-eoh-event queue/bounce/msgid
+ cp msgfile-with-msgid-with-eoh-event queue/active/msgid
+ $(SHLIB_ENV) $(VALGRIND) ./bounce_notify_util_tester \
+ -c. bounce active msgid 2>&1 | \
+ sed 's;msgid.[0-9]*/mail.example;msgid.unix-time/mail.example;' \
+ > with-msgid-with-eoh-event-with-thread.tmp
+ diff with-msgid-with-eoh-event-with-thread.ref with-msgid-with-eoh-event-with-thread.tmp
+ rm -f with-msgid-with-eoh-event-with-thread.tmp
+ rm -rf queue main.cf
+
+with-msgid-no-eoh-event_test: bounce_notify_util_tester \
+ msgfile-with-msgid-no-eoh-event logfile-with-msgid-no-eoh-event \
+ with-msgid-no-eoh-event-no-thread.ref \
+ with-msgid-no-eoh-event-with-thread.ref
+ rm -rf queue main.cf
+ echo 'enable_threaded_bounces = no' >main.cf
+ echo 'queue_directory = queue' >>main.cf
+ echo 'myhostname = mail.example' >>main.cf
+ touch -t 197101010000 main.cf
+ mkdir -p queue/active queue/bounce
+ cp logfile-with-msgid-no-eoh-event queue/bounce/msgid
+ cp msgfile-with-msgid-no-eoh-event queue/active/msgid
+ $(SHLIB_ENV) $(VALGRIND) ./bounce_notify_util_tester \
+ -c. bounce active msgid 2>&1 | \
+ sed 's;msgid.[0-9]*/mail.example;msgid.unix-time/mail.example;' \
+ > with-msgid-no-eoh-event-no-thread.tmp
+ diff with-msgid-no-eoh-event-no-thread.ref with-msgid-no-eoh-event-no-thread.tmp
+ rm -f with-msgid-no-eoh-event-no-thread.tmp
+ :
+ rm -rf queue main.cf
+ echo 'enable_threaded_bounces = yes' >main.cf
+ echo 'queue_directory = queue' >>main.cf
+ echo 'myhostname = mail.example' >>main.cf
+ touch -t 197101010000 main.cf
+ mkdir -p queue/active queue/bounce
+ cp logfile-with-msgid-no-eoh-event queue/bounce/msgid
+ cp msgfile-with-msgid-no-eoh-event queue/active/msgid
+ $(SHLIB_ENV) $(VALGRIND) ./bounce_notify_util_tester \
+ -c. bounce active msgid 2>&1 | \
+ sed 's;msgid.[0-9]*/mail.example;msgid.unix-time/mail.example;' \
+ > with-msgid-no-eoh-event-with-thread.tmp
+ diff with-msgid-no-eoh-event-with-thread.ref with-msgid-no-eoh-event-with-thread.tmp
+ rm -f with-msgid-no-eoh-event-with-thread.tmp
+ rm -rf queue main.cf
+
+no-msgid-with-eoh-event_test: bounce_notify_util_tester \
+ msgfile-no-msgid-with-eoh-event logfile-no-msgid-with-eoh-event \
+ no-msgid-with-eoh-event-no-thread.ref \
+ no-msgid-with-eoh-event-with-thread.ref
+ rm -rf queue main.cf
+ echo 'enable_threaded_bounces = no' >main.cf
+ echo 'queue_directory = queue' >>main.cf
+ echo 'myhostname = mail.example' >>main.cf
+ touch -t 197101010000 main.cf
+ mkdir -p queue/active queue/bounce
+ cp logfile-no-msgid-with-eoh-event queue/bounce/msgid
+ cp msgfile-no-msgid-with-eoh-event queue/active/msgid
+ $(SHLIB_ENV) $(VALGRIND) ./bounce_notify_util_tester \
+ -c. bounce active msgid 2>&1 | \
+ sed 's;msgid.[0-9]*/mail.example;msgid.unix-time/mail.example;' \
+ > no-msgid-with-eoh-event-no-thread.tmp
+ diff no-msgid-with-eoh-event-no-thread.ref no-msgid-with-eoh-event-no-thread.tmp
+ rm -f no-msgid-with-eoh-event-no-thread.tmp
+ :
+ rm -rf queue main.cf
+ echo 'enable_threaded_bounces = yes' >main.cf
+ echo 'queue_directory = queue' >>main.cf
+ echo 'myhostname = mail.example' >>main.cf
+ touch -t 197101010000 main.cf
+ mkdir -p queue/active queue/bounce
+ cp logfile-no-msgid-with-eoh-event queue/bounce/msgid
+ cp msgfile-no-msgid-with-eoh-event queue/active/msgid
+ $(SHLIB_ENV) $(VALGRIND) ./bounce_notify_util_tester \
+ -c. bounce active msgid 2>&1 | \
+ sed 's;msgid.[0-9]*/mail.example;msgid.unix-time/mail.example;' \
+ > no-msgid-with-eoh-event-with-thread.tmp
+ diff no-msgid-with-eoh-event-with-thread.ref no-msgid-with-eoh-event-with-thread.tmp
+ rm -f no-msgid-with-eoh-event-with-thread.tmp
+ rm -rf queue main.cf
+
+no-msgid-no-eoh-event_test: bounce_notify_util_tester \
+ msgfile-no-msgid-no-eoh-event logfile-no-msgid-no-eoh-event \
+ no-msgid-no-eoh-event-no-thread.ref \
+ no-msgid-no-eoh-event-with-thread.ref
+ rm -rf queue main.cf
+ echo 'enable_threaded_bounces = no' >main.cf
+ echo 'queue_directory = queue' >>main.cf
+ echo 'myhostname = mail.example' >>main.cf
+ touch -t 197101010000 main.cf
+ mkdir -p queue/active queue/bounce
+ cp logfile-no-msgid-no-eoh-event queue/bounce/msgid
+ cp msgfile-no-msgid-no-eoh-event queue/active/msgid
+ $(SHLIB_ENV) $(VALGRIND) ./bounce_notify_util_tester \
+ -c. bounce active msgid 2>&1 | \
+ sed 's;msgid.[0-9]*/mail.example;msgid.unix-time/mail.example;' \
+ > no-msgid-no-eoh-event-no-thread.tmp
+ diff no-msgid-no-eoh-event-no-thread.ref no-msgid-no-eoh-event-no-thread.tmp
+ rm -f no-msgid-no-eoh-event-no-thread.tmp
+ :
+ rm -rf queue main.cf
+ echo 'enable_threaded_bounces = yes' >main.cf
+ echo 'queue_directory = queue' >>main.cf
+ echo 'myhostname = mail.example' >>main.cf
+ touch -t 197101010000 main.cf
+ mkdir -p queue/active queue/bounce
+ cp logfile-no-msgid-no-eoh-event queue/bounce/msgid
+ cp msgfile-no-msgid-no-eoh-event queue/active/msgid
+ $(SHLIB_ENV) $(VALGRIND) ./bounce_notify_util_tester \
+ -c. bounce active msgid 2>&1 | \
+ sed 's;msgid.[0-9]*/mail.example;msgid.unix-time/mail.example;' \
+ > no-msgid-no-eoh-event-with-thread.tmp
+ diff no-msgid-no-eoh-event-with-thread.ref no-msgid-no-eoh-event-with-thread.tmp
+ rm -f no-msgid-no-eoh-event-with-thread.tmp
+ rm -rf queue main.cf
+
+with-msgid-with-filter_test: bounce_notify_util_tester \
+ msgfile-with-msgid-with-filter logfile-with-msgid-with-filter \
+ with-msgid-with-filter-no-thread.ref \
+ with-msgid-with-filter-with-thread.ref
+ rm -rf queue main.cf
+ echo 'enable_threaded_bounces = no' >main.cf
+ echo 'queue_directory = queue' >>main.cf
+ echo 'myhostname = mail.example' >>main.cf
+ touch -t 197101010000 main.cf
+ mkdir -p queue/active queue/bounce
+ cp logfile-with-msgid-with-filter queue/bounce/msgid
+ cp msgfile-with-msgid-with-filter queue/active/msgid
+ $(SHLIB_ENV) $(VALGRIND) ./bounce_notify_util_tester \
+ -c. bounce active msgid 2>&1 | \
+ sed 's;msgid.[0-9]*/mail.example;msgid.unix-time/mail.example;' \
+ > with-msgid-with-filter-no-thread.tmp
+ diff with-msgid-with-filter-no-thread.ref with-msgid-with-filter-no-thread.tmp
+ rm -f with-msgid-with-filter-no-thread.tmp
+ :
+ rm -rf queue main.cf
+ echo 'enable_threaded_bounces = yes' >main.cf
+ echo 'queue_directory = queue' >>main.cf
+ echo 'myhostname = mail.example' >>main.cf
+ touch -t 197101010000 main.cf
+ mkdir -p queue/active queue/bounce
+ cp logfile-with-msgid-with-filter queue/bounce/msgid
+ cp msgfile-with-msgid-with-filter queue/active/msgid
+ $(SHLIB_ENV) $(VALGRIND) ./bounce_notify_util_tester \
+ -c. bounce active msgid 2>&1 | \
+ sed 's;msgid.[0-9]*/mail.example;msgid.unix-time/mail.example;' \
+ > with-msgid-with-filter-with-thread.tmp
+ diff with-msgid-with-filter-with-thread.ref with-msgid-with-filter-with-thread.tmp
+ rm -f with-msgid-with-filter-with-thread.tmp
+ rm -rf queue main.cf
depend: $(MAKES)
(sed '1,/^# do not edit/!d' Makefile.in; \
bounce_notify_util.o: ../../include/dsn_buf.h
bounce_notify_util.o: ../../include/dsn_mask.h
bounce_notify_util.o: ../../include/events.h
+bounce_notify_util.o: ../../include/header_opts.h
bounce_notify_util.o: ../../include/htable.h
bounce_notify_util.o: ../../include/int_filt.h
bounce_notify_util.o: ../../include/iostuff.h
bounce_notify_util.o: bounce_notify_util.c
bounce_notify_util.o: bounce_service.h
bounce_notify_util.o: bounce_template.h
+bounce_notify_util_tester.o: ../../include/attr.h
+bounce_notify_util_tester.o: ../../include/bounce_log.h
+bounce_notify_util_tester.o: ../../include/check_arg.h
+bounce_notify_util_tester.o: ../../include/dsn.h
+bounce_notify_util_tester.o: ../../include/dsn_buf.h
+bounce_notify_util_tester.o: ../../include/dsn_mask.h
+bounce_notify_util_tester.o: ../../include/htable.h
+bounce_notify_util_tester.o: ../../include/mail_conf.h
+bounce_notify_util_tester.o: ../../include/mail_params.h
+bounce_notify_util_tester.o: ../../include/msg.h
+bounce_notify_util_tester.o: ../../include/mymalloc.h
+bounce_notify_util_tester.o: ../../include/nvtable.h
+bounce_notify_util_tester.o: ../../include/rcpt_buf.h
+bounce_notify_util_tester.o: ../../include/rec_type.h
+bounce_notify_util_tester.o: ../../include/recipient_list.h
+bounce_notify_util_tester.o: ../../include/record.h
+bounce_notify_util_tester.o: ../../include/sys_defs.h
+bounce_notify_util_tester.o: ../../include/test_main.h
+bounce_notify_util_tester.o: ../../include/vbuf.h
+bounce_notify_util_tester.o: ../../include/vstream.h
+bounce_notify_util_tester.o: ../../include/vstring.h
+bounce_notify_util_tester.o: bounce_notify_util_tester.c
+bounce_notify_util_tester.o: bounce_service.h
+bounce_notify_util_tester.o: bounce_template.h
bounce_notify_verp.o: ../../include/attr.h
bounce_notify_verp.o: ../../include/bounce.h
bounce_notify_verp.o: ../../include/bounce_log.h
/* Available in Postfix 3.3 and later:
/* .IP "\fBservice_name (read-only)\fR"
/* The master.cf service name of a Postfix daemon process.
+/* .PP
+/* Available in Postfix 3.6 and later:
+/* .IP "\fBenable_threaded_bounces (no)\fR"
+/* Enable non-delivery notifications (bounce messages) that link
+/* to the original message by including a References: and In-Reply_to:
+/* header with the original Message-ID value.
/* FILES
/* /var/spool/postfix/bounce/* non-delivery records
/* /var/spool/postfix/defer/* non-delivery records
char *var_2bounce_rcpt;
char *var_delay_rcpt;
char *var_bounce_tmpl;
+bool var_threaded_bounce;
/*
* We're single threaded, so we can avoid some memory allocation overhead.
VAR_BOUNCE_TMPL, DEF_BOUNCE_TMPL, &var_bounce_tmpl, 0, 0,
0,
};
+ static const CONFIG_NBOOL_TABLE nbool_table[] = {
+ VAR_THREADED_BOUNCE, DEF_THREADED_BOUNCE, &var_threaded_bounce,
+ 0,
+ };
/*
* Fingerprint executables and core dumps.
CA_MAIL_SERVER_INT_TABLE(int_table),
CA_MAIL_SERVER_STR_TABLE(str_table),
CA_MAIL_SERVER_TIME_TABLE(time_table),
+ CA_MAIL_SERVER_NBOOL_TABLE(nbool_table),
CA_MAIL_SERVER_PRE_INIT(pre_jail_init),
CA_MAIL_SERVER_POST_INIT(post_jail_init),
CA_MAIL_SERVER_UNLIMITED,
#include <deliver_completed.h>
#include <dsn_mask.h>
#include <smtputf8.h>
+#include <header_opts.h>
/* Application-specific. */
#include "bounce_service.h"
#define STR vstring_str
+#define LEN VSTRING_LEN
/* bounce_mail_alloc - initialize */
{
BOUNCE_INFO *bounce_info;
int rec_type;
+ int prev_type;
+ int all_headers_seen = 0;
+ int skip_message_segment = 0;
+ int in_envelope = 1;
/*
* Bundle up a bunch of parameters and initialize information that will
bounce_info->arrival_time = 0;
bounce_info->orig_offs = 0;
bounce_info->message_size = 0;
+ bounce_info->orig_msgid = vstring_alloc(100);
bounce_info->rcpt_buf = rcpt_buf;
bounce_info->dsn_buf = dsn_buf;
bounce_info->log_handle = log_handle;
DELIVER_LOCK_MODE) < 0)
msg_fatal("cannot get shared lock on %s: %m",
VSTREAM_PATH(bounce_info->orig_fp));
- while ((rec_type = rec_get(bounce_info->orig_fp,
- bounce_info->buf, 0)) > 0) {
+ for (prev_type = 0;
+ (rec_type = rec_get(bounce_info->orig_fp, bounce_info->buf, 0)) > 0;
+ prev_type = rec_type) {
/*
* Postfix version dependent: data offset in SIZE record.
msg_warn("%s: no sender before message content record",
bounce_info->queue_id);
bounce_info->orig_offs = vstream_ftell(bounce_info->orig_fp);
- break;
+ if (var_threaded_bounce == 0)
+ skip_message_segment = 1;
+ else
+ in_envelope = 0;
+ }
+
+ /*
+ * Extract Message-ID for threaded bounces.
+ */
+ else if (in_envelope == 0
+ && (rec_type == REC_TYPE_NORM || rec_type == REC_TYPE_CONT)) {
+ const HEADER_OPTS *hdr;
+ char *cp;
+
+ /*
+ * Skip records that we cannot use. Degrade if we could not
+ * skip over the message content.
+ */
+ if (var_threaded_bounce == 0 || all_headers_seen
+ || prev_type == REC_TYPE_CONT) {
+ /* void */ ;
+ }
+
+ /*
+ * Extract message-id header value.
+ */
+ else if (is_header(STR(bounce_info->buf))) {
+ if ((hdr = header_opts_find(
+ vstring_str(bounce_info->buf))) != 0
+ && hdr->type == HDR_MESSAGE_ID) {
+ vstring_truncate(bounce_info->buf,
+ trimblanks(STR(bounce_info->buf),
+ LEN(bounce_info->buf))
+ - STR(bounce_info->buf));
+ cp = STR(bounce_info->buf) + strlen(hdr->name) + 1;
+ while (ISSPACE(*cp))
+ cp++;
+ if (*cp == '<' && vstring_end(bounce_info->buf)[-1] == '>')
+ vstring_strcpy(bounce_info->orig_msgid, cp);
+ else
+ msg_warn("%s: ignoring malformed Message-ID",
+ bounce_info->queue_id);
+ }
+ }
+
+ /*
+ * Skip remainder of multiline header.
+ */
+ else if (ISSPACE(*STR(bounce_info->buf))) {
+ /* void */ ;
+ }
+
+ /*
+ * Start of body.
+ */
+ else {
+ all_headers_seen = 1;
+ skip_message_segment = 1;
+ }
}
+
+ /*
+ * In case we ever want to process records from the extracted
+ * segment, and in case there was no "start of body" event.
+ */
+ else if (rec_type == REC_TYPE_XTRA) {
+ if (VSTRING_LEN(bounce_info->orig_msgid) == 0)
+ if (var_threaded_bounce)
+ all_headers_seen = 1;
+ in_envelope = 1;
+ }
+
+ /*
+ * Are we done yet?
+ */
if (bounce_info->orig_offs > 0
&& bounce_info->arrival_time > 0
- && VSTRING_LEN(bounce_info->sender) > 0)
+ && VSTRING_LEN(bounce_info->sender) > 0
+ && (var_threaded_bounce == 0 || all_headers_seen
+ || VSTRING_LEN(bounce_info->orig_msgid) > 0)) {
break;
+ }
+
+ /*
+ * Skip over (the remainder of) the message segment. If that
+ * fails, degrade.
+ */
+ if (skip_message_segment) {
+ if (vstream_fseek(bounce_info->orig_fp,
+ bounce_info->orig_offs +
+ bounce_info->message_size,
+ SEEK_SET) < 0)
+ /* void */ ;
+ skip_message_segment = 0;
+ }
}
}
return (bounce_info);
if (bounce_log_close(bounce_info->log_handle))
msg_warn("%s: read bounce log %s: %m",
bounce_info->queue_id, bounce_info->queue_id);
+ vstring_free(bounce_info->orig_msgid);
rcpb_free(bounce_info->rcpt_buf);
dsb_free(bounce_info->dsn_buf);
}
STR(quote_822_local(bounce_info->buf, dest)),
postmaster_copy);
+ /*
+ * References and Reply-To header that references the original message-id
+ * for better threading in MUAs.
+ */
+ if (VSTRING_LEN(bounce_info->orig_msgid) > 0) {
+ post_mail_fprintf(bounce, "References: %s", STR(bounce_info->orig_msgid));
+ post_mail_fprintf(bounce, "In-Reply-To: %s", STR(bounce_info->orig_msgid));
+ }
+
/*
* Auto-Submitted header, as per RFC 3834.
*/
--- /dev/null
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+ /*
+ * Utility library.
+ */
+#include <msg.h>
+#include <vstream.h>
+#include <vstring.h>
+
+ /*
+ * Global library.
+ */
+#include <dsn_mask.h>
+#include <mail_params.h>
+#include <record.h>
+#include <rec_type.h>
+
+ /*
+ * Bounce service.
+ */
+#include <bounce_service.h>
+#include <bounce_template.h>
+
+ /*
+ * Testing library.
+ */
+#include <test_main.h>
+
+#define TEST_ENCODING "7bit"
+#define NO_SMTPUTF8 (0)
+#define TEST_DSN_ENVID "TEST-ENVID"
+#define TEST_RECIPIENT "test-recipient"
+
+#define STR(x) vstring_str(x)
+#define LEN(x) VSTRING_LEN(x)
+
+/* test_driver - test driver */
+
+static void test_driver(int argc, char **argv)
+{
+ BOUNCE_TEMPLATES *bounce_templates;
+ BOUNCE_INFO *bounce_info;
+ VSTRING *message_buf;
+ VSTREAM *message_stream;
+ VSTRING *rec_buf;
+ int rec_type;
+
+ /*
+ * Sanity checks.
+ */
+ if (argc != 4)
+ msg_fatal("usage: %s [options] service queue_name queue_id", argv[0]);
+
+ if (chdir(var_queue_dir) < 0)
+ msg_fatal("chdir %s: %m", var_queue_dir);
+
+ /*
+ * Write one message to VSTRING.
+ */
+ message_buf = vstring_alloc(100);
+ if ((message_stream = vstream_memopen(message_buf, O_WRONLY)) == 0)
+ msg_fatal("vstream_memopen O_WRONLY: %m");
+ bounce_templates = bounce_templates_create();
+ bounce_info = bounce_mail_init(argv[1], argv[2], argv[3],
+ TEST_ENCODING, NO_SMTPUTF8, TEST_DSN_ENVID,
+ bounce_templates->failure);
+ if (bounce_header(message_stream, bounce_info, TEST_RECIPIENT,
+ NO_POSTMASTER_COPY) < 0)
+ msg_fatal("bounce_header: %m");
+ if (bounce_diagnostic_log(message_stream, bounce_info,
+ DSN_NOTIFY_OVERRIDE) <= 0)
+ msg_fatal("bounce_diagnostic_log: %m");
+ if (bounce_header_dsn(message_stream, bounce_info) != 0)
+ msg_fatal("bounce_header_dsn: %m");
+ if (bounce_diagnostic_dsn(message_stream, bounce_info,
+ DSN_NOTIFY_OVERRIDE) <= 0)
+ msg_fatal("bounce_diagnostic_dsn: %m");
+ bounce_original(message_stream, bounce_info, DSN_RET_FULL);
+ if (vstream_fclose(message_stream) != 0)
+ msg_fatal("vstream_fclose: %m");
+ bounce_mail_free(bounce_info);
+
+ /*
+ * Render the bounce message in human-readable form.
+ */
+ if ((message_stream = vstream_memopen(message_buf, O_RDONLY)) == 0)
+ msg_fatal("vstream_memopen O_RDONLY: %m");
+ rec_buf = vstring_alloc(100);
+ while ((rec_type = rec_get(message_stream, rec_buf, 0)) > 0) {
+ switch (rec_type) {
+ case REC_TYPE_CONT:
+ vstream_printf("%.*s", (int) LEN(rec_buf), STR(rec_buf));
+ break;
+ case REC_TYPE_NORM:
+ vstream_printf("%.*s\n", (int) LEN(rec_buf), STR(rec_buf));
+ break;
+ default:
+ msg_panic("unexpected message record type %d", rec_type);
+ }
+ vstream_fflush(VSTREAM_OUT);
+ }
+ if (vstream_fclose(message_stream) != 0)
+ msg_fatal("vstream_fclose: %m");
+ vstring_free(rec_buf);
+
+ /*
+ * Clean up.
+ */
+ exit(0);
+}
+
+int var_bounce_limit;
+int var_max_queue_time;
+int var_delay_warn_time;
+char *var_notify_classes;
+char *var_bounce_rcpt;
+char *var_2bounce_rcpt;
+char *var_delay_rcpt;
+char *var_bounce_tmpl;
+bool var_threaded_bounce;
+
+int main(int argc, char **argv)
+{
+ static const CONFIG_INT_TABLE int_table[] = {
+ VAR_BOUNCE_LIMIT, DEF_BOUNCE_LIMIT, &var_bounce_limit, 1, 0,
+ 0,
+ };
+ static const CONFIG_TIME_TABLE time_table[] = {
+ VAR_MAX_QUEUE_TIME, DEF_MAX_QUEUE_TIME, &var_max_queue_time, 0, 8640000,
+ VAR_DELAY_WARN_TIME, DEF_DELAY_WARN_TIME, &var_delay_warn_time, 0, 0,
+ 0,
+ };
+ static const CONFIG_STR_TABLE str_table[] = {
+ VAR_NOTIFY_CLASSES, DEF_NOTIFY_CLASSES, &var_notify_classes, 0, 0,
+ VAR_BOUNCE_RCPT, DEF_BOUNCE_RCPT, &var_bounce_rcpt, 1, 0,
+ VAR_2BOUNCE_RCPT, DEF_2BOUNCE_RCPT, &var_2bounce_rcpt, 1, 0,
+ VAR_DELAY_RCPT, DEF_DELAY_RCPT, &var_delay_rcpt, 1, 0,
+ VAR_BOUNCE_TMPL, DEF_BOUNCE_TMPL, &var_bounce_tmpl, 0, 0,
+ 0,
+ };
+ static const CONFIG_NBOOL_TABLE nbool_table[] = {
+ VAR_THREADED_BOUNCE, DEF_THREADED_BOUNCE, &var_threaded_bounce,
+ 0,
+ };
+
+ test_main(argc, argv, test_driver,
+ CA_TEST_MAIN_INT_TABLE(int_table),
+ CA_TEST_MAIN_STR_TABLE(str_table),
+ CA_TEST_MAIN_TIME_TABLE(time_table),
+ CA_TEST_MAIN_NBOOL_TABLE(nbool_table),
+ 0);
+
+ exit(0);
+}
long orig_offs; /* start of content */
time_t arrival_time; /* time of arrival */
long message_size; /* size of content */
+ VSTRING *orig_msgid; /* original message-id */
RCPT_BUF *rcpt_buf; /* recipient info */
DSN_BUF *dsn_buf; /* delivery status info */
BOUNCE_LOG *log_handle; /* open logfile */
--- /dev/null
+
+recipient = rcpt-address
+original_recipient = rcpt-orig_addr
+offset = 272
+notify_flags = rcpt-dsn_notify
+status = dsn-status
+action = dsn-action
+diag_type = dsn-dtype
+diag_text = dsn-dtext
+mta_type = dsn-mtype
+mta_mname = dsn-mname
+reason = dsn-reason
+
--- /dev/null
+
+recipient = rcpt-address
+original_recipient = rcpt-orig_addr
+offset = 271
+notify_flags = rcpt-dsn_notify
+status = dsn-status
+action = dsn-action
+diag_type = dsn-dtype
+diag_text = dsn-dtext
+mta_type = dsn-mtype
+mta_mname = dsn-mname
+reason = dsn-reason
+
--- /dev/null
+
+recipient = rcpt-address
+original_recipient = rcpt-orig_addr
+offset = 271
+notify_flags = rcpt-dsn_notify
+status = dsn-status
+action = dsn-action
+diag_type = dsn-dtype
+diag_text = dsn-dtext
+mta_type = dsn-mtype
+mta_mname = dsn-mname
+reason = dsn-reason
+
--- /dev/null
+
+recipient = rcpt-address
+original_recipient = rcpt-orig_addr
+offset = 271
+notify_flags = rcpt-dsn_notify
+status = dsn-status
+action = dsn-action
+diag_type = dsn-dtype
+diag_text = dsn-dtext
+mta_type = dsn-mtype
+mta_mname = dsn-mname
+reason = dsn-reason
+
--- /dev/null
+
+recipient = rcpt-address
+original_recipient = rcpt-orig_addr
+offset = 291
+notify_flags = rcpt-dsn_notify
+status = dsn-status
+action = dsn-action
+diag_type = dsn-dtype
+diag_text = dsn-dtext
+mta_type = dsn-mtype
+mta_mname = dsn-mname
+reason = dsn-reason
+
--- /dev/null
+
+recipient = rcpt-address
+original_recipient = rcpt-orig_addr
+offset = 271
+notify_flags = rcpt-dsn_notify
+status = dsn-status
+action = dsn-action
+diag_type = dsn-dtype
+diag_text = dsn-dtext
+mta_type = dsn-mtype
+mta_mname = dsn-mname
+reason = dsn-reason
+
--- /dev/null
+From: MAILER-DAEMON (Mail Delivery System)
+Subject: Undelivered Mail Returned to Sender
+To: test-recipient
+Auto-Submitted: auto-replied
+MIME-Version: 1.0
+Content-Type: multipart/report; report-type=delivery-status;
+ boundary="msgid.unix-time/mail.example"
+Content-Transfer-Encoding: 7bit
+
+This is a MIME-encapsulated message.
+
+--msgid.unix-time/mail.example
+Content-Description: Notification
+Content-Type: text/plain; charset=us-ascii
+
+
+<rcpt-address> (expanded from <rcpt-orig_addr>): dsn-reason
+
+--msgid.unix-time/mail.example
+Content-Description: Delivery report
+Content-Type: message/delivery-status
+
+Reporting-MTA: dns; mail.example
+Original-Envelope-Id: TEST-ENVID
+X-Postfix-Queue-ID: msgid
+X-Postfix-Sender: rfc822; sender@sender.example
+Arrival-Date: Sun, 29 Nov 2020 19:04:29 -0500 (EST)
+
+Final-Recipient: rfc822; rcpt-address
+Original-Recipient: rfc822; rcpt-orig_addr
+Action: failed
+Status: dsn-status
+Remote-MTA: dsn-mtype; dsn-mname
+Diagnostic-Code: dsn-dtype; dsn-dtext
+
+--msgid.unix-time/mail.example
+Content-Description: Undelivered Message
+Content-Type: message/rfc822
+
+Return-Path: <sender@sender.example>
+Received: by wzv.porcupine.org (Postfix, from userid 0)
+ id 4CklpP1JjKz4w4Z; Mon, 30 Nov 2020 00:04:29 +0000 (UTC)
+From: <sender@sender.example>
+To: <recipient@recipient.example>
+Subject: no-msgid-no-eoh-event
+
+--msgid.unix-time/mail.example--
--- /dev/null
+From: MAILER-DAEMON (Mail Delivery System)
+Subject: Undelivered Mail Returned to Sender
+To: test-recipient
+Auto-Submitted: auto-replied
+MIME-Version: 1.0
+Content-Type: multipart/report; report-type=delivery-status;
+ boundary="msgid.unix-time/mail.example"
+Content-Transfer-Encoding: 7bit
+
+This is a MIME-encapsulated message.
+
+--msgid.unix-time/mail.example
+Content-Description: Notification
+Content-Type: text/plain; charset=us-ascii
+
+
+<rcpt-address> (expanded from <rcpt-orig_addr>): dsn-reason
+
+--msgid.unix-time/mail.example
+Content-Description: Delivery report
+Content-Type: message/delivery-status
+
+Reporting-MTA: dns; mail.example
+Original-Envelope-Id: TEST-ENVID
+X-Postfix-Queue-ID: msgid
+X-Postfix-Sender: rfc822; sender@sender.example
+Arrival-Date: Sun, 29 Nov 2020 19:04:29 -0500 (EST)
+
+Final-Recipient: rfc822; rcpt-address
+Original-Recipient: rfc822; rcpt-orig_addr
+Action: failed
+Status: dsn-status
+Remote-MTA: dsn-mtype; dsn-mname
+Diagnostic-Code: dsn-dtype; dsn-dtext
+
+--msgid.unix-time/mail.example
+Content-Description: Undelivered Message
+Content-Type: message/rfc822
+
+Return-Path: <sender@sender.example>
+Received: by wzv.porcupine.org (Postfix, from userid 0)
+ id 4CklpP1JjKz4w4Z; Mon, 30 Nov 2020 00:04:29 +0000 (UTC)
+From: <sender@sender.example>
+To: <recipient@recipient.example>
+Subject: no-msgid-no-eoh-event
+
+--msgid.unix-time/mail.example--
--- /dev/null
+From: MAILER-DAEMON (Mail Delivery System)
+Subject: Undelivered Mail Returned to Sender
+To: test-recipient
+Auto-Submitted: auto-replied
+MIME-Version: 1.0
+Content-Type: multipart/report; report-type=delivery-status;
+ boundary="msgid.unix-time/mail.example"
+Content-Transfer-Encoding: 7bit
+
+This is a MIME-encapsulated message.
+
+--msgid.unix-time/mail.example
+Content-Description: Notification
+Content-Type: text/plain; charset=us-ascii
+
+
+<rcpt-address> (expanded from <rcpt-orig_addr>): dsn-reason
+
+--msgid.unix-time/mail.example
+Content-Description: Delivery report
+Content-Type: message/delivery-status
+
+Reporting-MTA: dns; mail.example
+Original-Envelope-Id: TEST-ENVID
+X-Postfix-Queue-ID: msgid
+X-Postfix-Sender: rfc822; sender@sender.example
+Arrival-Date: Sun, 29 Nov 2020 19:11:52 -0500 (EST)
+
+Final-Recipient: rfc822; rcpt-address
+Original-Recipient: rfc822; rcpt-orig_addr
+Action: failed
+Status: dsn-status
+Remote-MTA: dsn-mtype; dsn-mname
+Diagnostic-Code: dsn-dtype; dsn-dtext
+
+--msgid.unix-time/mail.example
+Content-Description: Undelivered Message
+Content-Type: message/rfc822
+
+Return-Path: <sender@sender.example>
+Received: by wzv.porcupine.org (Postfix, from userid 0)
+ id 4Cklyw0HDKz4w4Z; Mon, 30 Nov 2020 00:11:52 +0000 (UTC)
+From: <sender@sender.example>
+To: <recipient@recipient.example>
+Subject: no-msgid-with-eoh-event
+
+body text
+
+--msgid.unix-time/mail.example--
--- /dev/null
+From: MAILER-DAEMON (Mail Delivery System)
+Subject: Undelivered Mail Returned to Sender
+To: test-recipient
+Auto-Submitted: auto-replied
+MIME-Version: 1.0
+Content-Type: multipart/report; report-type=delivery-status;
+ boundary="msgid.unix-time/mail.example"
+Content-Transfer-Encoding: 7bit
+
+This is a MIME-encapsulated message.
+
+--msgid.unix-time/mail.example
+Content-Description: Notification
+Content-Type: text/plain; charset=us-ascii
+
+
+<rcpt-address> (expanded from <rcpt-orig_addr>): dsn-reason
+
+--msgid.unix-time/mail.example
+Content-Description: Delivery report
+Content-Type: message/delivery-status
+
+Reporting-MTA: dns; mail.example
+Original-Envelope-Id: TEST-ENVID
+X-Postfix-Queue-ID: msgid
+X-Postfix-Sender: rfc822; sender@sender.example
+Arrival-Date: Sun, 29 Nov 2020 19:11:52 -0500 (EST)
+
+Final-Recipient: rfc822; rcpt-address
+Original-Recipient: rfc822; rcpt-orig_addr
+Action: failed
+Status: dsn-status
+Remote-MTA: dsn-mtype; dsn-mname
+Diagnostic-Code: dsn-dtype; dsn-dtext
+
+--msgid.unix-time/mail.example
+Content-Description: Undelivered Message
+Content-Type: message/rfc822
+
+Return-Path: <sender@sender.example>
+Received: by wzv.porcupine.org (Postfix, from userid 0)
+ id 4Cklyw0HDKz4w4Z; Mon, 30 Nov 2020 00:11:52 +0000 (UTC)
+From: <sender@sender.example>
+To: <recipient@recipient.example>
+Subject: no-msgid-with-eoh-event
+
+body text
+
+--msgid.unix-time/mail.example--
--- /dev/null
+From: MAILER-DAEMON (Mail Delivery System)
+Subject: Undelivered Mail Returned to Sender
+To: test-recipient
+Auto-Submitted: auto-replied
+MIME-Version: 1.0
+Content-Type: multipart/report; report-type=delivery-status;
+ boundary="msgid.unix-time/mail.example"
+Content-Transfer-Encoding: 7bit
+
+This is a MIME-encapsulated message.
+
+--msgid.unix-time/mail.example
+Content-Description: Notification
+Content-Type: text/plain; charset=us-ascii
+
+
+<rcpt-address> (expanded from <rcpt-orig_addr>): dsn-reason
+
+--msgid.unix-time/mail.example
+Content-Description: Delivery report
+Content-Type: message/delivery-status
+
+Reporting-MTA: dns; mail.example
+Original-Envelope-Id: TEST-ENVID
+X-Postfix-Queue-ID: msgid
+X-Postfix-Sender: rfc822; sender@sender.example
+Arrival-Date: Sun, 29 Nov 2020 10:30:41 -0500 (EST)
+
+Final-Recipient: rfc822; rcpt-address
+Original-Recipient: rfc822; rcpt-orig_addr
+Action: failed
+Status: dsn-status
+Remote-MTA: dsn-mtype; dsn-mname
+Diagnostic-Code: dsn-dtype; dsn-dtext
+
+--msgid.unix-time/mail.example
+Content-Description: Undelivered Message
+Content-Type: message/rfc822
+
+Return-Path: <sender@sender.example>
+Received: by wzv.porcupine.org (Postfix, from userid 0)
+ id 4CkXPY0myNz4w4g; Sun, 29 Nov 2020 15:30:41 +0000 (UTC)
+From: <sender@sender.example>
+To: <recipient@recipient.example>
+Message-Id: <12345@mta-name.example>
+Subject: with-msgid-no-eoh-event
+Date: Sun, 29 Nov 2020 15:30:41 +0000 (UTC)
+
+--msgid.unix-time/mail.example--
--- /dev/null
+From: MAILER-DAEMON (Mail Delivery System)
+Subject: Undelivered Mail Returned to Sender
+To: test-recipient
+References: <12345@mta-name.example>
+In-Reply-To: <12345@mta-name.example>
+Auto-Submitted: auto-replied
+MIME-Version: 1.0
+Content-Type: multipart/report; report-type=delivery-status;
+ boundary="msgid.unix-time/mail.example"
+Content-Transfer-Encoding: 7bit
+
+This is a MIME-encapsulated message.
+
+--msgid.unix-time/mail.example
+Content-Description: Notification
+Content-Type: text/plain; charset=us-ascii
+
+
+<rcpt-address> (expanded from <rcpt-orig_addr>): dsn-reason
+
+--msgid.unix-time/mail.example
+Content-Description: Delivery report
+Content-Type: message/delivery-status
+
+Reporting-MTA: dns; mail.example
+Original-Envelope-Id: TEST-ENVID
+X-Postfix-Queue-ID: msgid
+X-Postfix-Sender: rfc822; sender@sender.example
+Arrival-Date: Sun, 29 Nov 2020 10:30:41 -0500 (EST)
+
+Final-Recipient: rfc822; rcpt-address
+Original-Recipient: rfc822; rcpt-orig_addr
+Action: failed
+Status: dsn-status
+Remote-MTA: dsn-mtype; dsn-mname
+Diagnostic-Code: dsn-dtype; dsn-dtext
+
+--msgid.unix-time/mail.example
+Content-Description: Undelivered Message
+Content-Type: message/rfc822
+
+Return-Path: <sender@sender.example>
+Received: by wzv.porcupine.org (Postfix, from userid 0)
+ id 4CkXPY0myNz4w4g; Sun, 29 Nov 2020 15:30:41 +0000 (UTC)
+From: <sender@sender.example>
+To: <recipient@recipient.example>
+Message-Id: <12345@mta-name.example>
+Subject: with-msgid-no-eoh-event
+Date: Sun, 29 Nov 2020 15:30:41 +0000 (UTC)
+
+--msgid.unix-time/mail.example--
--- /dev/null
+From: MAILER-DAEMON (Mail Delivery System)
+Subject: Undelivered Mail Returned to Sender
+To: test-recipient
+Auto-Submitted: auto-replied
+MIME-Version: 1.0
+Content-Type: multipart/report; report-type=delivery-status;
+ boundary="msgid.unix-time/mail.example"
+Content-Transfer-Encoding: 7bit
+
+This is a MIME-encapsulated message.
+
+--msgid.unix-time/mail.example
+Content-Description: Notification
+Content-Type: text/plain; charset=us-ascii
+
+
+<rcpt-address> (expanded from <rcpt-orig_addr>): dsn-reason
+
+--msgid.unix-time/mail.example
+Content-Description: Delivery report
+Content-Type: message/delivery-status
+
+Reporting-MTA: dns; mail.example
+Original-Envelope-Id: TEST-ENVID
+X-Postfix-Queue-ID: msgid
+X-Postfix-Sender: rfc822; sender@sender.example
+Arrival-Date: Sun, 29 Nov 2020 10:30:41 -0500 (EST)
+
+Final-Recipient: rfc822; rcpt-address
+Original-Recipient: rfc822; rcpt-orig_addr
+Action: failed
+Status: dsn-status
+Remote-MTA: dsn-mtype; dsn-mname
+Diagnostic-Code: dsn-dtype; dsn-dtext
+
+--msgid.unix-time/mail.example
+Content-Description: Undelivered Message
+Content-Type: message/rfc822
+
+Return-Path: <sender@sender.example>
+Received: by wzv.porcupine.org (Postfix, from userid 0)
+ id 4CkXPY10M8z4w4l; Sun, 29 Nov 2020 15:30:41 +0000 (UTC)
+From: <sender@sender.example>
+To: <recipient@recipient.example>
+Message-Id: <12345@mta-name.example>
+Subject: with-msgid-with-eoh-event
+Date: Sun, 29 Nov 2020 15:30:41 +0000 (UTC)
+
+body text
+
+--msgid.unix-time/mail.example--
--- /dev/null
+From: MAILER-DAEMON (Mail Delivery System)
+Subject: Undelivered Mail Returned to Sender
+To: test-recipient
+References: <12345@mta-name.example>
+In-Reply-To: <12345@mta-name.example>
+Auto-Submitted: auto-replied
+MIME-Version: 1.0
+Content-Type: multipart/report; report-type=delivery-status;
+ boundary="msgid.unix-time/mail.example"
+Content-Transfer-Encoding: 7bit
+
+This is a MIME-encapsulated message.
+
+--msgid.unix-time/mail.example
+Content-Description: Notification
+Content-Type: text/plain; charset=us-ascii
+
+
+<rcpt-address> (expanded from <rcpt-orig_addr>): dsn-reason
+
+--msgid.unix-time/mail.example
+Content-Description: Delivery report
+Content-Type: message/delivery-status
+
+Reporting-MTA: dns; mail.example
+Original-Envelope-Id: TEST-ENVID
+X-Postfix-Queue-ID: msgid
+X-Postfix-Sender: rfc822; sender@sender.example
+Arrival-Date: Sun, 29 Nov 2020 10:30:41 -0500 (EST)
+
+Final-Recipient: rfc822; rcpt-address
+Original-Recipient: rfc822; rcpt-orig_addr
+Action: failed
+Status: dsn-status
+Remote-MTA: dsn-mtype; dsn-mname
+Diagnostic-Code: dsn-dtype; dsn-dtext
+
+--msgid.unix-time/mail.example
+Content-Description: Undelivered Message
+Content-Type: message/rfc822
+
+Return-Path: <sender@sender.example>
+Received: by wzv.porcupine.org (Postfix, from userid 0)
+ id 4CkXPY10M8z4w4l; Sun, 29 Nov 2020 15:30:41 +0000 (UTC)
+From: <sender@sender.example>
+To: <recipient@recipient.example>
+Message-Id: <12345@mta-name.example>
+Subject: with-msgid-with-eoh-event
+Date: Sun, 29 Nov 2020 15:30:41 +0000 (UTC)
+
+body text
+
+--msgid.unix-time/mail.example--
--- /dev/null
+From: MAILER-DAEMON (Mail Delivery System)
+Subject: Undelivered Mail Returned to Sender
+To: test-recipient
+Auto-Submitted: auto-replied
+MIME-Version: 1.0
+Content-Type: multipart/report; report-type=delivery-status;
+ boundary="msgid.unix-time/mail.example"
+Content-Transfer-Encoding: 7bit
+
+This is a MIME-encapsulated message.
+
+--msgid.unix-time/mail.example
+Content-Description: Notification
+Content-Type: text/plain; charset=us-ascii
+
+
+<rcpt-address> (expanded from <rcpt-orig_addr>): dsn-reason
+
+--msgid.unix-time/mail.example
+Content-Description: Delivery report
+Content-Type: message/delivery-status
+
+Reporting-MTA: dns; mail.example
+Original-Envelope-Id: TEST-ENVID
+X-Postfix-Queue-ID: msgid
+X-Postfix-Sender: rfc822; sender@sender.example
+Arrival-Date: Sat, 5 Dec 2020 13:31:48 -0500 (EST)
+
+Final-Recipient: rfc822; rcpt-address
+Original-Recipient: rfc822; rcpt-orig_addr
+Action: failed
+Status: dsn-status
+Remote-MTA: dsn-mtype; dsn-mname
+Diagnostic-Code: dsn-dtype; dsn-dtext
+
+--msgid.unix-time/mail.example
+Content-Description: Undelivered Message
+Content-Type: message/rfc822
+
+Return-Path: <sender@sender.example>
+Received: by wzv.porcupine.org (Postfix, from userid 0)
+ id 4CpJ7m6tprz4w4Y; Sat, 5 Dec 2020 18:31:48 +0000 (UTC)
+From: <sender@sender.example>
+To: <recipient@recipient.example>
+Message-Id: <12345@mta-name.example>
+Subject: with-msgid-no-eoh-event
+
+--msgid.unix-time/mail.example--
--- /dev/null
+From: MAILER-DAEMON (Mail Delivery System)
+Subject: Undelivered Mail Returned to Sender
+To: test-recipient
+References: <12345@mta-name.example>
+In-Reply-To: <12345@mta-name.example>
+Auto-Submitted: auto-replied
+MIME-Version: 1.0
+Content-Type: multipart/report; report-type=delivery-status;
+ boundary="msgid.unix-time/mail.example"
+Content-Transfer-Encoding: 7bit
+
+This is a MIME-encapsulated message.
+
+--msgid.unix-time/mail.example
+Content-Description: Notification
+Content-Type: text/plain; charset=us-ascii
+
+
+<rcpt-address> (expanded from <rcpt-orig_addr>): dsn-reason
+
+--msgid.unix-time/mail.example
+Content-Description: Delivery report
+Content-Type: message/delivery-status
+
+Reporting-MTA: dns; mail.example
+Original-Envelope-Id: TEST-ENVID
+X-Postfix-Queue-ID: msgid
+X-Postfix-Sender: rfc822; sender@sender.example
+Arrival-Date: Sat, 5 Dec 2020 13:31:48 -0500 (EST)
+
+Final-Recipient: rfc822; rcpt-address
+Original-Recipient: rfc822; rcpt-orig_addr
+Action: failed
+Status: dsn-status
+Remote-MTA: dsn-mtype; dsn-mname
+Diagnostic-Code: dsn-dtype; dsn-dtext
+
+--msgid.unix-time/mail.example
+Content-Description: Undelivered Message
+Content-Type: message/rfc822
+
+Return-Path: <sender@sender.example>
+Received: by wzv.porcupine.org (Postfix, from userid 0)
+ id 4CpJ7m6tprz4w4Y; Sat, 5 Dec 2020 18:31:48 +0000 (UTC)
+From: <sender@sender.example>
+To: <recipient@recipient.example>
+Message-Id: <12345@mta-name.example>
+Subject: with-msgid-no-eoh-event
+
+--msgid.unix-time/mail.example--
--- /dev/null
+From: MAILER-DAEMON (Mail Delivery System)
+Subject: Undelivered Mail Returned to Sender
+To: test-recipient
+Auto-Submitted: auto-replied
+MIME-Version: 1.0
+Content-Type: multipart/report; report-type=delivery-status;
+ boundary="msgid.unix-time/mail.example"
+Content-Transfer-Encoding: 7bit
+
+This is a MIME-encapsulated message.
+
+--msgid.unix-time/mail.example
+Content-Description: Notification
+Content-Type: text/plain; charset=us-ascii
+
+
+<rcpt-address> (expanded from <rcpt-orig_addr>): dsn-reason
+
+--msgid.unix-time/mail.example
+Content-Description: Delivery report
+Content-Type: message/delivery-status
+
+Reporting-MTA: dns; mail.example
+Original-Envelope-Id: TEST-ENVID
+X-Postfix-Queue-ID: msgid
+X-Postfix-Sender: rfc822; sender@sender.example
+Arrival-Date: Sun, 29 Nov 2020 10:30:41 -0500 (EST)
+
+Final-Recipient: rfc822; rcpt-address
+Original-Recipient: rfc822; rcpt-orig_addr
+Action: failed
+Status: dsn-status
+Remote-MTA: dsn-mtype; dsn-mname
+Diagnostic-Code: dsn-dtype; dsn-dtext
+
+--msgid.unix-time/mail.example
+Content-Description: Undelivered Message
+Content-Type: message/rfc822
+
+Return-Path: <sender@sender.example>
+Received: by wzv.porcupine.org (Postfix, from userid 0)
+ id 4CkXPY194lz4w4n; Sun, 29 Nov 2020 15:30:41 +0000 (UTC)
+From: <sender@sender.example>
+To: <recipient@recipient.example>
+Whatever: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+Message-Id: <12345@mta-name.example>
+Subject: with-msgid-with-long-line
+Date: Sun, 29 Nov 2020 15:30:41 +0000 (UTC)
+
+--msgid.unix-time/mail.example--
--- /dev/null
+From: MAILER-DAEMON (Mail Delivery System)
+Subject: Undelivered Mail Returned to Sender
+To: test-recipient
+References: <12345@mta-name.example>
+In-Reply-To: <12345@mta-name.example>
+Auto-Submitted: auto-replied
+MIME-Version: 1.0
+Content-Type: multipart/report; report-type=delivery-status;
+ boundary="msgid.unix-time/mail.example"
+Content-Transfer-Encoding: 7bit
+
+This is a MIME-encapsulated message.
+
+--msgid.unix-time/mail.example
+Content-Description: Notification
+Content-Type: text/plain; charset=us-ascii
+
+
+<rcpt-address> (expanded from <rcpt-orig_addr>): dsn-reason
+
+--msgid.unix-time/mail.example
+Content-Description: Delivery report
+Content-Type: message/delivery-status
+
+Reporting-MTA: dns; mail.example
+Original-Envelope-Id: TEST-ENVID
+X-Postfix-Queue-ID: msgid
+X-Postfix-Sender: rfc822; sender@sender.example
+Arrival-Date: Sun, 29 Nov 2020 10:30:41 -0500 (EST)
+
+Final-Recipient: rfc822; rcpt-address
+Original-Recipient: rfc822; rcpt-orig_addr
+Action: failed
+Status: dsn-status
+Remote-MTA: dsn-mtype; dsn-mname
+Diagnostic-Code: dsn-dtype; dsn-dtext
+
+--msgid.unix-time/mail.example
+Content-Description: Undelivered Message
+Content-Type: message/rfc822
+
+Return-Path: <sender@sender.example>
+Received: by wzv.porcupine.org (Postfix, from userid 0)
+ id 4CkXPY194lz4w4n; Sun, 29 Nov 2020 15:30:41 +0000 (UTC)
+From: <sender@sender.example>
+To: <recipient@recipient.example>
+Whatever: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+Message-Id: <12345@mta-name.example>
+Subject: with-msgid-with-long-line
+Date: Sun, 29 Nov 2020 15:30:41 +0000 (UTC)
+
+--msgid.unix-time/mail.example--
/* into the \fBincoming\fR mail queue, and informs the queue
/* manager of its arrival.
/*
-/* The \fBcleanup\fR(8) daemon always performs the following transformations:
+/* The \fBcleanup\fR(8) daemon performs the following transformations:
/* .IP \(bu
/* Insert missing message headers: (\fBResent-\fR) \fBFrom:\fR,
/* \fBTo:\fR, \fBMessage-Id:\fR, and \fBDate:\fR.
+/* .br
+/* This is enabled with the \fBlocal_header_rewrite_clients\fR and
+/* \fBalways_add_missing_headers\fR parameter settings.
/* .IP \(bu
/* Transform envelope and header addresses to the standard
/* \fIuser@fully-qualified-domain\fR form that is expected by other
/* Postfix programs.
-/* This task is delegated to the \fBtrivial-rewrite\fR(8) daemon.
+/* This task depends on the \fBtrivial-rewrite\fR(8) daemon.
+/* .br
+/* The header transformation is enabled with the
+/* \fBlocal_header_rewrite_clients\fR parameter setting.
/* .IP \(bu
/* Eliminate duplicate envelope recipient addresses.
+/* .br
+/* This is enabled with the \fBduplicate_filter_limit\fR
+/* parameter setting.
/* .IP \(bu
/* Remove message headers: \fBBcc\fR, \fBContent-Length\fR,
/* \fBResent-Bcc\fR, \fBReturn-Path\fR.
-/* .PP
-/* The following address transformations are optional:
+/* .br
+/* This is enabled with the message_drop_headers parameter
+/* setting.
/* .IP \(bu
/* Optionally, rewrite all envelope and header addresses according
/* to the mappings specified in the \fBcanonical\fR(5) lookup tables.
+/* .br
+/* The header transformation is enabled with the
+/* \fBlocal_header_rewrite_clients\fR parameter setting.
/* .IP \(bu
/* Optionally, masquerade envelope sender addresses and message
/* header addresses (i.e. strip host or domain information below
/* all domains listed in the \fBmasquerade_domains\fR parameter,
/* except for user names listed in \fBmasquerade_exceptions\fR).
/* By default, address masquerading does not affect envelope recipients.
+/* .br
+/* The header transformation is enabled with the
+/* \fBlocal_header_rewrite_clients\fR parameter setting.
/* .IP \(bu
/* Optionally, expand envelope recipients according to information
-/* found in the \fBvirtual\fR(5) lookup tables.
+/* found in the \fBvirtual_alias_maps\fR lookup tables.
/* .PP
/* The \fBcleanup\fR(8) daemon performs sanity checks on the content of
/* each message. When it finds a problem, by default it returns a
-/* diagnostic status to the client, and leaves it up to the client
+/* diagnostic status to the cleanup service client, and leaves
+/* it up to the client
/* to deal with the problem. Alternatively, the client can request
/* the \fBcleanup\fR(8) daemon to bounce the message back to the sender
/* in case of trouble.
smtputf8.c mail_conf_over.c mail_parm_split.c midna_adomain.c \
mail_addr_form.c quote_flags.c maillog_client.c \
normalize_mailhost_addr.c map_search.c reject_deliver_request.c \
- info_log_addr_form.c sasl_mech_filter.c login_sender_match.c
+ info_log_addr_form.c sasl_mech_filter.c login_sender_match.c \
+ test_main.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 \
smtputf8.o attr_override.o mail_parm_split.o midna_adomain.o \
$(NON_PLUGIN_MAP_OBJ) mail_addr_form.o quote_flags.o maillog_client.o \
normalize_mailhost_addr.o map_search.o reject_deliver_request.o \
- info_log_addr_form.o sasl_mech_filter.o login_sender_match.o
+ info_log_addr_form.o sasl_mech_filter.o login_sender_match.o \
+ test_main.o
# MAP_OBJ is for maps that may be dynamically loaded with dynamicmaps.cf.
# When hard-linking these maps, makedefs sets NON_PLUGIN_MAP_OBJ=$(MAP_OBJ),
# otherwise it sets the PLUGIN_* macros.
haproxy_srvr.h dsn_filter.h dynamicmaps.h uxtext.h smtputf8.h \
attr_override.h mail_parm_split.h midna_adomain.h mail_addr_form.h \
maillog_client.h normalize_mailhost_addr.h map_search.h \
- info_log_addr_form.h sasl_mech_filter.h login_sender_match.h
+ info_log_addr_form.h sasl_mech_filter.h login_sender_match.h \
+ test_main.h
TESTSRC = rec2stream.c stream2rec.c recdump.c
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
CFLAGS = $(DEBUG) $(OPT) $(DEFS)
sys_exits.o: ../../include/vstring.h
sys_exits.o: sys_exits.c
sys_exits.o: sys_exits.h
+test_main.o: ../../include/argv.h
+test_main.o: ../../include/check_arg.h
+test_main.o: ../../include/dict.h
+test_main.o: ../../include/msg.h
+test_main.o: ../../include/msg_vstream.h
+test_main.o: ../../include/myflock.h
+test_main.o: ../../include/mymalloc.h
+test_main.o: ../../include/stringops.h
+test_main.o: ../../include/sys_defs.h
+test_main.o: ../../include/vbuf.h
+test_main.o: ../../include/vstream.h
+test_main.o: ../../include/vstring.h
+test_main.o: mail_conf.h
+test_main.o: mail_dict.h
+test_main.o: mail_params.h
+test_main.o: mail_task.h
+test_main.o: mail_version.h
+test_main.o: test_main.c
+test_main.o: test_main.h
timed_ipc.o: ../../include/check_arg.h
timed_ipc.o: ../../include/msg.h
timed_ipc.o: ../../include/sys_defs.h
/*
/* void debug_peer_init(void)
/*
-/* int peer_debug_check(peer_name, peer_addr)
+/* int debug_peer_check(peer_name, peer_addr)
/* const char *peer_name;
/* const char *peer_addr;
/*
&& ((curr_type = rec_get(fp, info->buf, 0)) == REC_TYPE_NORM
|| curr_type == REC_TYPE_CONT);
prev_type = curr_type) {
- if (prev_type != REC_TYPE_NORM)
+ if (prev_type == REC_TYPE_CONT)
continue;
if (is_header(STR(info->buf))) {
if ((hdr = header_opts_find(STR(info->buf))) != 0
#define DEF_DOUBLE_BOUNCE "double-bounce"
extern char *var_double_bounce_sender;
+ /*
+ * Bounce service: enable threaded bounces, with References: and
+ * In-Reply-To:.
+ */
+#define VAR_THREADED_BOUNCE "enable_threaded_bounces"
+#define DEF_THREADED_BOUNCE CONFIG_BOOL_NO
+extern bool var_threaded_bounce;
+
/*
* When forking a process, how often to try and how long to wait.
*/
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20201104"
+#define MAIL_RELEASE_DATE "20201212"
#define MAIL_VERSION_NUMBER "3.6"
#ifdef SNAPSHOT
--- /dev/null
+/*++
+/* NAME
+/* test_main 3
+/* SUMMARY
+/* test main program
+/* SYNOPSIS
+/* #include <test_main.h>
+/*
+/* NORETURN test_main(argc, argv, test_driver, key, value, ...)
+/* int argc;
+/* char **argv;
+/* void (*test_driver)(int argc, char **argv);
+/* int key;
+/* DESCRIPTION
+/* This module implements a test main program for stand-alone
+/* module tests.
+/*
+/* test_main() should be called from a main program. It does
+/* generic command-line options processing, and initializes
+/* configurable parameters. After calling the test_driver()
+/* function, the test_main() function terminates.
+/*
+/* Arguments:
+/* .IP "void (*test_driver)(int argc, char **argv)"
+/* A pointer to a function that is called after processing
+/* command-line options and initializing configuration parameters.
+/* The argc and argv specify the process name and non-option
+/* command-line arguments.
+/* .PP
+/* Optional test_main() arguments are specified as a null-terminated
+/* list with macros that have zero or more arguments:
+/* .IP "CA_TEST_MAIN_INT_TABLE(CONFIG_INT_TABLE *)"
+/* A table with configurable parameters, to be loaded from the
+/* global Postfix configuration file. Tables are loaded in the
+/* order as specified, and multiple instances of the same type
+/* are allowed.
+/* .IP "CA_TEST_MAIN_LONG_TABLE(CONFIG_LONG_TABLE *)"
+/* A table with configurable parameters, to be loaded from the
+/* global Postfix configuration file. Tables are loaded in the
+/* order as specified, and multiple instances of the same type
+/* are allowed.
+/* .IP "CA_TEST_MAIN_STR_TABLE(CONFIG_STR_TABLE *)"
+/* A table with configurable parameters, to be loaded from the
+/* global Postfix configuration file. Tables are loaded in the
+/* order as specified, and multiple instances of the same type
+/* are allowed.
+/* .IP "CA_TEST_MAIN_BOOL_TABLE(CONFIG_BOOL_TABLE *)"
+/* A table with configurable parameters, to be loaded from the
+/* global Postfix configuration file. Tables are loaded in the
+/* order as specified, and multiple instances of the same type
+/* are allowed.
+/* .IP "CA_TEST_MAIN_TIME_TABLE(CONFIG_TIME_TABLE *)"
+/* A table with configurable parameters, to be loaded from the
+/* global Postfix configuration file. Tables are loaded in the
+/* order as specified, and multiple instances of the same type
+/* are allowed.
+/* .IP "CA_TEST_MAIN_RAW_TABLE(CONFIG_RAW_TABLE *)"
+/* A table with configurable parameters, to be loaded from the
+/* global Postfix configuration file. Tables are loaded in the
+/* order as specified, and multiple instances of the same type
+/* are allowed. Raw parameters are not subjected to $name
+/* evaluation.
+/* .IP "CA_TEST_MAIN_NINT_TABLE(CONFIG_NINT_TABLE *)"
+/* A table with configurable parameters, to be loaded from the
+/* global Postfix configuration file. Tables are loaded in the
+/* order as specified, and multiple instances of the same type
+/* are allowed.
+/* .IP "CA_TEST_MAIN_NBOOL_TABLE(CONFIG_NBOOL_TABLE *)"
+/* A table with configurable parameters, to be loaded from the
+/* global Postfix configuration file. Tables are loaded in the
+/* order as specified, and multiple instances of the same type
+/* are allowed.
+/* DIAGNOSTICS
+/* Problems and transactions are logged stderr.
+/* BUGS
+/* 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
+/*
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <stdlib.h>
+
+ /*
+ * Utility library.
+ */
+#include <dict.h>
+#include <msg.h>
+#include <msg_vstream.h>
+#include <mymalloc.h>
+#include <stringops.h>
+
+ /*
+ * Global library.
+ */
+#include <mail_params.h>
+#include <mail_conf.h>
+#include <mail_dict.h>
+#include <mail_task.h>
+#include <mail_version.h>
+
+ /*
+ * Test library.
+ */
+#include <test_main.h>
+
+/* test_driver_main - the real main program */
+
+NORETURN test_main(int argc, char **argv, TEST_DRIVER_FN test_driver,...)
+{
+ const char *myname = "test_driver_main";
+ va_list ap;
+ int ch;
+ int key;
+ int test_driver_argc;
+ char **test_driver_argv;
+
+ /*
+ * Set up logging.
+ */
+ var_procname = mystrdup(basename(argv[0]));
+ msg_vstream_init(mail_task(var_procname), VSTREAM_ERR);
+
+ /*
+ * Check the Postfix library version as soon as we enable logging.
+ */
+ MAIL_VERSION_CHECK;
+
+ /*
+ * Parse JCL.
+ */
+ while ((ch = GETOPT(argc, argv, "c:v")) > 0) {
+ switch (ch) {
+ case 'c':
+ if (setenv(CONF_ENV_PATH, optarg, 1) < 0)
+ msg_fatal("out of memory");
+ break;
+ case 'v':
+ msg_verbose++;
+ break;
+ default:
+ msg_fatal("invalid option: %c. Usage: %s [-c config_dir] [-v]",
+ optopt, argv[0]);
+ break;
+ }
+ }
+
+ /*
+ * Initialize generic parameters.
+ */
+ set_mail_conf_str(VAR_PROCNAME, var_procname);
+ set_mail_conf_str(VAR_SERVNAME, var_procname);
+ mail_conf_read();
+
+ /*
+ * Register higher-level dictionaries and initialize the support for
+ * dynamically-loaded dictionarles.
+ */
+ mail_dict_init();
+
+ /*
+ * Application-specific initialization.
+ */
+ va_start(ap, test_driver);
+ while ((key = va_arg(ap, int)) != 0) {
+ switch (key) {
+ case TEST_MAIN_INT_TABLE:
+ get_mail_conf_int_table(va_arg(ap, CONFIG_INT_TABLE *));
+ break;
+ case TEST_MAIN_LONG_TABLE:
+ get_mail_conf_long_table(va_arg(ap, CONFIG_LONG_TABLE *));
+ break;
+ case TEST_MAIN_STR_TABLE:
+ get_mail_conf_str_table(va_arg(ap, CONFIG_STR_TABLE *));
+ break;
+ case TEST_MAIN_BOOL_TABLE:
+ get_mail_conf_bool_table(va_arg(ap, CONFIG_BOOL_TABLE *));
+ break;
+ case TEST_MAIN_TIME_TABLE:
+ get_mail_conf_time_table(va_arg(ap, CONFIG_TIME_TABLE *));
+ break;
+ case TEST_MAIN_RAW_TABLE:
+ get_mail_conf_raw_table(va_arg(ap, CONFIG_RAW_TABLE *));
+ break;
+ case TEST_MAIN_NINT_TABLE:
+ get_mail_conf_nint_table(va_arg(ap, CONFIG_NINT_TABLE *));
+ break;
+ case TEST_MAIN_NBOOL_TABLE:
+ get_mail_conf_nbool_table(va_arg(ap, CONFIG_NBOOL_TABLE *));
+ break;
+ default:
+ msg_panic("%s: unknown argument type: %d", myname, key);
+ }
+ }
+ va_end(ap);
+
+ /*
+ * Set up call-back info.
+ */
+ test_driver_argv = argv + optind - 1;
+ if (test_driver_argv != argv)
+ test_driver_argv[0] = argv[0];
+ test_driver_argc = argc - optind + 1;
+
+ /*
+ * Call the test driver and terminate (if they didn't terminate already).
+ */
+ test_driver(test_driver_argc, test_driver_argv);
+ exit(0);
+}
--- /dev/null
+/*++
+/* NAME
+/* test_main 3h
+/* SUMMARY
+/* test main program
+/* SYNOPSIS
+/* #include <test_main.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * Global library.
+ */
+#include <mail_conf.h>
+
+ /*
+ * External interface. Copied from master/mail_server.h, but without
+ * introducing libmaster dependencies.
+ */
+#define TEST_MAIN_INT_TABLE 1
+#define TEST_MAIN_STR_TABLE 2
+#define TEST_MAIN_BOOL_TABLE 3
+#define TEST_MAIN_TIME_TABLE 4
+#define TEST_MAIN_RAW_TABLE 5
+#define TEST_MAIN_NINT_TABLE 6
+#define TEST_MAIN_NBOOL_TABLE 7
+#define TEST_MAIN_LONG_TABLE 8
+
+#define CA_TEST_MAIN_INT_TABLE(v) TEST_MAIN_INT_TABLE, CHECK_CPTR(TEST_MAIN, CONFIG_INT_TABLE, (v))
+#define CA_TEST_MAIN_STR_TABLE(v) TEST_MAIN_STR_TABLE, CHECK_CPTR(TEST_MAIN, CONFIG_STR_TABLE, (v))
+#define CA_TEST_MAIN_BOOL_TABLE(v) TEST_MAIN_BOOL_TABLE, CHECK_CPTR(TEST_MAIN, CONFIG_BOOL_TABLE, (v))
+#define CA_TEST_MAIN_TIME_TABLE(v) TEST_MAIN_TIME_TABLE, CHECK_CPTR(TEST_MAIN, CONFIG_TIME_TABLE, (v))
+#define CA_TEST_MAIN_RAW_TABLE(v) TEST_MAIN_RAW_TABLE, CHECK_CPTR(TEST_MAIN, CONFIG_RAW_TABLE, (v))
+#define CA_TEST_MAIN_NINT_TABLE(v) TEST_MAIN_NINT_TABLE, CHECK_CPTR(TEST_MAIN, CONFIG_NINT_TABLE, (v))
+#define CA_TEST_MAIN_NBOOL_TABLE(v) TEST_MAIN_NBOOL_TABLE, CHECK_CPTR(TEST_MAIN, CONFIG_NBOOL_TABLE, (v))
+#define CA_TEST_MAIN_LONG_TABLE(v) TEST_MAIN_LONG_TABLE, CHECK_CPTR(TEST_MAIN, CONFIG_LONG_TABLE, (v))
+
+CHECK_CPTR_HELPER_DCL(TEST_MAIN, CONFIG_INT_TABLE);
+CHECK_CPTR_HELPER_DCL(TEST_MAIN, CONFIG_STR_TABLE);
+CHECK_CPTR_HELPER_DCL(TEST_MAIN, CONFIG_BOOL_TABLE);
+CHECK_CPTR_HELPER_DCL(TEST_MAIN, CONFIG_TIME_TABLE);
+CHECK_CPTR_HELPER_DCL(TEST_MAIN, CONFIG_RAW_TABLE);
+CHECK_CPTR_HELPER_DCL(TEST_MAIN, CONFIG_NINT_TABLE);
+CHECK_CPTR_HELPER_DCL(TEST_MAIN, CONFIG_NBOOL_TABLE);
+CHECK_CPTR_HELPER_DCL(TEST_MAIN, CONFIG_LONG_TABLE);
+
+typedef void (*TEST_DRIVER_FN) (int, char **);
+extern NORETURN test_main(int, char **, TEST_DRIVER_FN,...);
+
+/* 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
+/*
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
-#include <stdio.h> /* strerror() */
#include <errno.h>
#include <netdb.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
-#include <stdio.h> /* strerror() */
#include <errno.h>
#include <netdb.h>
#include <string.h>
load_file.o: vstream.h
load_file.o: warn_stat.h
load_lib.o: load_lib.c
-load_lib.o: load_lib.h
-load_lib.o: msg.h
load_lib.o: sys_defs.h
logwriter.o: check_arg.h
logwriter.o: iostuff.h
break;
case 'm':
/* Ignore the 'l' modifier, width and precision. */
- VBUF_STRCAT(bp, strerror(saved_errno));
+ VBUF_STRCAT(bp, saved_errno ?
+ strerror(saved_errno) : "Application error");
break;
case 'p':
if (long_flag)