-TMKMAP_DB
-TMKMAP_DBM
-TMKMAP_OPEN_INFO
+-TMSG_STATS
-TMULTI_SERVER
-TMVECT
-TMYSQL
performs or prepares for mail delivery. Instead, have that routine
update the enhanced status code (and text) when the error happens.
This was an issue with mailbox, maildir and file delivery. Currently
-there remain two exceptions to this rule: mail_copy() for historical
-reasons may or may not return explicit error reports (fixing this
-requires that pipe_command() be restructured); and the maildir
+there remains one exception to this errno usage rule; the maildir
delivery routines log a helpful warning when delivery fails with
EACCES. The latter happens to work because mbox_open() does not
need to unlock the output file, so it won't clobber the errno value.
MAIL FROM command. This protects before-queue content
filters against over-size messages. File: smtpd/smtpd.c.
+20051017
+
+ Bugfix: after DSN support was added, smtp_skip_5xx_greeting
+ no longer recognized a 5xx SMTP status as a 4xx one. Found
+ by Ralf Hildebrandt. Fix: use the enhanced status code
+ instead of the SMTP reply code to choose between permanent
+ or transient errors. File: smtp/smtp_trouble.c.
+
+ Feature: smtp-sink can hard-reject, soft-reject or simply
+ drop connection requests. File: smtpstone/smtp-sink.c.
+
+ Documentation: clarified the processing of server replies,
+ specifically the reply code and the enhanced status code,
+ in smtp_chat.c.
+
+20051024
+
+ Performance: new smtp_connection_reuse_time_limit parameter to
+ limit connection reuse by elapsed time, instead of limiting
+ the number of deliveries per connection. Bounding by time
+ favors delivery over connections that perform well, while
+ bounding by number of deliveries allows slow connections
+ to drag down the performance. Insight and initial
+ implementation by Victor Duchovni, Morgan Stanley. Files:
+ smtp_connect.c, smtp_session.c,
+
+ Bugfix: the next-hop logical destination information for
+ connection caching was reset only after a good non-TLS
+ connection, so that cached connections to non-TLS backup
+ servers could suck away traffic from TLS primary servers
+ (the Postfix SMTP client cannot cache an open TLS connection).
+ Found during code review. This is fixed with multi-valued
+ connection caching state: expired, cachable, non-cachable,
+ and bad. Files: smtp_connect.c, smtp_trouble.c.
+
+ Bugfix: adding support for "sendmail -C" broke "sendmail
+ -q". File: sendmail/sendmail.c.
+
+20051101
+
+ Migration from a single "arrival time" stamp to a structure
+ with time stamps from different stages of message delivery.
+ The first iteration merely replaces "arrival time" stamps
+ by a structure or pointer to structure, and uses only the
+ arrival time field of that structure. This is an extensive
+ but straightforward transformation, based on example by
+ Victor Duchovni, Morgan Stanley. Files: anything that
+ invokes bounce_append etc., the log_adhoc module, and
+ anything that sends or receives a delivery request.
+
+20051102
+
+ Completion of support for time stamps from different stages
+ of message delivery. The information is now logged as
+ "delays=a/b/c/d" where a=time before queue manager, b=time
+ in queue manager, c=connection setup time, d=message
+ transmission time. Unlike Victor's example which used time
+ differences, this implementation uses absolute times. The
+ decision of what numbers to subtract actually depends on
+ program history, so we want to do it in one place. Files:
+ global/log_adhoc.c, smtp/smtp_connect.c, smtp/smtp_proto.c,
+ smtp/smtp_trouble.c, lmtp/lmtp_proto.c, lmtp/lmtp_trouble.c.
+
+20051103
+
+ Refinement of time stamping and delays formatting. The
+ hand-off time is now stamped in the delivery agent, so that
+ time is properly attributed when a transport is saturated
+ or throttled. Delays are now logged if larger than 0.01
+ second. Files: *qmgr/qmgr_deliver.c, global/deliver_request.c,
+ global/log_adhoc.c.
+
Open problems:
+ Is it safe to cache a connection after it has been used
+ for more than some number of address verification probes?
+
+ The code in smtp_connect() that catches server reject and
+ disconnect errors has become redundant. Connections that
+ fail before MAIL FROM no longer count towards the MX session
+ count limit per delivery attempt.
+
+ Access map actions such as FILTER and REDIRECT don't work
+ in smtpd_end_of_data_restrictions (or anything else that
+ generates additional queue file records after the message
+ content is stored).
+
Try to recognize that Resent- headers appear in blocks,
newest block first. But don't break on incorrect header
block organization.
issued by these CAs, append the root certificate to $smtpd_tls_CAfile or
install it in the $smtpd_tls_CApath directory. When you configure trust in a
root CA, it is not necessary to explicitly trust intermediary CAs signed by the
-root CA, unless $smtpd_tls_verify_depth is less than the number of CAs in the
-certificate chain for the clients of interest. With a verify depth of 1 you can
-only verify certificates directly signed by a trusted CA, and all trusted
+root CA, unless $smtpd_tls_ccert_verifydepth is less than the number of CAs in
+the certificate chain for the clients of interest. With a verify depth of 1 you
+can only verify certificates directly signed by a trusted CA, and all trusted
intermediary CAs need to be configured explicitly. With a verify depth of 2 you
can verify clients signed by a root CA or a direct intermediary CA (so long as
the client is correctly configured to supply its intermediate CA certificate).
jail.
When you configure Postfix to request client certificates (by setting
-$smtpd_tls_asck_ccert = yes), any certificates in $smtpd_tls_CAfile are sent to
+$smtpd_tls_ask_ccert = yes), any certificates in $smtpd_tls_CAfile are sent to
the client, in order to allow it to choose an identity signed by a CA you
trust. If no $smtpd_tls_CAfile is specified, no preferred CA list is sent, and
the client is free to choose an identity signed by any CA. Many clients use a
If you upgrade from Postfix 2.1 or earlier, read RELEASE_NOTES-2.2
before proceeding.
+Incompatibility with snapshot 20051103
+======================================
+
+The queue manager protocol has changed. You need to "postfix reload"
+after "make upgrade".
+
+The logging of recipient status information has changed. This may
+require changes to logfile processing tools.
+
+- Postfix now logs an additional attribute with detailed delay
+information (delays=a/b/c/d) as described below.
+
+- Postfix now logs an additional attribute with the connection reuse
+count (conn_use=nnn) as described below.
+
+Major changes with snapshot 20051103
+====================================
+
+This release makes a beginning with a series of new attributes in
+Postfix logfile records.
+
+- Better insight into the nature of performance bottle necks, with
+detailed logging of delays in various stages of message delivery.
+Postfix logs additional delay information as "delays=a/b/c/d" where
+a=time before queue manager, b=time in queue manager, c=connection
+setup time, d=message transmission time.
+
+- Logging of the connection reuse count when SMTP connections are
+used for more than one message delivery. This information is needed
+because Postfix can now reuse connections hundreds of times or more,
+and can help to diagnose interoperability problems with servers
+that suffer from memory leaks or other resource leaks.
+
+Incompatibility with snapshot 20051026
+======================================
+
+The connection cache protocol for SMTP connections has changed.
+You need to "postfix reload" after "make upgrade".
+
+The smtp_connection_cache_reuse_limit parameter (which limits the
+number of deliveries per SMTP connection) is replaced by the new
+smtp_connection_reuse_time_limit parameter (the time after which a
+connection is no longer stored into the connection cache).
+
+Major changes with snapshot 20051026
+====================================
+
+This snapshot addresses a performance stability problem with remote
+SMTP servers. The problem is not specific to Postfix: it can happen
+when any MTA sends large amounts of SMTP email to a site that has
+multiple MX hosts. The insight that led to the solution, as well
+as an initial implementation, are due to Victor Duchovni.
+
+The problem starts when one of a set of MX hosts becomes slower
+than the rest. Even though SMTP clients connect to fast and slow
+MX hosts with equal probability, the slow MX host ends up with more
+simultaneous inbound connections than the faster MX hosts, because
+the slow MX host needs more time to serve each client request.
+
+The slow MX host becomes a connection attractor. If one MX host
+becomes N times slower than the rest, it dominates mail delivery
+latency unless there are more than N fast MX hosts to counter the
+effect. And if the number of MX hosts is smaller than N, the mail
+delivery latency becomes effectively that of the slowest MX host
+divided by the total number of MX hosts.
+
+The solution uses connection caching in a way that differs from
+Postfix 2.2. By limiting the amount of time during which a connection
+can be used repeatedly (instead of limiting the number of deliveries
+over that connection), Postfix not only restores fairness in the
+distribution of simultaneous connections across a set of MX hosts,
+it also favors deliveries over connections that perform well, which
+is exactly what we want.
+
+The smtp_connection_reuse_time_limit feature implements the connection
+reuse time limit as discussed above. It limits the amount of time
+after which an SMTP connection is no longer stored into the connection
+cache. The default limit, 300s, can result in a huge number of
+deliveries over a single connection.
+
+This solution will be complete when Postfix logging is updated to
+include information about the number of times that a connection was
+used. This information is needed to diagnose inter-operability
+problems with servers that exhibit bugs when they receive multiple
+messages over the same connection.
+
Incompatibility with snapshot 20051011
======================================
# erwise log a generic message.
#
# Note: this action currently affects all recipients
-# of the message.
+# of the message. To discard only one recipient
+# without discarding the entire message, use the
+# transport(5) table to direct mail to the discard(8)
+# service.
#
# This feature is available in Postfix 2.0 and later.
#
-# DUNNO Pretend that the lookup key was not found. This
-# prevents Postfix from trying substrings of the
-# lookup key (such as a subdomain name, or a network
+# DUNNO Pretend that the lookup key was not found. This
+# prevents Postfix from trying substrings of the
+# lookup key (such as a subdomain name, or a network
# address subnetwork).
#
# This feature is available in Postfix 2.0 and later.
#
# FILTER transport:destination
-# After the message is queued, send the entire mes-
+# After the message is queued, send the entire mes-
# sage through the specified external content filter.
-# The transport:destination syntax is described in
-# the transport(5) manual page. More information
-# about external content filters is in the Postfix
+# The transport:destination syntax is described in
+# the transport(5) manual page. More information
+# about external content filters is in the Postfix
# FILTER_README file.
#
-# Note: this action overrides the main.cf con-
+# Note: this action overrides the main.cf con-
# tent_filter setting, and currently affects all
# recipients of the message.
#
# This feature is available in Postfix 2.0 and later.
#
# HOLD optional text...
-# Place the message on the hold queue, where it will
-# sit until someone either deletes it or releases it
-# for delivery. Log the optional text if specified,
+# Place the message on the hold queue, where it will
+# sit until someone either deletes it or releases it
+# for delivery. Log the optional text if specified,
# otherwise log a generic message.
#
-# Mail that is placed on hold can be examined with
-# the postcat(1) command, and can be destroyed or
+# Mail that is placed on hold can be examined with
+# the postcat(1) command, and can be destroyed or
# released with the postsuper(1) command.
#
-# Note: use "postsuper -r" to release mail that was
-# kept on hold for a significant fraction of $maxi-
+# Note: use "postsuper -r" to release mail that was
+# kept on hold for a significant fraction of $maxi-
# mal_queue_lifetime or $bounce_queue_lifetime, or
# longer.
#
-# Note: this action currently affects all recipients
+# Note: this action currently affects all recipients
# of the message.
#
# This feature is available in Postfix 2.0 and later.
#
# PREPEND headername: headervalue
-# Prepend the specified message header to the mes-
+# Prepend the specified message header to the mes-
# sage. When this action is used multiple times, the
-# first prepended header appears before the second
+# first prepended header appears before the second
# etc. prepended header.
#
-# Note: this action does not support multi-line mes-
+# Note: this action does not support multi-line mes-
# sage headers.
#
# This feature is available in Postfix 2.1 and later.
#
# REDIRECT user@domain
-# After the message is queued, send the message to
+# After the message is queued, send the message to
# the specified address instead of the intended
# recipient(s).
#
-# Note: this action overrides the FILTER action, and
+# Note: this action overrides the FILTER action, and
# currently affects all recipients of the message.
#
# This feature is available in Postfix 2.1 and later.
#
# WARN optional text...
# Log a warning with the optional text, together with
-# client information and if available, with helo,
+# client information and if available, with helo,
# sender, recipient and protocol information.
#
# This feature is available in Postfix 2.1 and later.
#
# ENHANCED STATUS CODES
# When an enhanced status code is specified in an access ta-
-# ble, it is subject to modification. The following trans-
-# formations are needed when the same access table is used
-# for client, helo, sender, or recipient access restric-
-# tions; they happen regardless of whether Postfix replies
+# ble, it is subject to modification. The following trans-
+# formations are needed when the same access table is used
+# for client, helo, sender, or recipient access restric-
+# tions; they happen regardless of whether Postfix replies
# to a MAIL FROM, RCPT TO or other SMTP command.
#
-# o When a sender address matches a REJECT action, the
-# Postfix SMTP server will transform a recipient DSN
-# status (e.g., 4.1.1-4.1.6) into the corresponding
+# o When a sender address matches a REJECT action, the
+# Postfix SMTP server will transform a recipient DSN
+# status (e.g., 4.1.1-4.1.6) into the corresponding
# sender DSN status, and vice versa.
#
-# o When non-address information matches a REJECT
-# action (such as the HELO command argument or the
-# client hostname/address), the Postfix SMTP server
-# will transform a sender or recipient DSN status
-# into a generic non-address DSN status (e.g.,
+# o When non-address information matches a REJECT
+# action (such as the HELO command argument or the
+# client hostname/address), the Postfix SMTP server
+# will transform a sender or recipient DSN status
+# into a generic non-address DSN status (e.g.,
# 4.0.0).
#
# REGULAR EXPRESSION TABLES
-# This section describes how the table lookups change when
+# This section describes how the table lookups change when
# the table is given in the form of regular expressions. For
-# a description of regular expression lookup table syntax,
+# a description of regular expression lookup table syntax,
# see regexp_table(5) or pcre_table(5).
#
-# Each pattern is a regular expression that is applied to
+# Each pattern is a regular expression that is applied to
# the entire string being looked up. Depending on the appli-
-# cation, that string is an entire client hostname, an
+# cation, that string is an entire client hostname, an
# entire client IP address, or an entire mail address. Thus,
# no parent domain or parent network search is done,
-# user@domain mail addresses are not broken up into their
+# user@domain mail addresses are not broken up into their
# user@ and domain constituent parts, nor is user+foo broken
# up into user and foo.
#
-# Patterns are applied in the order as specified in the ta-
-# ble, until a pattern is found that matches the search
+# Patterns are applied in the order as specified in the ta-
+# ble, until a pattern is found that matches the search
# string.
#
-# Actions are the same as with indexed file lookups, with
-# the additional feature that parenthesized substrings from
+# Actions are the same as with indexed file lookups, with
+# the additional feature that parenthesized substrings from
# the pattern can be interpolated as $1, $2 and so on.
#
# TCP-BASED TABLES
-# This section describes how the table lookups change when
+# This section describes how the table lookups change when
# lookups are directed to a TCP-based server. For a descrip-
# tion of the TCP client/server lookup protocol, see tcp_ta-
# ble(5). This feature is not available up to and including
# Postfix version 2.2.
#
-# Each lookup operation uses the entire query string once.
-# Depending on the application, that string is an entire
+# Each lookup operation uses the entire query string once.
+# Depending on the application, that string is an entire
# client hostname, an entire client IP address, or an entire
-# mail address. Thus, no parent domain or parent network
-# search is done, user@domain mail addresses are not broken
-# up into their user@ and domain constituent parts, nor is
+# mail address. Thus, no parent domain or parent network
+# search is done, user@domain mail addresses are not broken
+# up into their user@ and domain constituent parts, nor is
# user+foo broken up into user and foo.
#
# Actions are the same as with indexed file lookups.
#
# EXAMPLE
-# The following example uses an indexed file, so that the
-# order of table entries does not matter. The example per-
-# mits access by the client at address 1.2.3.4 but rejects
-# all other clients in 1.2.3.0/24. Instead of hash lookup
-# tables, some systems use dbm. Use the command "postconf
-# -m" to find out what lookup tables Postfix supports on
+# The following example uses an indexed file, so that the
+# order of table entries does not matter. The example per-
+# mits access by the client at address 1.2.3.4 but rejects
+# all other clients in 1.2.3.0/24. Instead of hash lookup
+# tables, some systems use dbm. Use the command "postconf
+# -m" to find out what lookup tables Postfix supports on
# your system.
#
# /etc/postfix/main.cf:
# editing the file.
#
# BUGS
-# The table format does not understand quoting conventions.
+# The table format does not understand quoting conventions.
#
# SEE ALSO
# postmap(1), Postfix lookup table manager
# transport(5), transport:nexthop syntax
#
# README FILES
-# Use "postconf readme_directory" or "postconf html_direc-
+# Use "postconf readme_directory" or "postconf html_direc-
# tory" to locate this information.
# SMTPD_ACCESS_README, built-in SMTP server access control
# DATABASE_README, Postfix lookup table overview
#
# LICENSE
-# The Secure Mailer license must be distributed with this
+# The Secure Mailer license must be distributed with this
# software.
#
# AUTHOR(S)
#
# Note: this action disables further header or
# body_checks inspection of the current message and
-# affects all recipients.
+# affects all recipients. To discard only one recip-
+# ient without discarding the entire message, use the
+# transport(5) table to direct mail to the discard(8)
+# service.
#
# This feature is available in Postfix 2.0 and later.
#
-# DUNNO Pretend that the input line did not match any pat-
-# tern, and inspect the next input line. This action
+# DUNNO Pretend that the input line did not match any pat-
+# tern, and inspect the next input line. This action
# can be used to shorten the table search.
#
-# For backwards compatibility reasons, Postfix also
-# accepts OK but it is (and always has been) treated
+# For backwards compatibility reasons, Postfix also
+# accepts OK but it is (and always has been) treated
# as DUNNO.
#
# This feature is available in Postfix 2.1 and later.
#
# FILTER transport:destination
-# Write a content filter request to the queue file
-# and inspect the next input line. After the com-
-# plete message is received it will be sent through
+# Write a content filter request to the queue file
+# and inspect the next input line. After the com-
+# plete message is received it will be sent through
# the specified external content filter. More infor-
-# mation about external content filters is in the
+# mation about external content filters is in the
# Postfix FILTER_README file.
#
-# Note: this action overrides the main.cf con-
-# tent_filter setting, and affects all recipients of
-# the message. In the case that multiple FILTER
+# Note: this action overrides the main.cf con-
+# tent_filter setting, and affects all recipients of
+# the message. In the case that multiple FILTER
# actions fire, only the last one is executed.
#
# This feature is available in Postfix 2.0 and later.
#
# HOLD optional text...
-# Arrange for the message to be placed on the hold
-# queue, and inspect the next input line. The mes-
-# sage remains on hold until someone either deletes
-# it or releases it for delivery. Log the optional
+# Arrange for the message to be placed on the hold
+# queue, and inspect the next input line. The mes-
+# sage remains on hold until someone either deletes
+# it or releases it for delivery. Log the optional
# text if specified, otherwise log a generic message.
#
-# Mail that is placed on hold can be examined with
-# the postcat(1) command, and can be destroyed or
+# Mail that is placed on hold can be examined with
+# the postcat(1) command, and can be destroyed or
# released with the postsuper(1) command.
#
-# Note: use "postsuper -r" to release mail that was
-# kept on hold for a significant fraction of $maxi-
+# Note: use "postsuper -r" to release mail that was
+# kept on hold for a significant fraction of $maxi-
# mal_queue_lifetime or $bounce_queue_lifetime, or
# longer.
#
-# Note: this action affects all recipients of the
+# Note: this action affects all recipients of the
# message.
#
# This feature is available in Postfix 2.0 and later.
#
-# IGNORE Delete the current line from the input and inspect
+# IGNORE Delete the current line from the input and inspect
# the next input line.
#
# PREPEND text...
#
# Notes:
#
-# o The prepended text is output on a separate
+# o The prepended text is output on a separate
# line, immediately before the input that
# triggered the PREPEND action.
#
# o The prepended text is not considered part of
-# the input stream: it is not subject to
+# the input stream: it is not subject to
# header/body checks or address rewriting, and
# it does not affect the way that Postfix adds
# missing message headers.
#
# o When prepending text before a message header
-# line, the prepended text must begin with a
+# line, the prepended text must begin with a
# valid message header label.
#
# o This action cannot be used to prepend multi-
# This feature is available in Postfix 2.1 and later.
#
# REDIRECT user@domain
-# Write a message redirection request to the queue
-# file and inspect the next input line. After the
+# Write a message redirection request to the queue
+# file and inspect the next input line. After the
# message is queued, it will be sent to the specified
# address instead of the intended recipient(s).
#
-# Note: this action overrides the FILTER action, and
-# affects all recipients of the message. If multiple
-# REDIRECT actions fire, only the last one is exe-
+# Note: this action overrides the FILTER action, and
+# affects all recipients of the message. If multiple
+# REDIRECT actions fire, only the last one is exe-
# cuted.
#
# This feature is available in Postfix 2.1 and later.
#
# REPLACE text...
-# Replace the current line with the specified text
+# Replace the current line with the specified text
# and inspect the next input line.
#
# This feature is available in Postfix 2.2 and later.
-# The description below applies to Postfix 2.2.2 and
+# The description below applies to Postfix 2.2.2 and
# later.
#
# Notes:
#
-# o When replacing a message header line, the
-# replacement text must begin with a valid
+# o When replacing a message header line, the
+# replacement text must begin with a valid
# header label.
#
-# o The replaced text remains part of the input
-# stream. Unlike the result from the PREPEND
-# action, a replaced message header may be
-# subject to address rewriting and may affect
-# the way that Postfix adds missing message
+# o The replaced text remains part of the input
+# stream. Unlike the result from the PREPEND
+# action, a replaced message header may be
+# subject to address rewriting and may affect
+# the way that Postfix adds missing message
# headers.
#
# REJECT optional text...
-# Reject the entire message. Reply with optional
+# Reject the entire message. Reply with optional
# text... when the optional text is specified, other-
# wise reply with a generic error message.
#
-# Note: this action disables further header or
-# body_checks inspection of the current message and
+# Note: this action disables further header or
+# body_checks inspection of the current message and
# affects all recipients.
#
# Postfix version 2.3 and later support enhanced sta-
# enhanced status code of "5.7.1".
#
# WARN optional text...
-# Log a warning with the optional text... (or log a
-# generic message) and inspect the next input line.
+# Log a warning with the optional text... (or log a
+# generic message) and inspect the next input line.
# This action is useful for debugging and for testing
# a pattern before applying more drastic actions.
#
# BUGS
-# Many people overlook the main limitations of header and
-# body_checks rules. These rules operate on one logical
-# message header or one body line at a time, and a decision
-# made for one line is not carried over to the next line.
+# Many people overlook the main limitations of header and
+# body_checks rules. These rules operate on one logical
+# message header or one body line at a time, and a decision
+# made for one line is not carried over to the next line.
# If text in the message body is encoded (RFC 2045) then the
-# rules have to specified for the encoded form. Likewise,
+# rules have to specified for the encoded form. Likewise,
# when message headers are encoded (RFC 2047) then the rules
# need to be specified for the encoded form.
#
-# Message headers added by the cleanup(8) daemon itself are
+# Message headers added by the cleanup(8) daemon itself are
# excluded from inspection. Examples of such message headers
# are From:, To:, Message-ID:, Date:.
#
-# Message headers deleted by the cleanup(8) daemon will be
+# Message headers deleted by the cleanup(8) daemon will be
# examined before they are deleted. Examples are: Bcc:, Con-
# tent-Length:, Return-Path:.
#
# body_checks
# Lookup tables with content filter rules for message
# body lines. These filters see one physical line at
-# a time, in chunks of at most $line_length_limit
+# a time, in chunks of at most $line_length_limit
# bytes.
#
# body_checks_size_limit
-# The amount of content per message body segment
+# The amount of content per message body segment
# (attachment) that is subjected to $body_checks fil-
# tering.
#
#
# nested_header_checks (default: $header_checks)
# Lookup tables with content filter rules for message
-# header lines: respectively, these are applied to
-# the initial message headers (not including MIME
-# headers), to the MIME headers anywhere in the mes-
-# sage, and to the initial headers of attached mes-
+# header lines: respectively, these are applied to
+# the initial message headers (not including MIME
+# headers), to the MIME headers anywhere in the mes-
+# sage, and to the initial headers of attached mes-
# sages.
#
-# Note: these filters see one logical message header
-# at a time, even when a message header spans multi-
-# ple lines. Message headers that are longer than
+# Note: these filters see one logical message header
+# at a time, even when a message header spans multi-
+# ple lines. Message headers that are longer than
# $header_size_limit characters are truncated.
#
# disable_mime_input_processing
-# While receiving mail, give no special treatment to
-# MIME related message headers; all text after the
+# While receiving mail, give no special treatment to
+# MIME related message headers; all text after the
# initial message headers is considered to be part of
-# the message body. This means that header_checks is
-# applied to all the initial message headers, and
+# the message body. This means that header_checks is
+# applied to all the initial message headers, and
# that body_checks is applied to the remainder of the
# message.
#
-# Note: when used in this manner, body_checks will
-# process a multi-line message header one line at a
+# Note: when used in this manner, body_checks will
+# process a multi-line message header one line at a
# time.
#
# EXAMPLES
-# Header pattern to block attachments with bad file name
+# Header pattern to block attachments with bad file name
# extensions.
#
# /etc/postfix/main.cf:
# RFC 2047, message header encoding for non-ASCII text
#
# README FILES
-# Use "postconf readme_directory" or "postconf html_direc-
+# Use "postconf readme_directory" or "postconf html_direc-
# tory" to locate this information.
# DATABASE_README, Postfix lookup table overview
# CONTENT_INSPECTION_README, Postfix content inspection overview
# BACKSCATTER_README, blocking returned forged mail
#
# LICENSE
-# The Secure Mailer license must be distributed with this
+# The Secure Mailer license must be distributed with this
# software.
#
# AUTHOR(S)
certificates issued by these CAs, append the root certificate to
$<a href="postconf.5.html#smtpd_tls_CAfile">smtpd_tls_CAfile</a> or install it in the $<a href="postconf.5.html#smtpd_tls_CApath">smtpd_tls_CApath</a> directory. When
you configure trust in a root CA, it is not necessary to explicitly trust
-intermediary CAs signed by the root CA, unless $smtpd_tls_verify_depth
+intermediary CAs signed by the root CA, unless $<a href="postconf.5.html#smtpd_tls_ccert_verifydepth">smtpd_tls_ccert_verifydepth</a>
is less than the number of CAs in the certificate chain for the clients
of interest. With a verify depth of 1 you can only verify certificates
directly signed by a trusted CA, and all trusted intermediary CAs need to
accessible inside the optional chroot jail. </p>
<p> When you configure Postfix to request client certificates (by
-setting $smtpd_tls_asck_ccert = yes), any certificates in
+setting $<a href="postconf.5.html#smtpd_tls_ask_ccert">smtpd_tls_ask_ccert</a> = yes), any certificates in
$<a href="postconf.5.html#smtpd_tls_CAfile">smtpd_tls_CAfile</a> are sent to the client, in order to allow it to
choose an identity signed by a CA you trust. If no $<a href="postconf.5.html#smtpd_tls_CAfile">smtpd_tls_CAfile</a>
is specified, no preferred CA list is sent, and the client is free
erwise log a generic message.
Note: this action currently affects all recipients
- of the message.
+ of the message. To discard only one recipient
+ without discarding the entire message, use the
+ <a href="transport.5.html">transport(5)</a> table to direct mail to the <a href="discard.8.html">discard(8)</a>
+ service.
This feature is available in Postfix 2.0 and later.
- <b>DUNNO</b> Pretend that the lookup key was not found. This
- prevents Postfix from trying substrings of the
- lookup key (such as a subdomain name, or a network
+ <b>DUNNO</b> Pretend that the lookup key was not found. This
+ prevents Postfix from trying substrings of the
+ lookup key (such as a subdomain name, or a network
address subnetwork).
This feature is available in Postfix 2.0 and later.
<b>FILTER</b> <i>transport:destination</i>
- After the message is queued, send the entire mes-
+ After the message is queued, send the entire mes-
sage through the specified external content filter.
- The <i>transport:destination</i> syntax is described in
- the <a href="transport.5.html"><b>transport</b>(5)</a> manual page. More information
- about external content filters is in the Postfix
+ The <i>transport:destination</i> syntax is described in
+ the <a href="transport.5.html"><b>transport</b>(5)</a> manual page. More information
+ about external content filters is in the Postfix
<a href="FILTER_README.html">FILTER_README</a> file.
- Note: this action overrides the <b>main.cf <a href="postconf.5.html#content_filter">con</a>-</b>
+ Note: this action overrides the <b>main.cf <a href="postconf.5.html#content_filter">con</a>-</b>
<b><a href="postconf.5.html#content_filter">tent_filter</a></b> setting, and currently affects all
recipients of the message.
This feature is available in Postfix 2.0 and later.
<b>HOLD</b> <i>optional text...</i>
- Place the message on the <b>hold</b> queue, where it will
- sit until someone either deletes it or releases it
- for delivery. Log the optional text if specified,
+ Place the message on the <b>hold</b> queue, where it will
+ sit until someone either deletes it or releases it
+ for delivery. Log the optional text if specified,
otherwise log a generic message.
- Mail that is placed on hold can be examined with
- the <a href="postcat.1.html"><b>postcat</b>(1)</a> command, and can be destroyed or
+ Mail that is placed on hold can be examined with
+ the <a href="postcat.1.html"><b>postcat</b>(1)</a> command, and can be destroyed or
released with the <a href="postsuper.1.html"><b>postsuper</b>(1)</a> command.
- Note: use "<b>postsuper -r</b>" to release mail that was
- kept on hold for a significant fraction of <b>$<a href="postconf.5.html#maximal_queue_lifetime">maxi</a>-</b>
+ Note: use "<b>postsuper -r</b>" to release mail that was
+ kept on hold for a significant fraction of <b>$<a href="postconf.5.html#maximal_queue_lifetime">maxi</a>-</b>
<b><a href="postconf.5.html#maximal_queue_lifetime">mal_queue_lifetime</a></b> or <b>$<a href="postconf.5.html#bounce_queue_lifetime">bounce_queue_lifetime</a></b>, or
longer.
- Note: this action currently affects all recipients
+ Note: this action currently affects all recipients
of the message.
This feature is available in Postfix 2.0 and later.
<b>PREPEND</b> <i>headername: headervalue</i>
- Prepend the specified message header to the mes-
+ Prepend the specified message header to the mes-
sage. When this action is used multiple times, the
- first prepended header appears before the second
+ first prepended header appears before the second
etc. prepended header.
- Note: this action does not support multi-line mes-
+ Note: this action does not support multi-line mes-
sage headers.
This feature is available in Postfix 2.1 and later.
<b>REDIRECT</b> <i>user@domain</i>
- After the message is queued, send the message to
+ After the message is queued, send the message to
the specified address instead of the intended
recipient(s).
- Note: this action overrides the FILTER action, and
+ Note: this action overrides the FILTER action, and
currently affects all recipients of the message.
This feature is available in Postfix 2.1 and later.
<b>WARN</b> <i>optional text...</i>
Log a warning with the optional text, together with
- client information and if available, with helo,
+ client information and if available, with helo,
sender, recipient and protocol information.
This feature is available in Postfix 2.1 and later.
<b>ENHANCED STATUS CODES</b>
When an enhanced status code is specified in an access ta-
- ble, it is subject to modification. The following trans-
- formations are needed when the same access table is used
- for client, helo, sender, or recipient access restric-
- tions; they happen regardless of whether Postfix replies
+ ble, it is subject to modification. The following trans-
+ formations are needed when the same access table is used
+ for client, helo, sender, or recipient access restric-
+ tions; they happen regardless of whether Postfix replies
to a MAIL FROM, RCPT TO or other SMTP command.
- <b>o</b> When a sender address matches a REJECT action, the
- Postfix SMTP server will transform a recipient DSN
- status (e.g., 4.1.1-4.1.6) into the corresponding
+ <b>o</b> When a sender address matches a REJECT action, the
+ Postfix SMTP server will transform a recipient DSN
+ status (e.g., 4.1.1-4.1.6) into the corresponding
sender DSN status, and vice versa.
- <b>o</b> When non-address information matches a REJECT
- action (such as the HELO command argument or the
- client hostname/address), the Postfix SMTP server
- will transform a sender or recipient DSN status
- into a generic non-address DSN status (e.g.,
+ <b>o</b> When non-address information matches a REJECT
+ action (such as the HELO command argument or the
+ client hostname/address), the Postfix SMTP server
+ will transform a sender or recipient DSN status
+ into a generic non-address DSN status (e.g.,
4.0.0).
<b>REGULAR EXPRESSION TABLES</b>
- This section describes how the table lookups change when
+ This section describes how the table lookups change when
the table is given in the form of regular expressions. For
- a description of regular expression lookup table syntax,
+ a description of regular expression lookup table syntax,
see <a href="regexp_table.5.html"><b>regexp_table</b>(5)</a> or <a href="pcre_table.5.html"><b>pcre_table</b>(5)</a>.
- Each pattern is a regular expression that is applied to
+ Each pattern is a regular expression that is applied to
the entire string being looked up. Depending on the appli-
- cation, that string is an entire client hostname, an
+ cation, that string is an entire client hostname, an
entire client IP address, or an entire mail address. Thus,
no parent domain or parent network search is done,
- <i>user@domain</i> mail addresses are not broken up into their
+ <i>user@domain</i> mail addresses are not broken up into their
<i>user@</i> and <i>domain</i> constituent parts, nor is <i>user+foo</i> broken
up into <i>user</i> and <i>foo</i>.
- Patterns are applied in the order as specified in the ta-
- ble, until a pattern is found that matches the search
+ Patterns are applied in the order as specified in the ta-
+ ble, until a pattern is found that matches the search
string.
- Actions are the same as with indexed file lookups, with
- the additional feature that parenthesized substrings from
+ Actions are the same as with indexed file lookups, with
+ the additional feature that parenthesized substrings from
the pattern can be interpolated as <b>$1</b>, <b>$2</b> and so on.
<b>TCP-BASED TABLES</b>
- This section describes how the table lookups change when
+ This section describes how the table lookups change when
lookups are directed to a TCP-based server. For a descrip-
tion of the TCP client/server lookup protocol, see <a href="tcp_table.5.html"><b>tcp_ta-</b></a>
<a href="tcp_table.5.html"><b>ble</b>(5)</a>. This feature is not available up to and including
Postfix version 2.2.
- Each lookup operation uses the entire query string once.
- Depending on the application, that string is an entire
+ Each lookup operation uses the entire query string once.
+ Depending on the application, that string is an entire
client hostname, an entire client IP address, or an entire
- mail address. Thus, no parent domain or parent network
- search is done, <i>user@domain</i> mail addresses are not broken
- up into their <i>user@</i> and <i>domain</i> constituent parts, nor is
+ mail address. Thus, no parent domain or parent network
+ search is done, <i>user@domain</i> mail addresses are not broken
+ up into their <i>user@</i> and <i>domain</i> constituent parts, nor is
<i>user+foo</i> broken up into <i>user</i> and <i>foo</i>.
Actions are the same as with indexed file lookups.
<b>EXAMPLE</b>
- The following example uses an indexed file, so that the
- order of table entries does not matter. The example per-
- mits access by the client at address 1.2.3.4 but rejects
- all other clients in 1.2.3.0/24. Instead of <b>hash</b> lookup
- tables, some systems use <b>dbm</b>. Use the command "<b>postconf</b>
- <b>-m</b>" to find out what lookup tables Postfix supports on
+ The following example uses an indexed file, so that the
+ order of table entries does not matter. The example per-
+ mits access by the client at address 1.2.3.4 but rejects
+ all other clients in 1.2.3.0/24. Instead of <b>hash</b> lookup
+ tables, some systems use <b>dbm</b>. Use the command "<b>postconf</b>
+ <b>-m</b>" to find out what lookup tables Postfix supports on
your system.
/etc/postfix/main.cf:
editing the file.
<b>BUGS</b>
- The table format does not understand quoting conventions.
+ The table format does not understand quoting conventions.
<b>SEE ALSO</b>
<a href="postmap.1.html">postmap(1)</a>, Postfix lookup table manager
<a href="DATABASE_README.html">DATABASE_README</a>, Postfix lookup table overview
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>
Note: this action disables further header or
<a href="postconf.5.html#body_checks">body_checks</a> inspection of the current message and
- affects all recipients.
+ affects all recipients. To discard only one recip-
+ ient without discarding the entire message, use the
+ <a href="transport.5.html">transport(5)</a> table to direct mail to the <a href="discard.8.html">discard(8)</a>
+ service.
This feature is available in Postfix 2.0 and later.
- <b>DUNNO</b> Pretend that the input line did not match any pat-
- tern, and inspect the next input line. This action
+ <b>DUNNO</b> Pretend that the input line did not match any pat-
+ tern, and inspect the next input line. This action
can be used to shorten the table search.
- For backwards compatibility reasons, Postfix also
- accepts <b>OK</b> but it is (and always has been) treated
+ For backwards compatibility reasons, Postfix also
+ accepts <b>OK</b> but it is (and always has been) treated
as <b>DUNNO</b>.
This feature is available in Postfix 2.1 and later.
<b>FILTER</b> <i>transport:destination</i>
- Write a content filter request to the queue file
- and inspect the next input line. After the com-
- plete message is received it will be sent through
+ Write a content filter request to the queue file
+ and inspect the next input line. After the com-
+ plete message is received it will be sent through
the specified external content filter. More infor-
- mation about external content filters is in the
+ mation about external content filters is in the
Postfix <a href="FILTER_README.html">FILTER_README</a> file.
- Note: this action overrides the <b>main.cf <a href="postconf.5.html#content_filter">con</a>-</b>
- <b><a href="postconf.5.html#content_filter">tent_filter</a></b> setting, and affects all recipients of
- the message. In the case that multiple <b>FILTER</b>
+ Note: this action overrides the <b>main.cf <a href="postconf.5.html#content_filter">con</a>-</b>
+ <b><a href="postconf.5.html#content_filter">tent_filter</a></b> setting, and affects all recipients of
+ the message. In the case that multiple <b>FILTER</b>
actions fire, only the last one is executed.
This feature is available in Postfix 2.0 and later.
<b>HOLD</b> <i>optional text...</i>
- Arrange for the message to be placed on the <b>hold</b>
- queue, and inspect the next input line. The mes-
- sage remains on <b>hold</b> until someone either deletes
- it or releases it for delivery. Log the optional
+ Arrange for the message to be placed on the <b>hold</b>
+ queue, and inspect the next input line. The mes-
+ sage remains on <b>hold</b> until someone either deletes
+ it or releases it for delivery. Log the optional
text if specified, otherwise log a generic message.
- Mail that is placed on hold can be examined with
- the <a href="postcat.1.html"><b>postcat</b>(1)</a> command, and can be destroyed or
+ Mail that is placed on hold can be examined with
+ the <a href="postcat.1.html"><b>postcat</b>(1)</a> command, and can be destroyed or
released with the <a href="postsuper.1.html"><b>postsuper</b>(1)</a> command.
- Note: use "<b>postsuper -r</b>" to release mail that was
- kept on hold for a significant fraction of <b>$<a href="postconf.5.html#maximal_queue_lifetime">maxi</a>-</b>
+ Note: use "<b>postsuper -r</b>" to release mail that was
+ kept on hold for a significant fraction of <b>$<a href="postconf.5.html#maximal_queue_lifetime">maxi</a>-</b>
<b><a href="postconf.5.html#maximal_queue_lifetime">mal_queue_lifetime</a></b> or <b>$<a href="postconf.5.html#bounce_queue_lifetime">bounce_queue_lifetime</a></b>, or
longer.
- Note: this action affects all recipients of the
+ Note: this action affects all recipients of the
message.
This feature is available in Postfix 2.0 and later.
- <b>IGNORE</b> Delete the current line from the input and inspect
+ <b>IGNORE</b> Delete the current line from the input and inspect
the next input line.
<b>PREPEND</b> <i>text...</i>
Notes:
- <b>o</b> The prepended text is output on a separate
+ <b>o</b> The prepended text is output on a separate
line, immediately before the input that
triggered the <b>PREPEND</b> action.
<b>o</b> The prepended text is not considered part of
- the input stream: it is not subject to
+ the input stream: it is not subject to
header/body checks or address rewriting, and
it does not affect the way that Postfix adds
missing message headers.
<b>o</b> When prepending text before a message header
- line, the prepended text must begin with a
+ line, the prepended text must begin with a
valid message header label.
<b>o</b> This action cannot be used to prepend multi-
This feature is available in Postfix 2.1 and later.
<b>REDIRECT</b> <i>user@domain</i>
- Write a message redirection request to the queue
- file and inspect the next input line. After the
+ Write a message redirection request to the queue
+ file and inspect the next input line. After the
message is queued, it will be sent to the specified
address instead of the intended recipient(s).
- Note: this action overrides the <b>FILTER</b> action, and
- affects all recipients of the message. If multiple
- <b>REDIRECT</b> actions fire, only the last one is exe-
+ Note: this action overrides the <b>FILTER</b> action, and
+ affects all recipients of the message. If multiple
+ <b>REDIRECT</b> actions fire, only the last one is exe-
cuted.
This feature is available in Postfix 2.1 and later.
<b>REPLACE</b> <i>text...</i>
- Replace the current line with the specified text
+ Replace the current line with the specified text
and inspect the next input line.
This feature is available in Postfix 2.2 and later.
- The description below applies to Postfix 2.2.2 and
+ The description below applies to Postfix 2.2.2 and
later.
Notes:
- <b>o</b> When replacing a message header line, the
- replacement text must begin with a valid
+ <b>o</b> When replacing a message header line, the
+ replacement text must begin with a valid
header label.
- <b>o</b> The replaced text remains part of the input
- stream. Unlike the result from the <b>PREPEND</b>
- action, a replaced message header may be
- subject to address rewriting and may affect
- the way that Postfix adds missing message
+ <b>o</b> The replaced text remains part of the input
+ stream. Unlike the result from the <b>PREPEND</b>
+ action, a replaced message header may be
+ subject to address rewriting and may affect
+ the way that Postfix adds missing message
headers.
<b>REJECT</b> <i>optional text...</i>
- Reject the entire message. Reply with <i>optional</i>
+ Reject the entire message. Reply with <i>optional</i>
<i>text...</i> when the optional text is specified, other-
wise reply with a generic error message.
- Note: this action disables further header or
- <a href="postconf.5.html#body_checks">body_checks</a> inspection of the current message and
+ Note: this action disables further header or
+ <a href="postconf.5.html#body_checks">body_checks</a> inspection of the current message and
affects all recipients.
Postfix version 2.3 and later support enhanced sta-
enhanced status code of "5.7.1".
<b>WARN</b> <i>optional text...</i>
- Log a warning with the <i>optional text...</i> (or log a
- generic message) and inspect the next input line.
+ Log a warning with the <i>optional text...</i> (or log a
+ generic message) and inspect the next input line.
This action is useful for debugging and for testing
a pattern before applying more drastic actions.
<b>BUGS</b>
- Many people overlook the main limitations of header and
- <a href="postconf.5.html#body_checks">body_checks</a> rules. These rules operate on one logical
- message header or one body line at a time, and a decision
- made for one line is not carried over to the next line.
+ Many people overlook the main limitations of header and
+ <a href="postconf.5.html#body_checks">body_checks</a> rules. These rules operate on one logical
+ message header or one body line at a time, and a decision
+ made for one line is not carried over to the next line.
If text in the message body is encoded (<a href="http://www.faqs.org/rfcs/rfc2045.html">RFC 2045</a>) then the
- rules have to specified for the encoded form. Likewise,
+ rules have to specified for the encoded form. Likewise,
when message headers are encoded (<a href="http://www.faqs.org/rfcs/rfc2047.html">RFC 2047</a>) then the rules
need to be specified for the encoded form.
- Message headers added by the <a href="cleanup.8.html"><b>cleanup</b>(8)</a> daemon itself are
+ Message headers added by the <a href="cleanup.8.html"><b>cleanup</b>(8)</a> daemon itself are
excluded from inspection. Examples of such message headers
are <b>From:</b>, <b>To:</b>, <b>Message-ID:</b>, <b>Date:</b>.
- Message headers deleted by the <a href="cleanup.8.html"><b>cleanup</b>(8)</a> daemon will be
+ Message headers deleted by the <a href="cleanup.8.html"><b>cleanup</b>(8)</a> daemon will be
examined before they are deleted. Examples are: <b>Bcc:, Con-</b>
<b>tent-Length:</b>, <b>Return-Path:</b>.
<b><a href="postconf.5.html#body_checks">body_checks</a></b>
Lookup tables with content filter rules for message
body lines. These filters see one physical line at
- a time, in chunks of at most <b>$<a href="postconf.5.html#line_length_limit">line_length_limit</a></b>
+ a time, in chunks of at most <b>$<a href="postconf.5.html#line_length_limit">line_length_limit</a></b>
bytes.
<b><a href="postconf.5.html#body_checks_size_limit">body_checks_size_limit</a></b>
- The amount of content per message body segment
+ The amount of content per message body segment
(attachment) that is subjected to <b>$<a href="postconf.5.html#body_checks">body_checks</a></b> fil-
tering.
<b><a href="postconf.5.html#nested_header_checks">nested_header_checks</a></b> (default: <b>$<a href="postconf.5.html#header_checks">header_checks</a></b>)
Lookup tables with content filter rules for message
- header lines: respectively, these are applied to
- the initial message headers (not including MIME
- headers), to the MIME headers anywhere in the mes-
- sage, and to the initial headers of attached mes-
+ header lines: respectively, these are applied to
+ the initial message headers (not including MIME
+ headers), to the MIME headers anywhere in the mes-
+ sage, and to the initial headers of attached mes-
sages.
- Note: these filters see one logical message header
- at a time, even when a message header spans multi-
- ple lines. Message headers that are longer than
+ Note: these filters see one logical message header
+ at a time, even when a message header spans multi-
+ ple lines. Message headers that are longer than
<b>$<a href="postconf.5.html#header_size_limit">header_size_limit</a></b> characters are truncated.
<b><a href="postconf.5.html#disable_mime_input_processing">disable_mime_input_processing</a></b>
- While receiving mail, give no special treatment to
- MIME related message headers; all text after the
+ While receiving mail, give no special treatment to
+ MIME related message headers; all text after the
initial message headers is considered to be part of
- the message body. This means that <b><a href="postconf.5.html#header_checks">header_checks</a></b> is
- applied to all the initial message headers, and
+ the message body. This means that <b><a href="postconf.5.html#header_checks">header_checks</a></b> is
+ applied to all the initial message headers, and
that <b><a href="postconf.5.html#body_checks">body_checks</a></b> is applied to the remainder of the
message.
- Note: when used in this manner, <b><a href="postconf.5.html#body_checks">body_checks</a></b> will
- process a multi-line message header one line at a
+ Note: when used in this manner, <b><a href="postconf.5.html#body_checks">body_checks</a></b> will
+ process a multi-line message header one line at a
time.
<b>EXAMPLES</b>
- Header pattern to block attachments with bad file name
+ Header pattern to block attachments with bad file name
extensions.
/etc/postfix/main.cf:
<a href="BACKSCATTER_README.html">BACKSCATTER_README</a>, blocking returned forged mail
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>
(default: 10)</b></DT><DD>
<p> When SMTP connection caching is enabled, the number of times that
-an SMTP session is reused before it is closed.
+an SMTP session may be reused before it is closed.
</p>
-<p> This feature is available in Postfix 2.2 and later. </p>
+<p> This feature is available in Postfix 2.2. In Postfix 2.3 it is
+replaced by $<a href="postconf.5.html#smtp_connection_reuse_time_limit">smtp_connection_reuse_time_limit</a>.</p>
</DD>
<p> This feature is available in Postfix 2.2 and later. </p>
+</DD>
+
+<DT><b><a name="smtp_connection_reuse_time_limit">smtp_connection_reuse_time_limit</a>
+(default: 300s)</b></DT><DD>
+
+<p> The amount of time during which Postfix will use an SMTP
+connection repeatedly. The timer starts when the connection is
+initiated (i.e. it includes the connect, greeting and helo latency,
+in addition to the latencies of subsequent mail delivery transactions).
+</p>
+
+<p> This feature addresses a performance stability problem with
+remote SMTP servers. This problem is not specific to Postfix: it
+can happen when any MTA sends large amounts of SMTP email to a site
+that has multiple MX hosts. </p>
+
+<p> The problem starts when one of a set of MX hosts becomes slower
+than the rest. Even though SMTP clients connect to fast and slow
+MX hosts with equal probability, the slow MX host ends up with more
+simultaneous inbound connections than the faster MX hosts, because
+the slow MX host needs more time to serve each client request. </p>
+
+<p> The slow MX host becomes a connection attractor. If one MX
+host becomes N times slower than the rest, it dominates mail delivery
+latency unless there are more than N fast MX hosts to counter the
+effect. And if the number of MX hosts is smaller than N, the mail
+delivery latency becomes effectively that of the slowest MX host
+divided by the total number of MX hosts. </p>
+
+<p> The solution uses connection caching in a way that differs from
+Postfix 2.2. By limiting the amount of time during which a connection
+can be used repeatedly (instead of limiting the number of deliveries
+over that connection), Postfix not only restores fairness in the
+distribution of simultaneous connections across a set of MX hosts,
+it also favors deliveries over connections that perform well, which
+is exactly what we want. </p>
+
+<p> The default reuse time limit, 300s, is comparable to the various
+smtp transaction timeouts which are fair estimates of maximum excess
+latency for a slow delivery. Note that hosts may accept thousands
+of messages over a single connection within the default connection
+reuse time limit. This number is much larger than the default Postfix
+2.2 limit of 10 messages per cached connection. It may prove necessary
+to lower the limit to avoid interoperability issues with MTAs that
+exhibit bugs when many messages are delivered via a single connection.
+A lower reuse time limit risks losing the benefit of connection
+reuse when the average connection and mail delivery latency exceeds
+the reuse time limit. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
</DD>
<DT><b><a name="smtp_data_done_timeout">smtp_data_done_timeout</a>
Reject the specified commands with a hard (5xx)
error code. This option implies <b>-p</b>.
- Examples of commands are HELO, EHLO, LHLO, MAIL,
- RCPT, VRFY, DATA, ., RSET, NOOP, and QUIT. Separate
- command names by white space or commas, and use
- quotes to protect white space from the shell. Com-
- mand names are case-insensitive.
+ Examples of commands are CONNECT, HELO, EHLO, LHLO,
+ MAIL, RCPT, VRFY, DATA, ., RSET, NOOP, and QUIT.
+ Separate command names by white space or commas,
+ and use quotes to protect white space from the
+ shell. Command names are case-insensitive.
<b>-F</b> Disable XFORWARD support.
Disconnect (without replying) after receiving one
of the specified commands.
- Examples of commands are HELO, EHLO, LHLO, MAIL,
- RCPT, VRFY, DATA, ., RSET, NOOP, and QUIT. Separate
- command names by white space or commas, and use
- quotes to protect white space from the shell. Com-
- mand names are case-insensitive.
+ Examples of commands are CONNECT, HELO, EHLO, LHLO,
+ MAIL, RCPT, VRFY, DATA, ., RSET, NOOP, and QUIT.
+ Separate command names by white space or commas,
+ and use quotes to protect white space from the
+ shell. Command names are case-insensitive.
<b>-r</b> <i>command,command,...</i>
Reject the specified commands with a soft (4xx)
error code. This option implies <b>-p</b>.
- Examples of commands are HELO, EHLO, LHLO, MAIL,
- RCPT, VRFY, DATA, ., RSET, NOOP, and QUIT. Separate
- command names by white space or commas, and use
- quotes to protect white space from the shell. Com-
- mand names are case-insensitive.
+ Examples of commands are CONNECT, HELO, EHLO, LHLO,
+ MAIL, RCPT, VRFY, DATA, ., RSET, NOOP, and QUIT.
+ Separate command names by white space or commas,
+ and use quotes to protect white space from the
+ shell. Command names are case-insensitive.
<b>-s</b> <i>command,command,...</i>
Log the named commands to syslogd.
- Examples of commands are HELO, EHLO, LHLO, MAIL,
- RCPT, VRFY, DATA, ., RSET, NOOP, and QUIT. Separate
- command names by white space or commas, and use
- quotes to protect white space from the shell. Com-
- mand names are case-insensitive.
+ Examples of commands are CONNECT, HELO, EHLO, LHLO,
+ MAIL, RCPT, VRFY, DATA, ., RSET, NOOP, and QUIT.
+ Separate command names by white space or commas,
+ and use quotes to protect white space from the
+ shell. Command names are case-insensitive.
<b>-t</b> <i>timeout</i> (default: 100)
Limit the time for receiving a command or sending a
destination has a high volume of mail in the active
queue.
- <b><a href="postconf.5.html#smtp_connection_cache_reuse_limit">smtp_connection_cache_reuse_limit</a> (10)</b>
- When SMTP connection caching is enabled, the number
- of times that an SMTP session is reused before it
- is closed.
+ <b><a href="postconf.5.html#smtp_connection_reuse_time_limit">smtp_connection_reuse_time_limit</a> (300s)</b>
+ The amount of time during which Postfix will use an
+ SMTP connection repeatedly.
<b><a href="postconf.5.html#smtp_connection_cache_time_limit">smtp_connection_cache_time_limit</a> (2s)</b>
When SMTP connection caching is enabled, the amount
- of time that an unused SMTP client socket is kept
+ of time that an unused SMTP client socket is kept
open before it is closed.
<b>TROUBLE SHOOTING CONTROLS</b>
<b><a href="postconf.5.html#debug_peer_level">debug_peer_level</a> (2)</b>
- The increment in verbose logging level when a
- remote client or server matches a pattern in the
+ The increment in verbose logging level when a
+ remote client or server matches a pattern in the
<a href="postconf.5.html#debug_peer_list">debug_peer_list</a> parameter.
<b><a href="postconf.5.html#debug_peer_list">debug_peer_list</a> (empty)</b>
- Optional list of remote client or server hostname
- or network address patterns that cause the verbose
- logging level to increase by the amount specified
+ Optional list of remote client or server hostname
+ or network address patterns that cause the verbose
+ logging level to increase by the amount specified
in $<a href="postconf.5.html#debug_peer_level">debug_peer_level</a>.
<b><a href="postconf.5.html#error_notice_recipient">error_notice_recipient</a> (postmaster)</b>
- The recipient of postmaster notifications about
- mail delivery problems that are caused by policy,
+ The recipient of postmaster notifications about
+ mail delivery problems that are caused by policy,
resource, software or protocol errors.
<b><a href="postconf.5.html#notify_classes">notify_classes</a> (resource, software)</b>
- The list of error classes that are reported to the
+ The list of error classes that are reported to the
postmaster.
<b>MISCELLANEOUS CONTROLS</b>
<b><a href="postconf.5.html#best_mx_transport">best_mx_transport</a> (empty)</b>
- Where the Postfix SMTP client should deliver mail
+ Where the Postfix SMTP client should deliver mail
when it detects a "mail loops back to myself" error
condition.
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
- The default location of the Postfix main.cf and
+ The default location of the Postfix main.cf and
master.cf configuration files.
<b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
- How much time a Postfix daemon process may take to
- handle a request before it is terminated by a
+ How much time a Postfix daemon process may take to
+ handle a request before it is terminated by a
built-in watchdog timer.
<b><a href="postconf.5.html#disable_dns_lookups">disable_dns_lookups</a> (no)</b>
- Disable DNS lookups in the Postfix SMTP and LMTP
+ Disable DNS lookups in the Postfix SMTP and LMTP
clients.
<b><a href="postconf.5.html#fallback_relay">fallback_relay</a> (empty)</b>
- Optional list of relay hosts for SMTP destinations
+ Optional list of relay hosts for SMTP destinations
that can't be found or that are unreachable.
<b><a href="postconf.5.html#inet_interfaces">inet_interfaces</a> (all)</b>
tem receives mail on.
<b><a href="postconf.5.html#inet_protocols">inet_protocols</a> (ipv4)</b>
- The Internet protocols Postfix will attempt to use
+ The Internet protocols Postfix will attempt to use
when making or accepting connections.
<b><a href="postconf.5.html#ipc_timeout">ipc_timeout</a> (3600s)</b>
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 waits for the next service request
+ The maximum amount of time that an idle Postfix
+ daemon process waits for the next service request
before exiting.
<b><a href="postconf.5.html#max_use">max_use</a> (100)</b>
- The maximal number of connection requests before a
+ The maximal number of connection requests before a
Postfix daemon process terminates.
<b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
- The process ID of a Postfix command or daemon
+ The process ID of a Postfix command or daemon
process.
<b><a href="postconf.5.html#process_name">process_name</a> (read-only)</b>
- The process name of a Postfix command or daemon
+ The process name of a Postfix command or daemon
process.
<b><a href="postconf.5.html#proxy_interfaces">proxy_interfaces</a> (empty)</b>
The network interface addresses that this mail sys-
- tem receives mail on by way of a proxy or network
+ tem receives mail on by way of a proxy or network
address translation unit.
<b><a href="postconf.5.html#smtp_bind_address">smtp_bind_address</a> (empty)</b>
An optional numerical network address that the SMTP
- client should bind to when making an IPv4 connec-
+ client should bind to when making an IPv4 connec-
tion.
<b><a href="postconf.5.html#smtp_bind_address6">smtp_bind_address6</a> (empty)</b>
An optional numerical network address that the SMTP
- client should bind to when making an IPv6 connec-
+ client should bind to when making an IPv6 connec-
tion.
<b><a href="postconf.5.html#smtp_helo_name">smtp_helo_name</a> ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
- The hostname to send in the SMTP EHLO or HELO com-
+ The hostname to send in the SMTP EHLO or HELO com-
mand.
<b><a href="postconf.5.html#smtp_host_lookup">smtp_host_lookup</a> (dns)</b>
- What mechanisms when the SMTP client uses to look
+ What mechanisms when the SMTP client uses to look
up a host's IP address.
<b><a href="postconf.5.html#smtp_randomize_addresses">smtp_randomize_addresses</a> (yes)</b>
- Randomize the order of equal-preference MX host
+ Randomize the order of equal-preference MX host
addresses.
<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> (postfix)</b>
- The mail system name that is prepended to the
- process name in syslog records, so that "smtpd"
+ The mail system name that is prepended to the
+ process name in syslog records, so that "smtpd"
becomes, for example, "postfix/smtpd".
<b>SEE ALSO</b>
<a href="TLS_README.html">TLS_README</a>, Postfix STARTTLS howto
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>
;;
FreeBSD.5*) SYSTYPE=FREEBSD5
;;
+ FreeBSD.6*) SYSTYPE=FREEBSD6
+ ;;
OpenBSD.2*) SYSTYPE=OPENBSD2
;;
OpenBSD.3*) SYSTYPE=OPENBSD3
# Snapshot only.
CCARGS="$CCARGS -DSNAPSHOT"
-# Non-production, i.e. needs thorough testing.
+# Non-production: needs thorough testing, or major changes are still
+# needed before the code stabilizes.
#CCARGS="$CCARGS -DNONPROD"
sed 's/ / /g' <<EOF
Reject the specified commands with a hard (5xx) error code.
This option implies \fB-p\fR.
.sp
-Examples of commands are HELO, EHLO, LHLO, MAIL, RCPT, VRFY,
+Examples of commands are CONNECT, HELO, EHLO, LHLO, MAIL, RCPT, VRFY,
DATA, ., RSET, NOOP, and QUIT. Separate command names by
white space or commas, and use quotes to protect white space
from the shell. Command names are case-insensitive.
Disconnect (without replying) after receiving one of the
specified commands.
.sp
-Examples of commands are HELO, EHLO, LHLO, MAIL, RCPT, VRFY,
+Examples of commands are CONNECT, HELO, EHLO, LHLO, MAIL, RCPT, VRFY,
DATA, ., RSET, NOOP, and QUIT. Separate command names by
white space or commas, and use quotes to protect white space
from the shell. Command names are case-insensitive.
Reject the specified commands with a soft (4xx) error code.
This option implies \fB-p\fR.
.sp
-Examples of commands are HELO, EHLO, LHLO, MAIL, RCPT, VRFY,
+Examples of commands are CONNECT, HELO, EHLO, LHLO, MAIL, RCPT, VRFY,
DATA, ., RSET, NOOP, and QUIT. Separate command names by
white space or commas, and use quotes to protect white space
from the shell. Command names are case-insensitive.
.IP "\fB-s \fIcommand,command,...\fR"
Log the named commands to syslogd.
.sp
-Examples of commands are HELO, EHLO, LHLO, MAIL, RCPT, VRFY,
+Examples of commands are CONNECT, HELO, EHLO, LHLO, MAIL, RCPT, VRFY,
DATA, ., RSET, NOOP, and QUIT. Separate command names by
white space or commas, and use quotes to protect white space
from the shell. Command names are case-insensitive.
message.
.sp
Note: this action currently affects all recipients of the message.
+To discard only one recipient without discarding the entire message,
+use the transport(5) table to direct mail to the discard(8) service.
.sp
This feature is available in Postfix 2.0 and later.
.IP \fBDUNNO\fR
.sp
Note: this action disables further header or body_checks inspection
of the current message and affects all recipients.
+To discard only one recipient without discarding the entire message,
+use the transport(5) table to direct mail to the discard(8) service.
.sp
This feature is available in Postfix 2.0 and later.
.IP \fBDUNNO\fR
This feature is available in Postfix 2.2 and later.
.SH smtp_connection_cache_reuse_limit (default: 10)
When SMTP connection caching is enabled, the number of times that
-an SMTP session is reused before it is closed.
+an SMTP session may be reused before it is closed.
.PP
-This feature is available in Postfix 2.2 and later.
+This feature is available in Postfix 2.2. In Postfix 2.3 it is
+replaced by $smtp_connection_reuse_time_limit.
.SH smtp_connection_cache_time_limit (default: 2s)
When SMTP connection caching is enabled, the amount of time that
an unused SMTP client socket is kept open before it is closed. Do
not specify larger values without permission from the remote sites.
.PP
This feature is available in Postfix 2.2 and later.
+.SH smtp_connection_reuse_time_limit (default: 300s)
+The amount of time during which Postfix will use an SMTP
+connection repeatedly. The timer starts when the connection is
+initiated (i.e. it includes the connect, greeting and helo latency,
+in addition to the latencies of subsequent mail delivery transactions).
+.PP
+This feature addresses a performance stability problem with
+remote SMTP servers. This problem is not specific to Postfix: it
+can happen when any MTA sends large amounts of SMTP email to a site
+that has multiple MX hosts.
+.PP
+The problem starts when one of a set of MX hosts becomes slower
+than the rest. Even though SMTP clients connect to fast and slow
+MX hosts with equal probability, the slow MX host ends up with more
+simultaneous inbound connections than the faster MX hosts, because
+the slow MX host needs more time to serve each client request.
+.PP
+The slow MX host becomes a connection attractor. If one MX
+host becomes N times slower than the rest, it dominates mail delivery
+latency unless there are more than N fast MX hosts to counter the
+effect. And if the number of MX hosts is smaller than N, the mail
+delivery latency becomes effectively that of the slowest MX host
+divided by the total number of MX hosts.
+.PP
+The solution uses connection caching in a way that differs from
+Postfix 2.2. By limiting the amount of time during which a connection
+can be used repeatedly (instead of limiting the number of deliveries
+over that connection), Postfix not only restores fairness in the
+distribution of simultaneous connections across a set of MX hosts,
+it also favors deliveries over connections that perform well, which
+is exactly what we want.
+.PP
+The default reuse time limit, 300s, is comparable to the various
+smtp transaction timeouts which are fair estimates of maximum excess
+latency for a slow delivery. Note that hosts may accept thousands
+of messages over a single connection within the default connection
+reuse time limit. This number is much larger than the default Postfix
+2.2 limit of 10 messages per cached connection. It may prove necessary
+to lower the limit to avoid interoperability issues with MTAs that
+exhibit bugs when many messages are delivered via a single connection.
+A lower reuse time limit risks losing the benefit of connection
+reuse when the average connection and mail delivery latency exceeds
+the reuse time limit.
+.PP
+This feature is available in Postfix 2.3 and later.
.SH smtp_data_done_timeout (default: 600s)
The SMTP client time limit for sending the SMTP ".", and for receiving
the server response.
.IP "\fBsmtp_connection_cache_on_demand (yes)\fR"
Temporarily enable SMTP connection caching while a destination
has a high volume of mail in the active queue.
-.IP "\fBsmtp_connection_cache_reuse_limit (10)\fR"
-When SMTP connection caching is enabled, the number of times that
-an SMTP session is reused before it is closed.
+.IP "\fBsmtp_connection_reuse_time_limit (300s)\fR"
+The amount of time during which Postfix will use an SMTP
+connection repeatedly.
.IP "\fBsmtp_connection_cache_time_limit (2s)\fR"
When SMTP connection caching is enabled, the amount of time that
an unused SMTP client socket is kept open before it is closed.
s;\bsmtp_connection_cache_on_demand\b;<a href="postconf.5.html#smtp_connection_cache_on_demand">$&</a>;g;
s;\bsmtp_connection_cache_reuse_limit\b;<a href="postconf.5.html#smtp_connection_cache_reuse_limit">$&</a>;g;
+ s;\bsmtp_connection_reuse_time_limit\b;<a href="postconf.5.html#smtp_connection_reuse_time_limit">$&</a>;g;
s;\bsmtp_connection_cache_time_limit\b;<a href="postconf.5.html#smtp_connection_cache_time_limit">$&</a>;g;
s;\bsmtp_connection_cache_destinations\b;<a href="postconf.5.html#smtp_connection_cache_destinations">$&</a>;g;
certificates issued by these CAs, append the root certificate to
$smtpd_tls_CAfile or install it in the $smtpd_tls_CApath directory. When
you configure trust in a root CA, it is not necessary to explicitly trust
-intermediary CAs signed by the root CA, unless $smtpd_tls_verify_depth
+intermediary CAs signed by the root CA, unless $smtpd_tls_ccert_verifydepth
is less than the number of CAs in the certificate chain for the clients
of interest. With a verify depth of 1 you can only verify certificates
directly signed by a trusted CA, and all trusted intermediary CAs need to
accessible inside the optional chroot jail. </p>
<p> When you configure Postfix to request client certificates (by
-setting $smtpd_tls_asck_ccert = yes), any certificates in
+setting $smtpd_tls_ask_ccert = yes), any certificates in
$smtpd_tls_CAfile are sent to the client, in order to allow it to
choose an identity signed by a CA you trust. If no $smtpd_tls_CAfile
is specified, no preferred CA list is sent, and the client is free
# message.
# .sp
# Note: this action currently affects all recipients of the message.
+# To discard only one recipient without discarding the entire message,
+# use the transport(5) table to direct mail to the discard(8) service.
# .sp
# This feature is available in Postfix 2.0 and later.
# .IP \fBDUNNO\fR
# .sp
# Note: this action disables further header or body_checks inspection
# of the current message and affects all recipients.
+# To discard only one recipient without discarding the entire message,
+# use the transport(5) table to direct mail to the discard(8) service.
# .sp
# This feature is available in Postfix 2.0 and later.
# .IP \fBDUNNO\fR
%PARAM smtp_connection_cache_reuse_limit 10
<p> When SMTP connection caching is enabled, the number of times that
-an SMTP session is reused before it is closed.
-</p>
-
-<p> This feature is available in Postfix 2.2 and later. </p>
+an SMTP session may be reused before it is closed.
+</p>
+
+<p> This feature is available in Postfix 2.2. In Postfix 2.3 it is
+replaced by $smtp_connection_reuse_time_limit.</p>
+
+%PARAM smtp_connection_reuse_time_limit 300s
+
+<p> The amount of time during which Postfix will use an SMTP
+connection repeatedly. The timer starts when the connection is
+initiated (i.e. it includes the connect, greeting and helo latency,
+in addition to the latencies of subsequent mail delivery transactions).
+</p>
+
+<p> This feature addresses a performance stability problem with
+remote SMTP servers. This problem is not specific to Postfix: it
+can happen when any MTA sends large amounts of SMTP email to a site
+that has multiple MX hosts. </p>
+
+<p> The problem starts when one of a set of MX hosts becomes slower
+than the rest. Even though SMTP clients connect to fast and slow
+MX hosts with equal probability, the slow MX host ends up with more
+simultaneous inbound connections than the faster MX hosts, because
+the slow MX host needs more time to serve each client request. </p>
+
+<p> The slow MX host becomes a connection attractor. If one MX
+host becomes N times slower than the rest, it dominates mail delivery
+latency unless there are more than N fast MX hosts to counter the
+effect. And if the number of MX hosts is smaller than N, the mail
+delivery latency becomes effectively that of the slowest MX host
+divided by the total number of MX hosts. </p>
+
+<p> The solution uses connection caching in a way that differs from
+Postfix 2.2. By limiting the amount of time during which a connection
+can be used repeatedly (instead of limiting the number of deliveries
+over that connection), Postfix not only restores fairness in the
+distribution of simultaneous connections across a set of MX hosts,
+it also favors deliveries over connections that perform well, which
+is exactly what we want. </p>
+
+<p> The default reuse time limit, 300s, is comparable to the various
+smtp transaction timeouts which are fair estimates of maximum excess
+latency for a slow delivery. Note that hosts may accept thousands
+of messages over a single connection within the default connection
+reuse time limit. This number is much larger than the default Postfix
+2.2 limit of 10 messages per cached connection. It may prove necessary
+to lower the limit to avoid interoperability issues with MTAs that
+exhibit bugs when many messages are delivered via a single connection.
+A lower reuse time limit risks losing the benefit of connection
+reuse when the average connection and mail delivery latency exceeds
+the reuse time limit. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
%PARAM smtp_connection_cache_destinations
bounce.o: ../../include/mail_queue.h
bounce.o: ../../include/mail_server.h
bounce.o: ../../include/msg.h
+bounce.o: ../../include/msg_stats.h
bounce.o: ../../include/rcpt_buf.h
bounce.o: ../../include/recipient_list.h
bounce.o: ../../include/stringops.h
bounce_notify_service.o: ../../include/mail_params.h
bounce_notify_service.o: ../../include/mail_queue.h
bounce_notify_service.o: ../../include/msg.h
+bounce_notify_service.o: ../../include/msg_stats.h
bounce_notify_service.o: ../../include/name_mask.h
bounce_notify_service.o: ../../include/post_mail.h
bounce_notify_service.o: ../../include/rcpt_buf.h
bounce_notify_verp.o: ../../include/mail_params.h
bounce_notify_verp.o: ../../include/mail_queue.h
bounce_notify_verp.o: ../../include/msg.h
+bounce_notify_verp.o: ../../include/msg_stats.h
bounce_notify_verp.o: ../../include/name_mask.h
bounce_notify_verp.o: ../../include/post_mail.h
bounce_notify_verp.o: ../../include/rcpt_buf.h
bounce_one_service.o: ../../include/mail_error.h
bounce_one_service.o: ../../include/mail_params.h
bounce_one_service.o: ../../include/msg.h
+bounce_one_service.o: ../../include/msg_stats.h
bounce_one_service.o: ../../include/name_mask.h
bounce_one_service.o: ../../include/post_mail.h
bounce_one_service.o: ../../include/rcpt_buf.h
bounce_trace_service.o: ../../include/mail_params.h
bounce_trace_service.o: ../../include/mail_queue.h
bounce_trace_service.o: ../../include/msg.h
+bounce_trace_service.o: ../../include/msg_stats.h
bounce_trace_service.o: ../../include/name_mask.h
bounce_trace_service.o: ../../include/post_mail.h
bounce_trace_service.o: ../../include/rcpt_buf.h
cleanup_api.o: ../../include/match_ops.h
cleanup_api.o: ../../include/mime_state.h
cleanup_api.o: ../../include/msg.h
+cleanup_api.o: ../../include/msg_stats.h
cleanup_api.o: ../../include/mymalloc.h
cleanup_api.o: ../../include/nvtable.h
cleanup_api.o: ../../include/recipient_list.h
cleanup_bounce.o: ../../include/match_ops.h
cleanup_bounce.o: ../../include/mime_state.h
cleanup_bounce.o: ../../include/msg.h
+cleanup_bounce.o: ../../include/msg_stats.h
cleanup_bounce.o: ../../include/mymalloc.h
cleanup_bounce.o: ../../include/nvtable.h
cleanup_bounce.o: ../../include/rec_type.h
cleanup_out_recipient.o: ../../include/match_ops.h
cleanup_out_recipient.o: ../../include/mime_state.h
cleanup_out_recipient.o: ../../include/msg.h
+cleanup_out_recipient.o: ../../include/msg_stats.h
cleanup_out_recipient.o: ../../include/mymalloc.h
cleanup_out_recipient.o: ../../include/nvtable.h
cleanup_out_recipient.o: ../../include/rec_type.h
*/
extern int cleanup_bounce(CLEANUP_STATE *);
+ /*
+ * MSG_STATS compatibility.
+ */
+#define CLEANUP_MSG_STATS(stats, state) \
+ MSG_STATS_INIT1(stats, incoming_arrival, state->time)
+
/* LICENSE
/* .ad
/* .fi
static void cleanup_bounce_append(CLEANUP_STATE *state, RECIPIENT *rcpt,
DSN *dsn)
{
- if (bounce_append(BOUNCE_FLAG_CLEAN, state->queue_id, state->time,
+ MSG_STATS stats;
+
+ if (bounce_append(BOUNCE_FLAG_CLEAN, state->queue_id,
+ CLEANUP_MSG_STATS(&stats, state),
rcpt, "none", dsn) != 0) {
msg_warn("%s: bounce logfile update error", state->queue_id);
state->errs |= CLEANUP_STAT_WRITE;
#include <trace.h>
#include <mail_queue.h> /* cleanup_trace_path */
#include <mail_proto.h>
+#include <msg_stats.h>
/* Application-specific. */
static void cleanup_trace_append(CLEANUP_STATE *state, RECIPIENT *rcpt,
DSN *dsn)
{
+ MSG_STATS stats;
+
if (cleanup_trace_path == 0) {
cleanup_trace_path = vstring_alloc(10);
mail_queue_path(cleanup_trace_path, MAIL_QUEUE_TRACE,
state->queue_id);
}
- if (trace_append(BOUNCE_FLAG_CLEAN, state->queue_id, state->time,
+ if (trace_append(BOUNCE_FLAG_CLEAN, state->queue_id,
+ CLEANUP_MSG_STATS(&stats, state),
rcpt, "none", dsn) != 0) {
msg_warn("%s: trace logfile update error", state->queue_id);
state->errs |= CLEANUP_STAT_WRITE;
@$(EXPORT) make -f Makefile.in Makefile 1>&2
# do not edit below this line - it is generated by 'make depend'
+discard.o: ../../include/attr.h
discard.o: ../../include/bounce.h
discard.o: ../../include/deliver_completed.h
discard.o: ../../include/deliver_request.h
discard.o: ../../include/mail_queue.h
discard.o: ../../include/mail_server.h
discard.o: ../../include/msg.h
+discard.o: ../../include/msg_stats.h
discard.o: ../../include/recipient_list.h
discard.o: ../../include/sent.h
discard.o: ../../include/sys_defs.h
rcpt = request->rcpt_list.info + nrcpt;
if (rcpt->offset >= 0) {
status = sent(BOUNCE_FLAGS(request), request->queue_id,
- request->arrival_time, rcpt, "none", &dsn);
+ &request->msg_stats, rcpt, "none", &dsn);
if (status == 0 && (request->flags & DEL_REQ_FLAG_SUCCESS))
deliver_completed(src, rcpt->offset);
result |= status;
@$(EXPORT) make -f Makefile.in Makefile 1>&2
# do not edit below this line - it is generated by 'make depend'
+error.o: ../../include/attr.h
error.o: ../../include/bounce.h
error.o: ../../include/deliver_completed.h
error.o: ../../include/deliver_request.h
error.o: ../../include/mail_queue.h
error.o: ../../include/mail_server.h
error.o: ../../include/msg.h
+error.o: ../../include/msg_stats.h
error.o: ../../include/recipient_list.h
error.o: ../../include/sys_defs.h
error.o: ../../include/sys_exits.h
rcpt = request->rcpt_list.info + nrcpt;
if (rcpt->offset >= 0) {
status = bounce_append(BOUNCE_FLAGS(request), request->queue_id,
- request->arrival_time, rcpt, "none",
+ &request->msg_stats, rcpt, "none",
&dsn);
if (status == 0)
deliver_completed(src, rcpt->offset);
ehlo_mask.c \
wildcard_inet_addr.c valid_mailhost_addr.c dsn_util.c dsn_mask.c \
dsn_attr_map.c dsn.c dsn_buf.c rcpt_buf.c rcpt_print.c dsn_print.c \
- dsb_scan.c mail_conf_long.c
+ dsb_scan.c mail_conf_long.c msg_stats_print.c msg_stats_scan.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 debug_peer.o debug_process.o defer.o db_common.o \
ehlo_mask.o \
wildcard_inet_addr.o valid_mailhost_addr.o dsn_util.o dsn_mask.o \
dsn_attr_map.o dsn.o dsn_buf.o rcpt_buf.o rcpt_print.o dsn_print.o \
- dsb_scan.o mail_conf_long.o
+ dsb_scan.o mail_conf_long.o msg_stats_print.o msg_stats_scan.o
HDRS = abounce.h anvil_clnt.h been_here.h bounce.h bounce_log.h \
canon_addr.h cfg_parser.h cleanup_user.h clnt_stream.h config.h \
debug_peer.h debug_process.h defer.h deliver_completed.h \
xtext.h scache.h user_acl.h ehlo_mask.h db_common.h \
wildcard_inet_addr.h valid_mailhost_addr.h dsn_util.h dsn_mask.h \
dsn_attr_map.h dsn.h dsn_buf.h rcpt_buf.h rcpt_print.h dsn_print.h \
- dsb_scan.h
+ dsb_scan.h msg_stats.h
TESTSRC = rec2stream.c stream2rec.c recdump.c
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
CFLAGS = $(DEBUG) $(OPT) $(DEFS)
abounce.o: dsn_buf.h
abounce.o: mail_params.h
abounce.o: mail_proto.h
+abounce.o: msg_stats.h
abounce.o: recipient_list.h
anvil_clnt.o: ../../include/attr.h
anvil_clnt.o: ../../include/attr_clnt.h
bounce.o: log_adhoc.h
bounce.o: mail_params.h
bounce.o: mail_proto.h
+bounce.o: msg_stats.h
bounce.o: rcpt_print.h
bounce.o: recipient_list.h
bounce.o: trace.h
defer.o: mail_params.h
defer.o: mail_proto.h
defer.o: mail_queue.h
+defer.o: msg_stats.h
defer.o: rcpt_print.h
defer.o: recipient_list.h
defer.o: trace.h
deliver_pass.o: dsn_buf.h
deliver_pass.o: mail_params.h
deliver_pass.o: mail_proto.h
+deliver_pass.o: msg_stats.h
deliver_pass.o: recipient_list.h
deliver_request.o: ../../include/attr.h
deliver_request.o: ../../include/iostuff.h
deliver_request.o: mail_open_ok.h
deliver_request.o: mail_proto.h
deliver_request.o: mail_queue.h
+deliver_request.o: msg_stats.h
deliver_request.o: recipient_list.h
dict_ldap.o: ../../include/argv.h
dict_ldap.o: ../../include/binhash.h
is_header.o: ../../include/sys_defs.h
is_header.o: is_header.c
is_header.o: is_header.h
+log_adhoc.o: ../../include/attr.h
log_adhoc.o: ../../include/msg.h
log_adhoc.o: ../../include/sys_defs.h
log_adhoc.o: ../../include/vbuf.h
+log_adhoc.o: ../../include/vstream.h
log_adhoc.o: ../../include/vstring.h
log_adhoc.o: dsn.h
log_adhoc.o: dsn_buf.h
log_adhoc.o: log_adhoc.c
log_adhoc.o: log_adhoc.h
+log_adhoc.o: msg_stats.h
log_adhoc.o: recipient_list.h
mail_addr.o: ../../include/stringops.h
mail_addr.o: ../../include/sys_defs.h
maps.o: mail_conf.h
maps.o: maps.c
maps.o: maps.h
+mark_corrupt.o: ../../include/attr.h
mark_corrupt.o: ../../include/msg.h
mark_corrupt.o: ../../include/set_eugid.h
mark_corrupt.o: ../../include/sys_defs.h
mark_corrupt.o: mail_queue.h
mark_corrupt.o: mark_corrupt.c
mark_corrupt.o: mark_corrupt.h
+mark_corrupt.o: msg_stats.h
mark_corrupt.o: recipient_list.h
match_parent_style.o: ../../include/match_list.h
match_parent_style.o: ../../include/match_ops.h
mkmap_sdbm.o: ../../include/vstring.h
mkmap_sdbm.o: mkmap.h
mkmap_sdbm.o: mkmap_sdbm.c
+msg_stats_print.o: ../../include/attr.h
+msg_stats_print.o: ../../include/iostuff.h
+msg_stats_print.o: ../../include/sys_defs.h
+msg_stats_print.o: ../../include/vbuf.h
+msg_stats_print.o: ../../include/vstream.h
+msg_stats_print.o: mail_proto.h
+msg_stats_print.o: msg_stats.h
+msg_stats_print.o: msg_stats_print.c
+msg_stats_scan.o: ../../include/attr.h
+msg_stats_scan.o: ../../include/iostuff.h
+msg_stats_scan.o: ../../include/msg.h
+msg_stats_scan.o: ../../include/sys_defs.h
+msg_stats_scan.o: ../../include/vbuf.h
+msg_stats_scan.o: ../../include/vstream.h
+msg_stats_scan.o: ../../include/vstring.h
+msg_stats_scan.o: mail_proto.h
+msg_stats_scan.o: msg_stats.h
+msg_stats_scan.o: msg_stats_scan.c
mynetworks.o: ../../include/argv.h
mynetworks.o: ../../include/inet_addr_list.h
mynetworks.o: ../../include/mask_addr.h
scache_single.o: ../../include/vstring.h
scache_single.o: scache.h
scache_single.o: scache_single.c
+sent.o: ../../include/attr.h
sent.o: ../../include/msg.h
sent.o: ../../include/sys_defs.h
sent.o: ../../include/vbuf.h
sent.o: dsn_util.h
sent.o: log_adhoc.h
sent.o: mail_params.h
+sent.o: msg_stats.h
sent.o: recipient_list.h
sent.o: sent.c
sent.o: sent.h
trace.o: log_adhoc.h
trace.o: mail_params.h
trace.o: mail_proto.h
+trace.o: msg_stats.h
trace.o: rcpt_print.h
trace.o: recipient_list.h
trace.o: trace.c
verify.o: log_adhoc.h
verify.o: mail_params.h
verify.o: mail_proto.h
+verify.o: msg_stats.h
verify.o: recipient_list.h
verify.o: verify.c
verify.o: verify.h
verify_clnt.o: dsn_buf.h
verify_clnt.o: mail_params.h
verify_clnt.o: mail_proto.h
+verify_clnt.o: msg_stats.h
verify_clnt.o: recipient_list.h
verify_clnt.o: verify_clnt.c
verify_clnt.o: verify_clnt.h
/* SYNOPSIS
/* #include <bounce.h>
/*
-/* int bounce_append(flags, id, entry, recipient, relay, dsn)
+/* int bounce_append(flags, id, stats, recipient, relay, dsn)
/* int flags;
/* const char *id;
-/* time_t entry;
+/* MSG_STATS *stats;
/* RECIPIENT *rcpt;
/* const char *relay;
/* DSN *dsn;
/* const char *verp_delims;
/*
/* int bounce_one(flags, queue, id, encoding, sender, envid, ret,
-/* entry, recipient, relay, dsn)
+/* stats, recipient, relay, dsn)
/* int flags;
/* const char *queue;
/* const char *id;
/* const char *sender;
/* const char *dsn_envid;
/* int dsn_ret;
-/* time_t entry;
+/* MSG_STATS *stats;
/* RECIPIENT *rcpt;
/* const char *relay;
/* DSN *dsn;
/* .IP id
/* The message queue id if the original message file. The bounce log
/* file has the same name as the original message file.
-/* .IP entry
-/* Message arrival time.
+/* .IP stats
+/* Time stamps from different message delivery stages
+/* and session reuse count.
/* .IP rcpt
/* Recipient information. See recipient_list(3).
/* .IP relay
/* bounce_append - append dsn_text to per-message bounce log */
-int bounce_append(int flags, const char *id, time_t entry,
+int bounce_append(int flags, const char *id, MSG_STATS *stats,
RECIPIENT *rcpt, const char *relay,
DSN *dsn)
{
*/
if (flags & DEL_REQ_FLAG_MTA_VRFY) {
my_dsn.action = "undeliverable";
- status = verify_append(id, entry, rcpt, relay, &my_dsn,
+ status = verify_append(id, stats, rcpt, relay, &my_dsn,
DEL_RCPT_STAT_BOUNCE);
return (status);
}
*/
if (flags & DEL_REQ_FLAG_USR_VRFY) {
my_dsn.action = "undeliverable";
- status = trace_append(flags, id, entry, rcpt, relay, &my_dsn);
+ status = trace_append(flags, id, stats, rcpt, relay, &my_dsn);
return (status);
}
ATTR_TYPE_FUNC, dsn_print, (void *) &my_dsn,
ATTR_TYPE_END) == 0
&& ((flags & DEL_REQ_FLAG_RECORD) == 0
- || trace_append(flags, id, entry, rcpt, relay,
+ || trace_append(flags, id, stats, rcpt, relay,
&my_dsn) == 0)) {
- log_adhoc(id, entry, rcpt, relay, &my_dsn, log_status);
+ log_adhoc(id, stats, rcpt, relay, &my_dsn, log_status);
status = (var_soft_bounce ? -1 : 0);
} else if ((flags & BOUNCE_FLAG_CLEAN) == 0) {
VSTRING *junk = vstring_alloc(100);
vstring_sprintf(junk, "%s or %s service failure",
var_bounce_service, var_trace_service);
my_dsn.reason = vstring_str(junk);
- status = defer_append(flags, id, entry, rcpt, relay, &my_dsn);
+ status = defer_append(flags, id, stats, rcpt, relay, &my_dsn);
vstring_free(junk);
} else {
status = -1;
int bounce_one(int flags, const char *queue, const char *id,
const char *encoding, const char *sender,
const char *dsn_envid, int dsn_ret,
- time_t entry, RECIPIENT *rcpt,
+ MSG_STATS *stats, RECIPIENT *rcpt,
const char *relay, DSN *dsn)
{
DSN my_dsn = *dsn;
*/
if (flags & DEL_REQ_FLAG_MTA_VRFY) {
my_dsn.action = "undeliverable";
- status = verify_append(id, entry, rcpt, relay, &my_dsn,
+ status = verify_append(id, stats, rcpt, relay, &my_dsn,
DEL_RCPT_STAT_BOUNCE);
return (status);
}
*/
if (flags & DEL_REQ_FLAG_USR_VRFY) {
my_dsn.action = "undeliverable";
- status = trace_append(flags, id, entry, rcpt, relay, &my_dsn);
+ status = trace_append(flags, id, stats, rcpt, relay, &my_dsn);
return (status);
}
* based procedure.
*/
else if (var_soft_bounce) {
- return (bounce_append(flags, id, entry, rcpt, relay, &my_dsn));
+ return (bounce_append(flags, id, stats, rcpt, relay, &my_dsn));
}
/*
ATTR_TYPE_FUNC, dsn_print, (void *) &my_dsn,
ATTR_TYPE_END) == 0
&& ((flags & DEL_REQ_FLAG_RECORD) == 0
- || trace_append(flags, id, entry, rcpt, relay,
+ || trace_append(flags, id, stats, rcpt, relay,
&my_dsn) == 0)) {
- log_adhoc(id, entry, rcpt, relay, &my_dsn, "bounced");
+ log_adhoc(id, stats, rcpt, relay, &my_dsn, "bounced");
status = 0;
} else if ((flags & BOUNCE_FLAG_CLEAN) == 0) {
VSTRING *junk = vstring_alloc(100);
vstring_sprintf(junk, "%s or %s service failure",
var_bounce_service, var_trace_service);
my_dsn.reason = vstring_str(junk);
- status = defer_append(flags, id, entry, rcpt, relay, &my_dsn);
+ status = defer_append(flags, id, stats, rcpt, relay, &my_dsn);
vstring_free(junk);
} else {
status = -1;
/*
* Client interface.
*/
-extern int bounce_append(int, const char *, time_t, RECIPIENT *,
+extern int bounce_append(int, const char *, MSG_STATS *, RECIPIENT *,
const char *, DSN *);
extern int bounce_flush(int, const char *, const char *, const char *,
const char *, const char *, int);
const char *, const char *, int, const char *);
extern int bounce_one(int, const char *, const char *, const char *,
const char *, const char *,
- int, time_t, RECIPIENT *,
+ int, MSG_STATS *, RECIPIENT *,
const char *, DSN *);
/*
/* SYNOPSIS
/* #include <defer.h>
/*
-/* int defer_append(flags, id, entry, rcpt, relay, dsn)
+/* int defer_append(flags, id, stats, rcpt, relay, dsn)
/* int flags;
/* const char *id;
-/* time_t entry;
+/* MSG_STATS *stats;
/* RECIPIENT *rcpt;
/* const char *relay;
/* DSN *dsn;
/* The message queue name of the original message file.
/* .IP id
/* The queue id of the original message file.
-/* .IP entry
-/* Message arrival time.
+/* .IP stats
+/* Time stamps from different message delivery stages
+/* and session reuse count.
/* .IP rcpt
/* Recipient information. See recipient_list(3).
/* .IP relay
/* defer_append - defer message delivery */
-int defer_append(int flags, const char *id, time_t entry,
+int defer_append(int flags, const char *id, MSG_STATS *stats,
RECIPIENT *rcpt, const char *relay,
DSN *dsn)
{
*/
if (flags & DEL_REQ_FLAG_MTA_VRFY) {
my_dsn.action = "undeliverable";
- status = verify_append(id, entry, rcpt, relay, &my_dsn,
+ status = verify_append(id, stats, rcpt, relay, &my_dsn,
DEL_RCPT_STAT_DEFER);
return (status);
}
*/
if (flags & DEL_REQ_FLAG_USR_VRFY) {
my_dsn.action = "undeliverable";
- status = trace_append(flags, id, entry, rcpt, relay, &my_dsn);
+ status = trace_append(flags, id, stats, rcpt, relay, &my_dsn);
return (status);
}
ATTR_TYPE_FUNC, dsn_print, (void *) &my_dsn,
ATTR_TYPE_END) != 0)
msg_warn("%s: %s service failure", id, var_defer_service);
- log_adhoc(id, entry, rcpt, relay, &my_dsn, "deferred");
+ log_adhoc(id, stats, rcpt, relay, &my_dsn, "deferred");
/*
* Traced delivery.
*/
if (flags & DEL_REQ_FLAG_RECORD)
- if (trace_append(flags, id, entry, rcpt, relay, &my_dsn) != 0)
+ if (trace_append(flags, id, stats, rcpt, relay, &my_dsn) != 0)
msg_warn("%s: %s service failure", id, var_trace_service);
/*
/*
* External interface.
*/
-extern int defer_append(int, const char *, time_t, RECIPIENT *,
+extern int defer_append(int, const char *, MSG_STATS *, RECIPIENT *,
const char *, DSN *);
extern int defer_flush(int, const char *, const char *, const char *,
const char *, const char *, int);
ATTR_TYPE_STR, MAIL_ATTR_SENDER, request->sender,
ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, request->dsn_envid,
ATTR_TYPE_NUM, MAIL_ATTR_DSN_RET, request->dsn_ret,
- ATTR_TYPE_LONG, MAIL_ATTR_TIME, request->arrival_time,
+ ATTR_TYPE_FUNC, msg_stats_print, (void *) &request->msg_stats,
ATTR_TYPE_STR, MAIL_ATTR_CLIENT_NAME, request->client_name,
ATTR_TYPE_STR, MAIL_ATTR_CLIENT_ADDR, request->client_addr,
ATTR_TYPE_STR, MAIL_ATTR_PROTO_NAME, request->client_proto,
/* char *nexthop;
/* char *encoding;
/* char *sender;
-/* long arrival_time;
+/* MSG_STATS stats;
/* RECIPIENT_LIST rcpt_list;
/* DSN *hop_status;
/* char *client_name;
ATTR_TYPE_STR, MAIL_ATTR_SENDER, address,
ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, dsn_envid,
ATTR_TYPE_NUM, MAIL_ATTR_DSN_RET, &dsn_ret,
- ATTR_TYPE_LONG, MAIL_ATTR_TIME, &request->arrival_time,
+ ATTR_TYPE_FUNC, msg_stats_scan, (void *) &request->msg_stats,
ATTR_TYPE_STR, MAIL_ATTR_CLIENT_NAME, client_name,
ATTR_TYPE_STR, MAIL_ATTR_CLIENT_ADDR, client_addr,
ATTR_TYPE_STR, MAIL_ATTR_PROTO_NAME, client_proto,
vstring_str(queue_id), &st, &path) == 0)
return (-1);
+ /* Don't override hand-off time after deliver_pass() delegation. */
+ if (request->msg_stats.agent_handoff.tv_sec == 0)
+ GETTIMEOFDAY(&request->msg_stats.agent_handoff);
+
request->queue_name = mystrdup(vstring_str(queue_name));
request->queue_id = mystrdup(vstring_str(queue_id));
request->nexthop = mystrdup(vstring_str(nexthop));
*/
#include <recipient_list.h>
#include <dsn.h>
+#include <msg_stats.h>
/*
* Structure of a server mail delivery request.
char *nexthop; /* next hop name */
char *encoding; /* content encoding */
char *sender; /* envelope sender */
- long arrival_time; /* arrival time */
+ MSG_STATS msg_stats; /* time profile */
RECIPIENT_LIST rcpt_list; /* envelope recipients */
DSN *hop_status; /* DSN status */
char *client_name; /* client hostname */
/* SYNOPSIS
/* #include <log_adhoc.h>
/*
-/* void log_adhoc(id, entry, recipient, relay, dsn, status)
+/* void log_adhoc(id, stats, recipient, relay, dsn, status)
/* const char *id;
-/* time_t entry;
+/* MSG_STATS *stats;
/* RECIPIENT *recipient;
/* const char *relay;
/* DSN *dsn;
/* The message queue name of the original message file.
/* .IP id
/* The queue id of the original message file.
-/* .IP entry
-/* Message arrival time.
+/* .IP stats
+/* Time stamps from different message delivery stages
+/* and session reuse count.
/* .IP recipient
/* Recipient information. See recipient_list(3).
/* .IP sender
#include <log_adhoc.h>
-/* log_adhoc - defer message delivery */
+/* log_adhoc - ad-hoc logging */
-void log_adhoc(const char *id, time_t entry, RECIPIENT *recipient,
+void log_adhoc(const char *id, MSG_STATS *stats, RECIPIENT *recipient,
const char *relay, DSN *dsn,
const char *status)
{
- int delay = time((time_t *) 0) - entry;
+ static VSTRING *buf;
+ int delay;
+ int pdelay; /* time before queue manager */
+ struct timeval adelay; /* queue manager latency */
+ struct timeval sdelay; /* connection set-up latency */
+ struct timeval xdelay; /* transmission latency */
+ struct timeval now;
+ /*
+ * Alas, we need an intermediate buffer for the pre-formatted result.
+ * There are several optional fields, and we want to tweak some
+ * formatting depending on delay values.
+ */
+ if (buf == 0)
+ buf = vstring_alloc(100);
+
+ /*
+ * First, general information that identifies the transaction.
+ */
+ vstring_sprintf(buf, "%s: to=<%s>", id, recipient->address);
if (recipient->orig_addr && *recipient->orig_addr
&& strcasecmp(recipient->address, recipient->orig_addr) != 0)
- msg_info("%s: to=<%s>, orig_to=<%s>, relay=%s, delay=%d, dsn=%s, status=%s (%s)",
- id, recipient->address, recipient->orig_addr, relay, delay,
- dsn->status, status, dsn->reason);
+ vstring_sprintf_append(buf, ", orig_to=<%s>", recipient->orig_addr);
+ vstring_sprintf_append(buf, ", relay=%s", relay);
+
+ /*
+ * Next, performance statistics.
+ *
+ * Use wall clock time to compute pdelay (before active queue latency) if
+ * there is no time stamp for active queue entry. This happens when mail
+ * is bounced by the cleanup server.
+ *
+ * Otherwise, use wall clock time to compute adelay (active queue latency)
+ * if there is no time stamp for hand-off to delivery agent. This happens
+ * when mail was deferred or bounced by the queue manager.
+ *
+ * Otherwise, use wall clock time to compute xdelay (message transfer
+ * latency) if there is no time stamp for delivery completion. In the
+ * case of multi-recipient deliveries the delivery agent may specify the
+ * delivery completion time, so that multiple recipient records show the
+ * same delay values.
+ *
+ * Don't compute the sdelay (connection setup latency) if there is no time
+ * stamp for connection setup completion.
+ *
+ * Instead of floating point, use integer math where practical.
+ */
+#define DELTA(x, y, z) \
+ do { \
+ (x).tv_sec = (y).tv_sec - (z).tv_sec; \
+ (x).tv_usec = (y).tv_usec - (z).tv_usec; \
+ if ((x).tv_usec < 0) { \
+ (x).tv_usec += 1000000; \
+ (x).tv_sec -= 1; \
+ } \
+ if ((x).tv_sec < 0) \
+ (x).tv_sec = (x).tv_usec = 0; \
+ } while (0)
+
+ if (stats->deliver_done.tv_sec)
+ now = stats->deliver_done;
else
- msg_info("%s: to=<%s>, relay=%s, delay=%d, dsn=%s, status=%s (%s)",
- id, recipient->address, relay, delay, dsn->status,
- status, dsn->reason);
+ GETTIMEOFDAY(&now);
+ delay = now.tv_sec - stats->incoming_arrival;
+ adelay.tv_sec = adelay.tv_usec =
+ sdelay.tv_sec = sdelay.tv_usec =
+ xdelay.tv_sec = xdelay.tv_usec = 0;
+ if (stats->active_arrival.tv_sec) {
+ pdelay = stats->active_arrival.tv_sec - stats->incoming_arrival;
+ if (stats->agent_handoff.tv_sec) {
+ DELTA(adelay, stats->agent_handoff, stats->active_arrival);
+ if (stats->conn_setup_done.tv_sec) {
+ DELTA(sdelay, stats->conn_setup_done, stats->agent_handoff);
+ DELTA(xdelay, now, stats->conn_setup_done);
+ } else {
+ /* Non-network delivery agent. */
+ DELTA(xdelay, now, stats->agent_handoff);
+ }
+ } else {
+ /* No delivery agent. */
+ DELTA(adelay, now, stats->active_arrival);
+ }
+ } else {
+ /* No queue manager. */
+ pdelay = now.tv_sec - stats->incoming_arrival;
+ }
+ if (stats->reuse_count > 0)
+ vstring_sprintf_append(buf, ", conn_use=%d", stats->reuse_count + 1);
+
+#define PRETTY_FORMAT(b, x) \
+ do { \
+ if ((x).tv_sec > 0 || (x).tv_usec < 10000) { \
+ vstring_sprintf_append((b), "/%ld", (long) (x).tv_sec); \
+ } else { \
+ vstring_sprintf_append((b), "/%.1g", \
+ (x).tv_sec + (x).tv_usec / 1000000.0); \
+ } \
+ } while (0)
+
+ vstring_sprintf_append(buf, ", delay=%d, delays=%d", delay, pdelay);
+ PRETTY_FORMAT(buf, adelay);
+ PRETTY_FORMAT(buf, sdelay);
+ PRETTY_FORMAT(buf, xdelay);
+
+ /*
+ * Finally, the delivery status.
+ */
+ vstring_sprintf_append(buf, ", dsn=%s, status=%s (%s)",
+ dsn->status, status, dsn->reason);
+
+ /*
+ * Ship it off.
+ */
+ msg_info("%s", vstring_str(buf));
}
*/
#include <recipient_list.h>
#include <dsn.h>
+#include <msg_stats.h>
/*
* Client interface.
*/
-extern void log_adhoc(const char *, time_t, RECIPIENT *, const char *,
+extern void log_adhoc(const char *, MSG_STATS *, RECIPIENT *, const char *,
DSN *, const char *);
/* LICENSE
#define DEF_SMTP_CACHE_CONN "2s"
extern int var_smtp_cache_conn;
-#define VAR_SMTP_REUSE_LIMIT "smtp_connection_cache_reuse_limit"
-#define DEF_SMTP_REUSE_LIMIT 10
-extern int var_smtp_reuse_limit;
+#define VAR_SMTP_REUSE_TIME "smtp_connection_reuse_time_limit"
+#define DEF_SMTP_REUSE_TIME "300s"
+extern int var_smtp_reuse_time;
#define VAR_SMTP_CACHE_DEST "smtp_connection_cache_destinations"
#define DEF_SMTP_CACHE_DEST ""
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20051014"
+#define MAIL_RELEASE_DATE "20051103"
#define MAIL_VERSION_NUMBER "2.3"
#ifdef SNAPSHOT
--- /dev/null
+#ifndef _MSG_STATS_H_INCLUDED_
+#define _MSG_STATS_H_INCLUDED_
+
+/*++
+/* NAME
+/* msg_stats 3h
+/* SUMMARY
+/* message delivery profiling
+/* SYNOPSIS
+/* #include <msg_stats.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * System library.
+ */
+#include <sys/time.h>
+#include <time.h>
+#include <string.h>
+
+ /*
+ * Utility library.
+ */
+#include <attr.h>
+#include <vstream.h>
+
+ /*
+ * External interface.
+ *
+ * This structure contains the time stamps from various mail delivery stages,
+ * as well as the connection reuse count. The time stamps provide additional
+ * insight into the nature of performance bottle necks.
+ *
+ * For convenience, we record absolute time stamps instead of time differences.
+ * This is because the decision of what numbers to subtract actually depends
+ * on program history. Since we prefer to compute time differences in one
+ * place, we postpone this task until the end, in log_adhoc().
+ *
+ * A zero time stamp or reuse count means the information is not supplied.
+ *
+ * Specifically, a zero active_arrival value means that the message did not
+ * reach the queue manager; and a zero agent_handoff time means that the
+ * queue manager did not give the message to a delivery agent.
+ *
+ * Some network clients update the conn_setup_done value when connection setup
+ * fails or completes.
+ *
+ * The deliver_done value is usually left at zero, which means use the wall
+ * clock time when reporting recipient status information. The exception is
+ * with delivery agents that can deliver multiple recipients in a single
+ * transaction. These agents explicitly update the deliver_done time stamp
+ * to ensure that multiple recipient records show the exact same delay
+ * values.
+ */
+typedef struct {
+ time_t incoming_arrival; /* incoming queue entry */
+ struct timeval active_arrival; /* active queue entry */
+ struct timeval agent_handoff; /* delivery agent hand-off */
+ struct timeval conn_setup_done; /* connection set-up done */
+ struct timeval deliver_done; /* transmission done */
+ int reuse_count; /* connection reuse count */
+} MSG_STATS;
+
+#define MSG_STATS_INIT(st) \
+ ( \
+ memset((char *) (st), 0, sizeof(*(st))), \
+ (st) \
+ )
+
+#define MSG_STATS_INIT1(st, member, value) \
+ ( \
+ memset((char *) (st), 0, sizeof(*(st))), \
+ ((st)->member = (value)), \
+ (st) \
+ )
+
+#define MSG_STATS_INIT2(st, m1, v1, m2, v2) \
+ ( \
+ memset((char *) (st), 0, sizeof(*(st))), \
+ ((st)->m1 = (v1)), \
+ ((st)->m2 = (v2)), \
+ (st) \
+ )
+
+extern int msg_stats_scan(ATTR_SCAN_MASTER_FN, VSTREAM *, int, void *);
+extern int msg_stats_print(ATTR_PRINT_MASTER_FN, VSTREAM *, int, void *);
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+#endif
--- /dev/null
+/*++
+/* NAME
+/* msg_stats_print
+/* SUMMARY
+/* write MSG_STATS structure to stream
+/* SYNOPSIS
+/* #include <msg_stats_print.h>
+/*
+/* int msg_stats_print(print_fn, stream, flags, ptr)
+/* ATTR_PRINT_MASTER_FN print_fn;
+/* VSTREAM *stream;
+/* int flags;
+/* void *ptr;
+/* DESCRIPTION
+/* msg_stats_print() writes a MSG_STATS structure to the named stream using
+/* the specified attribute print routine. msg_stats_print() is meant
+/* to be passed as a call-back to attr_print(), thusly:
+/*
+/* ... ATTR_PRINT_FUNC, msg_stats_print, (void *) stats, ...
+/* DIAGNOSTICS
+/* Fatal: out of memory.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+
+/* Utility library. */
+
+#include <attr.h>
+
+/* Global library. */
+
+#include <mail_proto.h>
+#include <msg_stats.h>
+
+/* msg_stats_print - write MSG_STATS to stream */
+
+int msg_stats_print(ATTR_PRINT_MASTER_FN print_fn, VSTREAM *fp,
+ int flags, void *ptr)
+{
+ int ret;
+
+ /*
+ * Send the entire structure. This is not only simpler but also likely to
+ * be quicker than having the sender figure out what fields need to be
+ * sent, converting numbers to string and back, and having the receiver
+ * initialize the unused fields by hand.
+ */
+ ret = print_fn(fp, flags | ATTR_FLAG_MORE,
+ ATTR_TYPE_DATA, MAIL_ATTR_TIME, sizeof(MSG_STATS), ptr,
+ ATTR_TYPE_END);
+ return (ret);
+}
--- /dev/null
+/*++
+/* NAME
+/* msg_stats_scan
+/* SUMMARY
+/* read MSG_STATS from stream
+/* SYNOPSIS
+/* #include <msg_stats.h>
+/*
+/* int msg_stats_scan(scan_fn, stream, flags, ptr)
+/* ATTR_SCAN_MASTER_FN scan_fn;
+/* VSTREAM *stream;
+/* int flags;
+/* void *ptr;
+/* DESCRIPTION
+/* msg_stats_scan() reads a MSG_STATS from the named stream using the
+/* specified attribute scan routine. msg_stats_scan() is meant
+/* to be passed as a call-back to attr_scan(), thusly:
+/*
+/* ... ATTR_SCAN_FUNC, msg_stats_scan, (void *) &stats, ...
+/* DIAGNOSTICS
+/* Fatal: out of memory.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+
+/* Utility library. */
+
+#include <attr.h>
+#include <vstring.h>
+#include <msg.h>
+
+/* Global library. */
+
+#include <mail_proto.h>
+#include <msg_stats.h>
+
+ /*
+ * SLMs.
+ */
+#define STR(x) vstring_str(x)
+#define LEN(x) VSTRING_LEN(x)
+
+/* msg_stats_scan - read MSG_STATS from stream */
+
+int msg_stats_scan(ATTR_SCAN_MASTER_FN scan_fn, VSTREAM *fp,
+ int flags, void *ptr)
+{
+ MSG_STATS *stats = (MSG_STATS *) ptr;
+ VSTRING *buf = vstring_alloc(sizeof(MSG_STATS) * 2);
+ int ret;
+
+ /*
+ * Receive the entire structure. This is not only simpler but also likely
+ * to be quicker than having the sender figure out what fields need to be
+ * sent, converting those numbers to string and back, and having the
+ * receiver initialize the unused fields by hand.
+ *
+ * XXX Would be nice if VSTRINGs could import a fixed-size buffer and
+ * gracefully reject attempts to extend it.
+ */
+ ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
+ ATTR_TYPE_DATA, MAIL_ATTR_TIME, buf,
+ ATTR_TYPE_END);
+ if (ret == 1) {
+ if (LEN(buf) == sizeof(*stats)) {
+ memcpy((char *) stats, STR(buf), sizeof(*stats));
+ } else {
+ msg_warn("msg_stats_scan: size mis-match: %u != %u",
+ (unsigned) LEN(buf), (unsigned) sizeof(*stats));
+ ret = (-1);
+ }
+ }
+ vstring_free(buf);
+ return (ret);
+}
/* ... ATTR_PRINT_FUNC, rcpt_print, (void *) recipient, ...
/* DIAGNOSTICS
/* Fatal: out of memory.
-/* LICENSE .ad .fi
+/* LICENSE
+/* .ad
+/* .fi
/* The Secure Mailer license must be distributed with this
/* software.
/* AUTHOR(S)
/* SYNOPSIS
/* #include <sent.h>
/*
-/* int sent(flags, queue_id, entry, recipient, relay, dsn)
+/* int sent(flags, queue_id, stats, recipient, relay, dsn)
/* int flags;
/* const char *queue_id;
-/* time_t entry;
+/* MSG_STATS *stats;
/* RECIPIENT *recipient;
/* const char *relay;
/* DSN *dsn;
/* the message delivery record.
/* .RE .IP queue_id
/* The message queue id.
-/* .IP entry
-/* Message arrival time.
+/* .IP stats
+/* Time stamps from different message delivery stages
+/* and session reuse count.
/* .IP recipient
/* Recipient information. See recipient_list(3).
/* .IP relay
/* sent - log that a message was or could be sent */
-int sent(int flags, const char *id, time_t entry,
+int sent(int flags, const char *id, MSG_STATS *stats,
RECIPIENT *recipient, const char *relay,
DSN *dsn)
{
*/
if (flags & DEL_REQ_FLAG_MTA_VRFY) {
my_dsn.action = "deliverable";
- status = verify_append(id, entry, recipient, relay, &my_dsn,
+ status = verify_append(id, stats, recipient, relay, &my_dsn,
DEL_RCPT_STAT_OK);
return (status);
}
*/
if (flags & DEL_REQ_FLAG_USR_VRFY) {
my_dsn.action = "deliverable";
- status = trace_append(flags, id, entry, recipient, relay, &my_dsn);
+ status = trace_append(flags, id, stats, recipient, relay, &my_dsn);
return (status);
}
my_dsn.action = "delivered";
if (((flags & DEL_REQ_FLAG_RECORD) == 0
- || trace_append(flags, id, entry, recipient, relay, &my_dsn) == 0)
+ || trace_append(flags, id, stats, recipient, relay, &my_dsn) == 0)
&& ((recipient->dsn_notify & DSN_NOTIFY_SUCCESS) == 0
- || trace_append(flags, id, entry, recipient, relay, &my_dsn) == 0)) {
- log_adhoc(id, entry, recipient, relay, &my_dsn, "sent");
+ || trace_append(flags, id, stats, recipient, relay, &my_dsn) == 0)) {
+ log_adhoc(id, stats, recipient, relay, &my_dsn, "sent");
status = 0;
} else {
VSTRING *junk = vstring_alloc(100);
id, var_trace_service);
my_dsn.reason = vstring_str(junk);
my_dsn.status ="4.3.0";
- status = defer_append(flags, id, entry, recipient, relay, &my_dsn);
+ status = defer_append(flags, id, stats, recipient, relay, &my_dsn);
vstring_free(junk);
}
return (status);
*/
#define SENT_FLAG_NONE (0)
-extern int sent(int, const char *, time_t, RECIPIENT *, const char *,
+extern int sent(int, const char *, MSG_STATS *, RECIPIENT *, const char *,
DSN *);
/* LICENSE
/* SYNOPSIS
/* #include <trace.h>
/*
-/* int trace_append(flags, id, entry, rcpt, relay, dsn)
+/* int trace_append(flags, id, stats, rcpt, relay, dsn)
/* int flags;
/* const char *id;
-/* time_t entry;
+/* MSG_STATS *stats;
/* RECIPIENT *rcpt;
/* const char *relay;
/* DSN *dsn;
/* Optional DSN envelope ID.
/* .IP dsn_ret
/* Optional DSN return full/headers option.
-/* .IP entry
-/* Message arrival time.
+/* .IP stats
+/* Time stamps from different message delivery stages
+/* and session reuse count.
/* .IP rcpt
/* Recipient information. See recipient_list(3).
/* .IP relay
/* trace_append - append to message delivery record */
-int trace_append(int flags, const char *id, time_t entry,
+int trace_append(int flags, const char *id, MSG_STATS *stats,
RECIPIENT *rcpt, const char *relay,
DSN *dsn)
{
req_stat = -1;
} else {
if (flags & DEL_REQ_FLAG_USR_VRFY)
- log_adhoc(id, entry, rcpt, relay, dsn, my_dsn.action);
+ log_adhoc(id, stats, rcpt, relay, dsn, my_dsn.action);
req_stat = 0;
}
vstring_free(why);
/*
* External interface.
*/
-extern int trace_append(int, const char *, time_t, RECIPIENT *,
+extern int trace_append(int, const char *, MSG_STATS *, RECIPIENT *,
const char *, DSN *);
extern int trace_flush(int, const char *, const char *, const char *,
const char *, const char *, int);
/* SYNOPSIS
/* #include <verify.h>
/*
-/* int verify_append(queue_id, entry, recipient, relay, dsn,
+/* int verify_append(queue_id, stats, recipient, relay, dsn,
/* verify_status)
/* const char *queue_id;
-/* time_t entry;
+/* MSG_STATS *stats;
/* RECIPIENT *recipient;
/* const char *relay;
/* DSN *dsn;
/* Arguments:
/* .IP queue_id
/* The message queue id.
-/* .IP entry
-/* Message arrival time.
+/* .IP stats
+/* Time stamps from different message delivery stages
+/* and session reuse count.
/* .IP recipient
/* Recipient information. See recipient_list(3).
/* .IP relay
/* verify_append - update address verification database */
-int verify_append(const char *queue_id, time_t entry,
+int verify_append(const char *queue_id, MSG_STATS *stats,
RECIPIENT *recipient, const char *relay,
DSN *dsn, int vrfy_stat)
{
req_stat = VRFY_STAT_OK;
}
if (req_stat == VRFY_STAT_OK) {
- log_adhoc(queue_id, entry, recipient, relay, dsn, my_dsn.action);
+ log_adhoc(queue_id, stats, recipient, relay, dsn, my_dsn.action);
req_stat = 0;
} else {
msg_warn("%s: %s service failure", queue_id, var_verify_service);
/*
* External interface.
*/
-extern int verify_append(const char *, time_t, RECIPIENT *,
+extern int verify_append(const char *, MSG_STATS *, RECIPIENT *,
const char *, DSN *, int);
/* LICENSE
# do not edit below this line - it is generated by 'make depend'
lmtp.o: ../../include/argv.h
+lmtp.o: ../../include/attr.h
lmtp.o: ../../include/debug_peer.h
lmtp.o: ../../include/deliver_request.h
lmtp.o: ../../include/dict.h
lmtp.o: ../../include/mail_queue.h
lmtp.o: ../../include/mail_server.h
lmtp.o: ../../include/msg.h
+lmtp.o: ../../include/msg_stats.h
lmtp.o: ../../include/mymalloc.h
lmtp.o: ../../include/name_mask.h
lmtp.o: ../../include/recipient_list.h
lmtp.o: lmtp.h
lmtp.o: lmtp_sasl.h
lmtp_addr.o: ../../include/argv.h
+lmtp_addr.o: ../../include/attr.h
lmtp_addr.o: ../../include/deliver_request.h
lmtp_addr.o: ../../include/dns.h
lmtp_addr.o: ../../include/dsn.h
lmtp_addr.o: ../../include/inet_proto.h
lmtp_addr.o: ../../include/mail_params.h
lmtp_addr.o: ../../include/msg.h
+lmtp_addr.o: ../../include/msg_stats.h
lmtp_addr.o: ../../include/myaddrinfo.h
lmtp_addr.o: ../../include/mymalloc.h
lmtp_addr.o: ../../include/own_inet_addr.h
lmtp_addr.o: lmtp_addr.c
lmtp_addr.o: lmtp_addr.h
lmtp_chat.o: ../../include/argv.h
+lmtp_chat.o: ../../include/attr.h
lmtp_chat.o: ../../include/cleanup_user.h
lmtp_chat.o: ../../include/deliver_request.h
lmtp_chat.o: ../../include/dsn.h
lmtp_chat.o: ../../include/mail_error.h
lmtp_chat.o: ../../include/mail_params.h
lmtp_chat.o: ../../include/msg.h
+lmtp_chat.o: ../../include/msg_stats.h
lmtp_chat.o: ../../include/mymalloc.h
lmtp_chat.o: ../../include/name_mask.h
lmtp_chat.o: ../../include/post_mail.h
lmtp_connect.o: ../../include/mail_params.h
lmtp_connect.o: ../../include/mail_proto.h
lmtp_connect.o: ../../include/msg.h
+lmtp_connect.o: ../../include/msg_stats.h
lmtp_connect.o: ../../include/myaddrinfo.h
lmtp_connect.o: ../../include/mymalloc.h
lmtp_connect.o: ../../include/own_inet_addr.h
lmtp_connect.o: lmtp_addr.h
lmtp_connect.o: lmtp_connect.c
lmtp_dsn.o: ../../include/argv.h
+lmtp_dsn.o: ../../include/attr.h
lmtp_dsn.o: ../../include/deliver_request.h
lmtp_dsn.o: ../../include/dsn.h
lmtp_dsn.o: ../../include/dsn_buf.h
+lmtp_dsn.o: ../../include/msg_stats.h
lmtp_dsn.o: ../../include/recipient_list.h
lmtp_dsn.o: ../../include/sys_defs.h
lmtp_dsn.o: ../../include/vbuf.h
lmtp_proto.o: ../../include/mail_queue.h
lmtp_proto.o: ../../include/mark_corrupt.h
lmtp_proto.o: ../../include/msg.h
+lmtp_proto.o: ../../include/msg_stats.h
lmtp_proto.o: ../../include/mymalloc.h
lmtp_proto.o: ../../include/name_code.h
lmtp_proto.o: ../../include/off_cvt.h
lmtp_proto.o: lmtp_proto.c
lmtp_proto.o: lmtp_sasl.h
lmtp_rcpt.o: ../../include/argv.h
+lmtp_rcpt.o: ../../include/attr.h
lmtp_rcpt.o: ../../include/bounce.h
lmtp_rcpt.o: ../../include/deliver_completed.h
lmtp_rcpt.o: ../../include/deliver_request.h
lmtp_rcpt.o: ../../include/dsn_buf.h
lmtp_rcpt.o: ../../include/dsn_mask.h
lmtp_rcpt.o: ../../include/msg.h
+lmtp_rcpt.o: ../../include/msg_stats.h
lmtp_rcpt.o: ../../include/recipient_list.h
lmtp_rcpt.o: ../../include/sent.h
lmtp_rcpt.o: ../../include/sys_defs.h
lmtp_rcpt.o: lmtp.h
lmtp_rcpt.o: lmtp_rcpt.c
lmtp_sasl_glue.o: ../../include/argv.h
+lmtp_sasl_glue.o: ../../include/attr.h
lmtp_sasl_glue.o: ../../include/deliver_request.h
lmtp_sasl_glue.o: ../../include/dict.h
lmtp_sasl_glue.o: ../../include/dsn.h
lmtp_sasl_glue.o: ../../include/match_list.h
lmtp_sasl_glue.o: ../../include/match_ops.h
lmtp_sasl_glue.o: ../../include/msg.h
+lmtp_sasl_glue.o: ../../include/msg_stats.h
lmtp_sasl_glue.o: ../../include/mymalloc.h
lmtp_sasl_glue.o: ../../include/name_mask.h
lmtp_sasl_glue.o: ../../include/recipient_list.h
lmtp_sasl_glue.o: lmtp_sasl.h
lmtp_sasl_glue.o: lmtp_sasl_glue.c
lmtp_sasl_proto.o: ../../include/argv.h
+lmtp_sasl_proto.o: ../../include/attr.h
lmtp_sasl_proto.o: ../../include/deliver_request.h
lmtp_sasl_proto.o: ../../include/dsn.h
lmtp_sasl_proto.o: ../../include/dsn_buf.h
lmtp_sasl_proto.o: ../../include/mail_params.h
lmtp_sasl_proto.o: ../../include/msg.h
+lmtp_sasl_proto.o: ../../include/msg_stats.h
lmtp_sasl_proto.o: ../../include/mymalloc.h
lmtp_sasl_proto.o: ../../include/recipient_list.h
lmtp_sasl_proto.o: ../../include/sys_defs.h
lmtp_sasl_proto.o: lmtp_sasl.h
lmtp_sasl_proto.o: lmtp_sasl_proto.c
lmtp_session.o: ../../include/argv.h
+lmtp_session.o: ../../include/attr.h
lmtp_session.o: ../../include/debug_peer.h
lmtp_session.o: ../../include/deliver_request.h
lmtp_session.o: ../../include/dsn.h
lmtp_session.o: ../../include/dsn_buf.h
+lmtp_session.o: ../../include/msg_stats.h
lmtp_session.o: ../../include/mymalloc.h
lmtp_session.o: ../../include/recipient_list.h
lmtp_session.o: ../../include/stringops.h
lmtp_session.o: lmtp.h
lmtp_session.o: lmtp_session.c
lmtp_state.o: ../../include/argv.h
+lmtp_state.o: ../../include/attr.h
lmtp_state.o: ../../include/deliver_request.h
lmtp_state.o: ../../include/dsn.h
lmtp_state.o: ../../include/dsn_buf.h
lmtp_state.o: ../../include/mail_conf.h
+lmtp_state.o: ../../include/msg_stats.h
lmtp_state.o: ../../include/mymalloc.h
lmtp_state.o: ../../include/recipient_list.h
lmtp_state.o: ../../include/sys_defs.h
lmtp_state.o: lmtp_sasl.h
lmtp_state.o: lmtp_state.c
lmtp_trouble.o: ../../include/argv.h
+lmtp_trouble.o: ../../include/attr.h
lmtp_trouble.o: ../../include/bounce.h
lmtp_trouble.o: ../../include/defer.h
lmtp_trouble.o: ../../include/deliver_completed.h
lmtp_trouble.o: ../../include/dsn_buf.h
lmtp_trouble.o: ../../include/mail_error.h
lmtp_trouble.o: ../../include/msg.h
+lmtp_trouble.o: ../../include/msg_stats.h
lmtp_trouble.o: ../../include/name_mask.h
lmtp_trouble.o: ../../include/recipient_list.h
lmtp_trouble.o: ../../include/smtp_stream.h
* Build the MAIL FROM command.
*/
case LMTP_STATE_MAIL:
+ GETTIMEOFDAY(&request->msg_stats.conn_setup_done);
REWRITE_ADDRESS(state->scratch, request->sender);
vstring_sprintf(next_command, "MAIL FROM:<%s>",
vstring_str(state->scratch));
* delivered.
*/
case LMTP_STATE_DOT:
+ GETTIMEOFDAY(&request->msg_stats.deliver_done);
if (nrcpt > 0) {
rcpt = request->rcpt_list.info + survivors[recv_dot];
if (resp->code / 100 == 2) {
resp->str, resp->str);
status = sent(DEL_REQ_TRACE_FLAGS(request->flags),
- request->queue_id, request->arrival_time, rcpt,
+ request->queue_id, &request->msg_stats, rcpt,
session->namaddr, &dsn);
if (status == 0) {
if (request->flags & DEL_REQ_FLAG_SUCCESS)
int soft_error = (dsn->dtext[0] == '4');
int nrcpt;
+ /*
+ * If we are still in the connection set-up phase, update the set-up
+ * completion time here, otherwise the time spent in set-up latency will
+ * be attributed as message transfer latency.
+ *
+ * All remaining recipients failed at this point, so we update the delivery
+ * completion time stamp so that multiple recipient status records show
+ * the same delay values.
+ */
+ if (request->msg_stats.conn_setup_done.tv_sec == 0) {
+ GETTIMEOFDAY(&request->msg_stats.conn_setup_done);
+ request->msg_stats.deliver_done =
+ request->msg_stats.conn_setup_done;
+ } else
+ GETTIMEOFDAY(&request->msg_stats.deliver_done);
+
/*
* If this is a soft error, postpone further deliveries to this domain.
* Otherwise, generate a bounce record for each recipient.
continue;
status = (soft_error ? defer_append : bounce_append)
(DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
- request->arrival_time, rcpt,
+ &request->msg_stats, rcpt,
session ? session->namaddr : "none", dsn);
if (status == 0) {
deliver_completed(state->src, rcpt->offset);
*/
status = (soft_error ? defer_append : bounce_append)
(DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
- request->arrival_time, rcpt,
+ &request->msg_stats, rcpt,
session ? session->namaddr : "none", &dsn);
if (status == 0) {
deliver_completed(state->src, rcpt->offset);
# do not edit below this line - it is generated by 'make depend'
alias.o: ../../include/argv.h
+alias.o: ../../include/attr.h
alias.o: ../../include/been_here.h
alias.o: ../../include/bounce.h
alias.o: ../../include/canon_addr.h
alias.o: ../../include/maps.h
alias.o: ../../include/mbox_conf.h
alias.o: ../../include/msg.h
+alias.o: ../../include/msg_stats.h
alias.o: ../../include/mymalloc.h
alias.o: ../../include/mypwd.h
alias.o: ../../include/recipient_list.h
biff_notify.o: biff_notify.c
biff_notify.o: biff_notify.h
command.o: ../../include/argv.h
+command.o: ../../include/attr.h
command.o: ../../include/been_here.h
command.o: ../../include/bounce.h
command.o: ../../include/defer.h
command.o: ../../include/maps.h
command.o: ../../include/mbox_conf.h
command.o: ../../include/msg.h
+command.o: ../../include/msg_stats.h
command.o: ../../include/pipe_command.h
command.o: ../../include/recipient_list.h
command.o: ../../include/resolve_clnt.h
command.o: command.c
command.o: local.h
deliver_attr.o: ../../include/argv.h
+deliver_attr.o: ../../include/attr.h
deliver_attr.o: ../../include/been_here.h
deliver_attr.o: ../../include/deliver_request.h
deliver_attr.o: ../../include/dict.h
deliver_attr.o: ../../include/maps.h
deliver_attr.o: ../../include/mbox_conf.h
deliver_attr.o: ../../include/msg.h
+deliver_attr.o: ../../include/msg_stats.h
deliver_attr.o: ../../include/recipient_list.h
deliver_attr.o: ../../include/resolve_clnt.h
deliver_attr.o: ../../include/sys_defs.h
deliver_attr.o: deliver_attr.c
deliver_attr.o: local.h
delivered.o: ../../include/argv.h
+delivered.o: ../../include/attr.h
delivered.o: ../../include/been_here.h
delivered.o: ../../include/deliver_request.h
delivered.o: ../../include/dict.h
delivered.o: ../../include/maps.h
delivered.o: ../../include/mbox_conf.h
delivered.o: ../../include/msg.h
+delivered.o: ../../include/msg_stats.h
delivered.o: ../../include/quote_822_local.h
delivered.o: ../../include/quote_flags.h
delivered.o: ../../include/rec_type.h
delivered.o: delivered.c
delivered.o: local.h
dotforward.o: ../../include/argv.h
+dotforward.o: ../../include/attr.h
dotforward.o: ../../include/been_here.h
dotforward.o: ../../include/bounce.h
dotforward.o: ../../include/deliver_request.h
dotforward.o: ../../include/maps.h
dotforward.o: ../../include/mbox_conf.h
dotforward.o: ../../include/msg.h
+dotforward.o: ../../include/msg_stats.h
dotforward.o: ../../include/mymalloc.h
dotforward.o: ../../include/mypwd.h
dotforward.o: ../../include/open_as.h
dotforward.o: dotforward.c
dotforward.o: local.h
file.o: ../../include/argv.h
+file.o: ../../include/attr.h
file.o: ../../include/been_here.h
file.o: ../../include/bounce.h
file.o: ../../include/defer.h
file.o: ../../include/mbox_conf.h
file.o: ../../include/mbox_open.h
file.o: ../../include/msg.h
+file.o: ../../include/msg_stats.h
file.o: ../../include/myflock.h
file.o: ../../include/recipient_list.h
file.o: ../../include/resolve_clnt.h
forward.o: ../../include/mark_corrupt.h
forward.o: ../../include/mbox_conf.h
forward.o: ../../include/msg.h
+forward.o: ../../include/msg_stats.h
forward.o: ../../include/mymalloc.h
forward.o: ../../include/rec_type.h
forward.o: ../../include/recipient_list.h
forward.o: forward.c
forward.o: local.h
include.o: ../../include/argv.h
+include.o: ../../include/attr.h
include.o: ../../include/been_here.h
include.o: ../../include/bounce.h
include.o: ../../include/defer.h
include.o: ../../include/maps.h
include.o: ../../include/mbox_conf.h
include.o: ../../include/msg.h
+include.o: ../../include/msg_stats.h
include.o: ../../include/mymalloc.h
include.o: ../../include/mypwd.h
include.o: ../../include/open_as.h
include.o: include.c
include.o: local.h
indirect.o: ../../include/argv.h
+indirect.o: ../../include/attr.h
indirect.o: ../../include/been_here.h
indirect.o: ../../include/bounce.h
indirect.o: ../../include/defer.h
indirect.o: ../../include/maps.h
indirect.o: ../../include/mbox_conf.h
indirect.o: ../../include/msg.h
+indirect.o: ../../include/msg_stats.h
indirect.o: ../../include/recipient_list.h
indirect.o: ../../include/resolve_clnt.h
indirect.o: ../../include/sent.h
indirect.o: indirect.c
indirect.o: local.h
local.o: ../../include/argv.h
+local.o: ../../include/attr.h
local.o: ../../include/been_here.h
local.o: ../../include/deliver_completed.h
local.o: ../../include/deliver_request.h
local.o: ../../include/maps.h
local.o: ../../include/mbox_conf.h
local.o: ../../include/msg.h
+local.o: ../../include/msg_stats.h
local.o: ../../include/mymalloc.h
local.o: ../../include/name_mask.h
local.o: ../../include/recipient_list.h
local.o: local.c
local.o: local.h
local_expand.o: ../../include/argv.h
+local_expand.o: ../../include/attr.h
local_expand.o: ../../include/been_here.h
local_expand.o: ../../include/deliver_request.h
local_expand.o: ../../include/dict.h
local_expand.o: ../../include/mail_params.h
local_expand.o: ../../include/maps.h
local_expand.o: ../../include/mbox_conf.h
+local_expand.o: ../../include/msg_stats.h
local_expand.o: ../../include/recipient_list.h
local_expand.o: ../../include/resolve_clnt.h
local_expand.o: ../../include/sys_defs.h
mailbox.o: ../../include/mbox_conf.h
mailbox.o: ../../include/mbox_open.h
mailbox.o: ../../include/msg.h
+mailbox.o: ../../include/msg_stats.h
mailbox.o: ../../include/mymalloc.h
mailbox.o: ../../include/mypwd.h
mailbox.o: ../../include/recipient_list.h
mailbox.o: local.h
mailbox.o: mailbox.c
maildir.o: ../../include/argv.h
+maildir.o: ../../include/attr.h
maildir.o: ../../include/been_here.h
maildir.o: ../../include/bounce.h
maildir.o: ../../include/defer.h
maildir.o: ../../include/mbox_conf.h
maildir.o: ../../include/mbox_open.h
maildir.o: ../../include/msg.h
+maildir.o: ../../include/msg_stats.h
maildir.o: ../../include/mymalloc.h
maildir.o: ../../include/recipient_list.h
maildir.o: ../../include/resolve_clnt.h
maildir.o: local.h
maildir.o: maildir.c
recipient.o: ../../include/argv.h
+recipient.o: ../../include/attr.h
recipient.o: ../../include/been_here.h
recipient.o: ../../include/bounce.h
recipient.o: ../../include/canon_addr.h
recipient.o: ../../include/maps.h
recipient.o: ../../include/mbox_conf.h
recipient.o: ../../include/msg.h
+recipient.o: ../../include/msg_stats.h
recipient.o: ../../include/mymalloc.h
recipient.o: ../../include/mypwd.h
recipient.o: ../../include/recipient_list.h
resolve.o: ../../include/maps.h
resolve.o: ../../include/mbox_conf.h
resolve.o: ../../include/msg.h
+resolve.o: ../../include/msg_stats.h
resolve.o: ../../include/recipient_list.h
resolve.o: ../../include/resolve_clnt.h
resolve.o: ../../include/rewrite_clnt.h
resolve.o: local.h
resolve.o: resolve.c
token.o: ../../include/argv.h
+token.o: ../../include/attr.h
token.o: ../../include/been_here.h
token.o: ../../include/bounce.h
token.o: ../../include/defer.h
token.o: ../../include/maps.h
token.o: ../../include/mbox_conf.h
token.o: ../../include/msg.h
+token.o: ../../include/msg_stats.h
token.o: ../../include/mymalloc.h
token.o: ../../include/readlline.h
token.o: ../../include/recipient_list.h
unknown.o: ../../include/maps.h
unknown.o: ../../include/mbox_conf.h
unknown.o: ../../include/msg.h
+unknown.o: ../../include/msg_stats.h
unknown.o: ../../include/mymalloc.h
unknown.o: ../../include/recipient_list.h
unknown.o: ../../include/resolve_clnt.h
state.msg_attr.dsn_envid = rqst->dsn_envid;
state.msg_attr.dsn_ret = rqst->dsn_ret;
state.msg_attr.relay = service;
- state.msg_attr.arrival_time = rqst->arrival_time;
+ state.msg_attr.msg_stats = rqst->msg_stats;
state.msg_attr.request = rqst;
RESET_OWNER_ATTR(state.msg_attr, state.level);
RESET_USER_ATTR(usr_attr, state.level);
const char *owner; /* null or list owner */
const char *delivered; /* for loop detection */
char *relay; /* relay host */
- long arrival_time; /* arrival time */
+ MSG_STATS msg_stats; /* time profile */
int exp_type; /* expansion type. see below */
char *exp_from; /* expanded_from */
DELIVER_REQUEST *request; /* the kitchen sink */
#define BOUNCE_FLAGS(request) DEL_REQ_TRACE_FLAGS((request)->flags)
#define BOUNCE_ATTR(attr) \
- attr.queue_id, attr.arrival_time, &attr.rcpt, attr.relay, \
+ attr.queue_id, &attr.msg_stats, &attr.rcpt, attr.relay, \
DSN_FROM_DSN_BUF(&attr.dsn, attr.why)
#define BOUNCE_ONE_ATTR(attr) \
attr.queue_name, attr.queue_id, attr.encoding, \
attr.sender, attr.dsn_envid, attr.dsn_ret, \
- attr.arrival_time, &attr.rcpt, attr.relay, \
+ &attr.msg_stats, &attr.rcpt, attr.relay, \
DSN_FROM_DSN_BUF(&attr.dsn, attr.why)
#define SENT_ATTR(attr) \
- attr.queue_id, attr.arrival_time, &attr.rcpt, attr.relay, \
+ attr.queue_id, &attr.msg_stats, &attr.rcpt, attr.relay, \
DSN_FROM_DSN_BUF(&attr.dsn, attr.why)
#define OPENED_ATTR(attr) \
attr.queue_id, attr.sender
qmgr.o: qmgr.c
qmgr.o: qmgr.h
qmgr_active.o: ../../include/abounce.h
+qmgr_active.o: ../../include/attr.h
qmgr_active.o: ../../include/bounce.h
qmgr_active.o: ../../include/defer.h
qmgr_active.o: ../../include/deliver_request.h
qmgr_active.o: ../../include/mail_params.h
qmgr_active.o: ../../include/mail_queue.h
qmgr_active.o: ../../include/msg.h
+qmgr_active.o: ../../include/msg_stats.h
qmgr_active.o: ../../include/mymalloc.h
qmgr_active.o: ../../include/qmgr_user.h
qmgr_active.o: ../../include/rec_type.h
qmgr_active.o: ../../include/vstring.h
qmgr_active.o: qmgr.h
qmgr_active.o: qmgr_active.c
+qmgr_bounce.o: ../../include/attr.h
qmgr_bounce.o: ../../include/bounce.h
qmgr_bounce.o: ../../include/deliver_completed.h
qmgr_bounce.o: ../../include/deliver_request.h
qmgr_bounce.o: ../../include/dsn.h
qmgr_bounce.o: ../../include/dsn_buf.h
+qmgr_bounce.o: ../../include/msg_stats.h
qmgr_bounce.o: ../../include/recipient_list.h
qmgr_bounce.o: ../../include/scan_dir.h
qmgr_bounce.o: ../../include/sys_defs.h
qmgr_bounce.o: ../../include/vstring.h
qmgr_bounce.o: qmgr.h
qmgr_bounce.o: qmgr_bounce.c
+qmgr_defer.o: ../../include/attr.h
qmgr_defer.o: ../../include/bounce.h
qmgr_defer.o: ../../include/defer.h
qmgr_defer.o: ../../include/deliver_request.h
qmgr_defer.o: ../../include/dsn.h
qmgr_defer.o: ../../include/dsn_buf.h
qmgr_defer.o: ../../include/msg.h
+qmgr_defer.o: ../../include/msg_stats.h
qmgr_defer.o: ../../include/recipient_list.h
qmgr_defer.o: ../../include/scan_dir.h
qmgr_defer.o: ../../include/sys_defs.h
qmgr_deliver.o: ../../include/mail_proto.h
qmgr_deliver.o: ../../include/mail_queue.h
qmgr_deliver.o: ../../include/msg.h
+qmgr_deliver.o: ../../include/msg_stats.h
qmgr_deliver.o: ../../include/recipient_list.h
qmgr_deliver.o: ../../include/scan_dir.h
qmgr_deliver.o: ../../include/stringops.h
qmgr_enable.o: ../../include/vstring.h
qmgr_enable.o: qmgr.h
qmgr_enable.o: qmgr_enable.c
+qmgr_entry.o: ../../include/attr.h
qmgr_entry.o: ../../include/deliver_request.h
qmgr_entry.o: ../../include/dsn.h
qmgr_entry.o: ../../include/dsn_buf.h
qmgr_entry.o: ../../include/events.h
qmgr_entry.o: ../../include/mail_params.h
qmgr_entry.o: ../../include/msg.h
+qmgr_entry.o: ../../include/msg_stats.h
qmgr_entry.o: ../../include/mymalloc.h
qmgr_entry.o: ../../include/recipient_list.h
qmgr_entry.o: ../../include/scan_dir.h
qmgr_message.o: ../../include/mail_proto.h
qmgr_message.o: ../../include/mail_queue.h
qmgr_message.o: ../../include/msg.h
+qmgr_message.o: ../../include/msg_stats.h
qmgr_message.o: ../../include/myflock.h
qmgr_message.o: ../../include/mymalloc.h
qmgr_message.o: ../../include/opened.h
/* DESCRIPTION
/* .nf
+ /*
+ * System library.
+ */
+#include <sys/time.h>
+#include <time.h>
+
/*
* Utility library.
*/
QMGR_ENTRY_LIST todo; /* todo queue entries */
QMGR_ENTRY_LIST busy; /* messages on the wire */
QMGR_QUEUE_LIST peers; /* neighbor queues */
- DSN *dsn; /* why unavailable */
+ DSN *dsn; /* why unavailable */
time_t clog_time_to_warn; /* time of next warning */
};
int refcount; /* queue entries */
int single_rcpt; /* send one rcpt at a time */
long arrival_time; /* time when queued */
+ struct timeval active_time; /* time of entry into active queue */
long warn_offset; /* warning bounce flag offset */
time_t warn_time; /* time next warning to be sent */
long data_offset; /* data seek offset */
extern QMGR_MESSAGE *qmgr_message_alloc(const char *, const char *, int);
extern QMGR_MESSAGE *qmgr_message_realloc(QMGR_MESSAGE *);
+#define QMGR_MSG_STATS(stats, message) \
+ MSG_STATS_INIT2(stats, \
+ incoming_arrival, message->arrival_time, \
+ active_arrival, message->active_time)
+
/*
* qmgr_defer.c
*/
void qmgr_bounce_recipient(QMGR_MESSAGE *message, RECIPIENT *recipient,
DSN *dsn)
{
+ MSG_STATS stats;
int status;
status = bounce_append(message->tflags, message->queue_id,
- message->arrival_time, recipient,
+ QMGR_MSG_STATS(&stats, message), recipient,
"none", dsn);
if (status == 0)
void qmgr_defer_recipient(QMGR_MESSAGE *message, RECIPIENT *recipient,
DSN *dsn)
{
+ MSG_STATS stats;
/*
* Update the message structure and log the message disposition.
*/
message->flags |= defer_append(message->tflags, message->queue_id,
- message->arrival_time, recipient,
+ QMGR_MSG_STATS(&stats, message), recipient,
"none", dsn);
}
RECIPIENT *recipient;
QMGR_MESSAGE *message = entry->message;
VSTRING *sender_buf = 0;
+ MSG_STATS stats;
char *sender;
int flags;
flags = message->tflags
| entry->queue->dflags
| (message->inspect_xport ? DEL_REQ_FLAG_BOUNCE : DEL_REQ_FLAG_DEFLT);
+ QMGR_MSG_STATS(&stats, message);
attr_print(stream, ATTR_FLAG_MORE,
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, message->queue_name,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, message->dsn_envid,
ATTR_TYPE_NUM, MAIL_ATTR_DSN_RET, message->dsn_ret,
- ATTR_TYPE_LONG, MAIL_ATTR_TIME, message->arrival_time,
+ ATTR_TYPE_FUNC, msg_stats_print, (void *) &stats,
ATTR_TYPE_STR, MAIL_ATTR_CLIENT_NAME, message->client_name,
ATTR_TYPE_STR, MAIL_ATTR_CLIENT_ADDR, message->client_addr,
ATTR_TYPE_STR, MAIL_ATTR_PROTO_NAME, message->client_proto,
message->refcount = 0;
message->single_rcpt = 0;
message->arrival_time = 0;
+ GETTIMEOFDAY(&message->active_time);
message->data_offset = 0;
message->queue_id = mystrdup(queue_id);
message->queue_name = mystrdup(queue_name);
ssize_t len;
int status;
DSN dsn;
+ MSG_STATS stats;
#define STREQ(x,y) (strcmp(x,y) == 0)
#define STR vstring_str
len) == 0
&& !var_double_bounce_sender[len]) {
status = sent(message->tflags, message->queue_id,
- message->arrival_time, recipient,
+ QMGR_MSG_STATS(&stats, message), recipient,
"none", DSN_SIMPLE(&dsn, "2.0.0",
"undeliverable postmaster notification discarded"));
if (status == 0) {
# do not edit below this line - it is generated by 'make depend'
pipe.o: ../../include/argv.h
+pipe.o: ../../include/attr.h
pipe.o: ../../include/bounce.h
pipe.o: ../../include/canon_addr.h
pipe.o: ../../include/defer.h
pipe.o: ../../include/mail_params.h
pipe.o: ../../include/mail_server.h
pipe.o: ../../include/msg.h
+pipe.o: ../../include/msg_stats.h
pipe.o: ../../include/mymalloc.h
pipe.o: ../../include/off_cvt.h
pipe.o: ../../include/pipe_command.h
for (n = 0; n < request->rcpt_list.len; n++) {
rcpt = request->rcpt_list.info + n;
status = sent(DEL_REQ_TRACE_FLAGS(request->flags),
- request->queue_id, request->arrival_time, rcpt,
+ request->queue_id, &request->msg_stats, rcpt,
service, &dsn);
if (status == 0 && (request->flags & DEL_REQ_FLAG_SUCCESS))
deliver_completed(src, rcpt->offset);
rcpt = request->rcpt_list.info + n;
status = bounce_append(DEL_REQ_TRACE_FLAGS(request->flags),
request->queue_id,
- request->arrival_time, rcpt,
+ &request->msg_stats, rcpt,
service, &dsn);
if (status == 0)
deliver_completed(src, rcpt->offset);
rcpt = request->rcpt_list.info + n;
result |= defer_append(DEL_REQ_TRACE_FLAGS(request->flags),
request->queue_id,
- request->arrival_time, rcpt,
+ &request->msg_stats, rcpt,
service, &dsn);
}
}
for (n = 0; n < request->rcpt_list.len; n++) {
rcpt = request->rcpt_list.info + n;
status = sent(DEL_REQ_TRACE_FLAGS(request->flags),
- request->queue_id, request->arrival_time,
+ request->queue_id, &request->msg_stats,
rcpt, service, DSN_FROM_DSN_BUF(&dsn, why));
if (status == 0 && (request->flags & DEL_REQ_FLAG_SUCCESS))
deliver_completed(request->fp, rcpt->offset);
qmgr.o: qmgr.c
qmgr.o: qmgr.h
qmgr_active.o: ../../include/abounce.h
+qmgr_active.o: ../../include/attr.h
qmgr_active.o: ../../include/bounce.h
qmgr_active.o: ../../include/defer.h
qmgr_active.o: ../../include/deliver_request.h
qmgr_active.o: ../../include/mail_params.h
qmgr_active.o: ../../include/mail_queue.h
qmgr_active.o: ../../include/msg.h
+qmgr_active.o: ../../include/msg_stats.h
qmgr_active.o: ../../include/mymalloc.h
qmgr_active.o: ../../include/qmgr_user.h
qmgr_active.o: ../../include/rec_type.h
qmgr_active.o: ../../include/vstring.h
qmgr_active.o: qmgr.h
qmgr_active.o: qmgr_active.c
+qmgr_bounce.o: ../../include/attr.h
qmgr_bounce.o: ../../include/bounce.h
qmgr_bounce.o: ../../include/deliver_completed.h
qmgr_bounce.o: ../../include/deliver_request.h
qmgr_bounce.o: ../../include/dsn.h
qmgr_bounce.o: ../../include/dsn_buf.h
+qmgr_bounce.o: ../../include/msg_stats.h
qmgr_bounce.o: ../../include/recipient_list.h
qmgr_bounce.o: ../../include/scan_dir.h
qmgr_bounce.o: ../../include/sys_defs.h
qmgr_bounce.o: ../../include/vstring.h
qmgr_bounce.o: qmgr.h
qmgr_bounce.o: qmgr_bounce.c
+qmgr_defer.o: ../../include/attr.h
qmgr_defer.o: ../../include/bounce.h
qmgr_defer.o: ../../include/defer.h
qmgr_defer.o: ../../include/deliver_request.h
qmgr_defer.o: ../../include/dsn.h
qmgr_defer.o: ../../include/dsn_buf.h
qmgr_defer.o: ../../include/msg.h
+qmgr_defer.o: ../../include/msg_stats.h
qmgr_defer.o: ../../include/recipient_list.h
qmgr_defer.o: ../../include/scan_dir.h
qmgr_defer.o: ../../include/sys_defs.h
qmgr_deliver.o: ../../include/mail_proto.h
qmgr_deliver.o: ../../include/mail_queue.h
qmgr_deliver.o: ../../include/msg.h
+qmgr_deliver.o: ../../include/msg_stats.h
qmgr_deliver.o: ../../include/recipient_list.h
qmgr_deliver.o: ../../include/scan_dir.h
qmgr_deliver.o: ../../include/stringops.h
qmgr_enable.o: ../../include/vstring.h
qmgr_enable.o: qmgr.h
qmgr_enable.o: qmgr_enable.c
+qmgr_entry.o: ../../include/attr.h
qmgr_entry.o: ../../include/deliver_request.h
qmgr_entry.o: ../../include/dsn.h
qmgr_entry.o: ../../include/dsn_buf.h
qmgr_entry.o: ../../include/events.h
qmgr_entry.o: ../../include/mail_params.h
qmgr_entry.o: ../../include/msg.h
+qmgr_entry.o: ../../include/msg_stats.h
qmgr_entry.o: ../../include/mymalloc.h
qmgr_entry.o: ../../include/recipient_list.h
qmgr_entry.o: ../../include/scan_dir.h
qmgr_message.o: ../../include/mail_proto.h
qmgr_message.o: ../../include/mail_queue.h
qmgr_message.o: ../../include/msg.h
+qmgr_message.o: ../../include/msg_stats.h
qmgr_message.o: ../../include/myflock.h
qmgr_message.o: ../../include/mymalloc.h
qmgr_message.o: ../../include/opened.h
/* DESCRIPTION
/* .nf
+ /*
+ * System library.
+ */
+#include <sys/time.h>
+#include <time.h>
+
/*
* Utility library.
*/
int refcount; /* queue entries */
int single_rcpt; /* send one rcpt at a time */
long arrival_time; /* time when queued */
- time_t queued_time; /* time when moved to the active
- * queue */
+ struct timeval active_time; /* time of entry into active queue */
+ time_t queued_time; /* sanitized time when moved to the
+ * active queue */
long warn_offset; /* warning bounce flag offset */
time_t warn_time; /* time next warning to be sent */
long data_offset; /* data seek offset */
extern QMGR_MESSAGE *qmgr_message_alloc(const char *, const char *, int);
extern QMGR_MESSAGE *qmgr_message_realloc(QMGR_MESSAGE *);
+#define QMGR_MSG_STATS(stats, message) \
+ MSG_STATS_INIT2(stats, \
+ incoming_arrival, message->arrival_time, \
+ active_arrival, message->active_time)
+
/*
* Sometimes it's required to access the transport queues and entries on per
* message basis. That's what the QMGR_JOB structure is for - it groups all
void qmgr_bounce_recipient(QMGR_MESSAGE *message, RECIPIENT *recipient,
DSN *dsn)
{
+ MSG_STATS stats;
int status;
status = bounce_append(message->tflags, message->queue_id,
- message->arrival_time, recipient,
+ QMGR_MSG_STATS(&stats, message), recipient,
"none", dsn);
if (status == 0)
void qmgr_defer_recipient(QMGR_MESSAGE *message, RECIPIENT *recipient,
DSN *dsn)
{
+ MSG_STATS stats;
/*
* Update the message structure and log the message disposition.
*/
message->flags |= defer_append(message->tflags, message->queue_id,
- message->arrival_time, recipient,
+ QMGR_MSG_STATS(&stats, message), recipient,
"none", dsn);
}
RECIPIENT *recipient;
QMGR_MESSAGE *message = entry->message;
VSTRING *sender_buf = 0;
+ MSG_STATS stats;
char *sender;
int flags;
flags = message->tflags
| entry->queue->dflags
| (message->inspect_xport ? DEL_REQ_FLAG_BOUNCE : DEL_REQ_FLAG_DEFLT);
+ QMGR_MSG_STATS(&stats, message);
attr_print(stream, ATTR_FLAG_MORE,
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, message->queue_name,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, message->dsn_envid,
ATTR_TYPE_NUM, MAIL_ATTR_DSN_RET, message->dsn_ret,
- ATTR_TYPE_LONG, MAIL_ATTR_TIME, message->arrival_time,
+ ATTR_TYPE_FUNC, msg_stats_print, (void *) &stats,
ATTR_TYPE_STR, MAIL_ATTR_CLIENT_NAME, message->client_name,
ATTR_TYPE_STR, MAIL_ATTR_CLIENT_ADDR, message->client_addr,
ATTR_TYPE_STR, MAIL_ATTR_PROTO_NAME, message->client_proto,
message->refcount = 0;
message->single_rcpt = 0;
message->arrival_time = 0;
+ GETTIMEOFDAY(&message->active_time);
message->queued_time = sane_time();
message->data_offset = 0;
message->queue_id = mystrdup(queue_id);
ssize_t len;
int status;
DSN dsn;
+ MSG_STATS stats;
#define STREQ(x,y) (strcmp(x,y) == 0)
#define STR vstring_str
len) == 0
&& !var_double_bounce_sender[len]) {
status = sent(message->tflags, message->queue_id,
- message->arrival_time, recipient,
+ QMGR_MSG_STATS(&stats, message), recipient,
"none", DSN_SIMPLE(&dsn, "2.0.0",
"undeliverable postmaster notification discarded"));
if (status == 0) {
sendmail.o: ../../include/mail_task.h
sendmail.o: ../../include/mime_state.h
sendmail.o: ../../include/msg.h
+sendmail.o: ../../include/msg_stats.h
sendmail.o: ../../include/msg_syslog.h
sendmail.o: ../../include/msg_vstream.h
sendmail.o: ../../include/mymalloc.h
#define GETOPT_LIST "A:B:C:F:GIL:N:O:R:UV:X:b:ce:f:h:imno:p:r:q:tvx"
saved_optind = optind;
- while ((c = GETOPT(argc, argv, GETOPT_LIST)) > 0) {
- VSTRING *buf = vstring_alloc(1);
+ while (argv[OPTIND] != 0) {
+ if (strcmp(argv[OPTIND], "-q") == 0) { /* not getopt compatible */
+ optind++;
+ continue;
+ }
+ if ((c = GETOPT(argc, argv, GETOPT_LIST)) <= 0)
+ break;
+ if (c == 'C') {
+ VSTRING *buf = vstring_alloc(1);
- if (c == 'C'
- && setenv(CONF_ENV_PATH,
+ if (setenv(CONF_ENV_PATH,
strcmp(sane_basename(buf, optarg), MAIN_CONF_FILE) == 0 ?
- sane_dirname(buf, optarg) : optarg, 1) < 0)
- msg_fatal_status(EX_UNAVAILABLE, "out of memory");
- vstring_free(buf);
+ sane_dirname(buf, optarg) : optarg, 1) < 0)
+ msg_fatal_status(EX_UNAVAILABLE, "out of memory");
+ vstring_free(buf);
+ }
}
optind = saved_optind;
mail_conf_read();
# do not edit below this line - it is generated by 'make depend'
smtp.o: ../../include/argv.h
+smtp.o: ../../include/attr.h
smtp.o: ../../include/debug_peer.h
smtp.o: ../../include/deliver_request.h
smtp.o: ../../include/dict.h
smtp.o: ../../include/match_list.h
smtp.o: ../../include/match_ops.h
smtp.o: ../../include/msg.h
+smtp.o: ../../include/msg_stats.h
smtp.o: ../../include/mymalloc.h
smtp.o: ../../include/name_mask.h
smtp.o: ../../include/recipient_list.h
smtp.o: smtp.h
smtp.o: smtp_sasl.h
smtp_addr.o: ../../include/argv.h
+smtp_addr.o: ../../include/attr.h
smtp_addr.o: ../../include/deliver_request.h
smtp_addr.o: ../../include/dict.h
smtp_addr.o: ../../include/dns.h
smtp_addr.o: ../../include/match_list.h
smtp_addr.o: ../../include/match_ops.h
smtp_addr.o: ../../include/msg.h
+smtp_addr.o: ../../include/msg_stats.h
smtp_addr.o: ../../include/myaddrinfo.h
smtp_addr.o: ../../include/mymalloc.h
smtp_addr.o: ../../include/own_inet_addr.h
smtp_addr.o: smtp_addr.c
smtp_addr.o: smtp_addr.h
smtp_chat.o: ../../include/argv.h
+smtp_chat.o: ../../include/attr.h
smtp_chat.o: ../../include/cleanup_user.h
smtp_chat.o: ../../include/deliver_request.h
smtp_chat.o: ../../include/dict.h
smtp_chat.o: ../../include/match_list.h
smtp_chat.o: ../../include/match_ops.h
smtp_chat.o: ../../include/msg.h
+smtp_chat.o: ../../include/msg_stats.h
smtp_chat.o: ../../include/mymalloc.h
smtp_chat.o: ../../include/name_mask.h
smtp_chat.o: ../../include/post_mail.h
smtp_connect.o: ../../include/match_list.h
smtp_connect.o: ../../include/match_ops.h
smtp_connect.o: ../../include/msg.h
+smtp_connect.o: ../../include/msg_stats.h
smtp_connect.o: ../../include/myaddrinfo.h
smtp_connect.o: ../../include/mymalloc.h
smtp_connect.o: ../../include/name_mask.h
smtp_connect.o: smtp_connect.c
smtp_connect.o: smtp_reuse.h
smtp_dsn.o: ../../include/argv.h
+smtp_dsn.o: ../../include/attr.h
smtp_dsn.o: ../../include/deliver_request.h
smtp_dsn.o: ../../include/dict.h
smtp_dsn.o: ../../include/dsn.h
smtp_dsn.o: ../../include/maps.h
smtp_dsn.o: ../../include/match_list.h
smtp_dsn.o: ../../include/match_ops.h
+smtp_dsn.o: ../../include/msg_stats.h
smtp_dsn.o: ../../include/recipient_list.h
smtp_dsn.o: ../../include/resolve_clnt.h
smtp_dsn.o: ../../include/scache.h
smtp_dsn.o: smtp.h
smtp_dsn.o: smtp_dsn.c
smtp_map11.o: ../../include/argv.h
+smtp_map11.o: ../../include/attr.h
smtp_map11.o: ../../include/deliver_request.h
smtp_map11.o: ../../include/dict.h
smtp_map11.o: ../../include/dsn.h
smtp_map11.o: ../../include/match_list.h
smtp_map11.o: ../../include/match_ops.h
smtp_map11.o: ../../include/msg.h
+smtp_map11.o: ../../include/msg_stats.h
smtp_map11.o: ../../include/quote_822_local.h
smtp_map11.o: ../../include/quote_flags.h
smtp_map11.o: ../../include/recipient_list.h
smtp_proto.o: ../../include/match_ops.h
smtp_proto.o: ../../include/mime_state.h
smtp_proto.o: ../../include/msg.h
+smtp_proto.o: ../../include/msg_stats.h
smtp_proto.o: ../../include/mymalloc.h
smtp_proto.o: ../../include/name_code.h
smtp_proto.o: ../../include/off_cvt.h
smtp_proto.o: smtp_proto.c
smtp_proto.o: smtp_sasl.h
smtp_rcpt.o: ../../include/argv.h
+smtp_rcpt.o: ../../include/attr.h
smtp_rcpt.o: ../../include/bounce.h
smtp_rcpt.o: ../../include/deliver_completed.h
smtp_rcpt.o: ../../include/deliver_request.h
smtp_rcpt.o: ../../include/match_list.h
smtp_rcpt.o: ../../include/match_ops.h
smtp_rcpt.o: ../../include/msg.h
+smtp_rcpt.o: ../../include/msg_stats.h
smtp_rcpt.o: ../../include/mymalloc.h
smtp_rcpt.o: ../../include/recipient_list.h
smtp_rcpt.o: ../../include/resolve_clnt.h
smtp_rcpt.o: smtp.h
smtp_rcpt.o: smtp_rcpt.c
smtp_reuse.o: ../../include/argv.h
+smtp_reuse.o: ../../include/attr.h
smtp_reuse.o: ../../include/deliver_request.h
smtp_reuse.o: ../../include/dict.h
smtp_reuse.o: ../../include/dns.h
smtp_reuse.o: ../../include/match_list.h
smtp_reuse.o: ../../include/match_ops.h
smtp_reuse.o: ../../include/msg.h
+smtp_reuse.o: ../../include/msg_stats.h
smtp_reuse.o: ../../include/myaddrinfo.h
smtp_reuse.o: ../../include/mymalloc.h
smtp_reuse.o: ../../include/recipient_list.h
smtp_reuse.o: smtp_reuse.c
smtp_reuse.o: smtp_reuse.h
smtp_sasl_glue.o: ../../include/argv.h
+smtp_sasl_glue.o: ../../include/attr.h
smtp_sasl_glue.o: ../../include/deliver_request.h
smtp_sasl_glue.o: ../../include/dict.h
smtp_sasl_glue.o: ../../include/dsn.h
smtp_sasl_glue.o: ../../include/match_list.h
smtp_sasl_glue.o: ../../include/match_ops.h
smtp_sasl_glue.o: ../../include/msg.h
+smtp_sasl_glue.o: ../../include/msg_stats.h
smtp_sasl_glue.o: ../../include/mymalloc.h
smtp_sasl_glue.o: ../../include/name_mask.h
smtp_sasl_glue.o: ../../include/recipient_list.h
smtp_sasl_glue.o: smtp_sasl.h
smtp_sasl_glue.o: smtp_sasl_glue.c
smtp_sasl_proto.o: ../../include/argv.h
+smtp_sasl_proto.o: ../../include/attr.h
smtp_sasl_proto.o: ../../include/deliver_request.h
smtp_sasl_proto.o: ../../include/dict.h
smtp_sasl_proto.o: ../../include/dsn.h
smtp_sasl_proto.o: ../../include/match_list.h
smtp_sasl_proto.o: ../../include/match_ops.h
smtp_sasl_proto.o: ../../include/msg.h
+smtp_sasl_proto.o: ../../include/msg_stats.h
smtp_sasl_proto.o: ../../include/mymalloc.h
smtp_sasl_proto.o: ../../include/recipient_list.h
smtp_sasl_proto.o: ../../include/resolve_clnt.h
smtp_sasl_proto.o: smtp_sasl.h
smtp_sasl_proto.o: smtp_sasl_proto.c
smtp_session.o: ../../include/argv.h
+smtp_session.o: ../../include/attr.h
smtp_session.o: ../../include/debug_peer.h
smtp_session.o: ../../include/deliver_request.h
smtp_session.o: ../../include/dict.h
smtp_session.o: ../../include/match_ops.h
smtp_session.o: ../../include/mime_state.h
smtp_session.o: ../../include/msg.h
+smtp_session.o: ../../include/msg_stats.h
smtp_session.o: ../../include/mymalloc.h
smtp_session.o: ../../include/recipient_list.h
smtp_session.o: ../../include/resolve_clnt.h
smtp_session.o: smtp_sasl.h
smtp_session.o: smtp_session.c
smtp_state.o: ../../include/argv.h
+smtp_state.o: ../../include/attr.h
smtp_state.o: ../../include/deliver_request.h
smtp_state.o: ../../include/dict.h
smtp_state.o: ../../include/dsn.h
smtp_state.o: ../../include/maps.h
smtp_state.o: ../../include/match_list.h
smtp_state.o: ../../include/match_ops.h
+smtp_state.o: ../../include/msg_stats.h
smtp_state.o: ../../include/mymalloc.h
smtp_state.o: ../../include/recipient_list.h
smtp_state.o: ../../include/resolve_clnt.h
smtp_state.o: smtp_sasl.h
smtp_state.o: smtp_state.c
smtp_trouble.o: ../../include/argv.h
+smtp_trouble.o: ../../include/attr.h
smtp_trouble.o: ../../include/bounce.h
smtp_trouble.o: ../../include/defer.h
smtp_trouble.o: ../../include/deliver_completed.h
smtp_trouble.o: ../../include/match_list.h
smtp_trouble.o: ../../include/match_ops.h
smtp_trouble.o: ../../include/msg.h
+smtp_trouble.o: ../../include/msg_stats.h
smtp_trouble.o: ../../include/name_mask.h
smtp_trouble.o: ../../include/recipient_list.h
smtp_trouble.o: ../../include/resolve_clnt.h
smtp_trouble.o: smtp.h
smtp_trouble.o: smtp_trouble.c
smtp_unalias.o: ../../include/argv.h
+smtp_unalias.o: ../../include/attr.h
smtp_unalias.o: ../../include/deliver_request.h
smtp_unalias.o: ../../include/dict.h
smtp_unalias.o: ../../include/dns.h
smtp_unalias.o: ../../include/match_list.h
smtp_unalias.o: ../../include/match_ops.h
smtp_unalias.o: ../../include/msg.h
+smtp_unalias.o: ../../include/msg_stats.h
smtp_unalias.o: ../../include/myaddrinfo.h
smtp_unalias.o: ../../include/recipient_list.h
smtp_unalias.o: ../../include/resolve_clnt.h
/* .IP "\fBsmtp_connection_cache_on_demand (yes)\fR"
/* Temporarily enable SMTP connection caching while a destination
/* has a high volume of mail in the active queue.
-/* .IP "\fBsmtp_connection_cache_reuse_limit (10)\fR"
-/* When SMTP connection caching is enabled, the number of times that
-/* an SMTP session is reused before it is closed.
+/* .IP "\fBsmtp_connection_reuse_time_limit (300s)\fR"
+/* The amount of time during which Postfix will use an SMTP
+/* connection repeatedly.
/* .IP "\fBsmtp_connection_cache_time_limit (2s)\fR"
/* When SMTP connection caching is enabled, the amount of time that
/* an unused SMTP client socket is kept open before it is closed.
int var_smtp_mxaddr_limit;
int var_smtp_mxsess_limit;
int var_smtp_cache_conn;
-int var_smtp_reuse_limit;
+int var_smtp_reuse_time;
char *var_smtp_cache_dest;
char *var_scache_service;
bool var_smtp_cache_demand;
VAR_SMTP_PIX_THRESH, DEF_SMTP_PIX_THRESH, &var_smtp_pix_thresh, 0, 0,
VAR_SMTP_PIX_DELAY, DEF_SMTP_PIX_DELAY, &var_smtp_pix_delay, 1, 0,
VAR_SMTP_CACHE_CONN, DEF_SMTP_CACHE_CONN, &var_smtp_cache_conn, 1, 0,
+ VAR_SMTP_REUSE_TIME, DEF_SMTP_REUSE_TIME, &var_smtp_reuse_time, 1, 0,
#ifdef USE_TLS
VAR_SMTP_STARTTLS_TMOUT, DEF_SMTP_STARTTLS_TMOUT, &var_smtp_starttls_tmout, 1, 0,
#endif
VAR_SMTP_LINE_LIMIT, DEF_SMTP_LINE_LIMIT, &var_smtp_line_limit, 0, 0,
VAR_SMTP_MXADDR_LIMIT, DEF_SMTP_MXADDR_LIMIT, &var_smtp_mxaddr_limit, 0, 0,
VAR_SMTP_MXSESS_LIMIT, DEF_SMTP_MXSESS_LIMIT, &var_smtp_mxsess_limit, 0, 0,
- VAR_SMTP_REUSE_LIMIT, DEF_SMTP_REUSE_LIMIT, &var_smtp_reuse_limit, 1, 0,
#ifdef USE_TLS
VAR_SMTP_TLS_SCERT_VD, DEF_SMTP_TLS_SCERT_VD, &var_smtp_tls_scert_vd, 0, 0,
#endif
int sndbufsize; /* PIPELINING buffer size */
int send_proto_helo; /* XFORWARD support */
- int reuse_count; /* how many uses left */
+ time_t expire_time; /* session reuse expiration time */
+ int reuse_count; /* # of times reused (for logging) */
#ifdef USE_SASL_AUTH
char *sasl_mechanism_list; /* server mechanism list */
} SMTP_SESSION;
-extern SMTP_SESSION *smtp_session_alloc(VSTREAM *, const char *,
- const char *, const char *, unsigned, int);
+extern SMTP_SESSION *smtp_session_alloc(VSTREAM *, const char *, const char *,
+ const char *, unsigned, time_t, int);
extern void smtp_session_free(SMTP_SESSION *);
extern int smtp_session_passivate(SMTP_SESSION *, VSTRING *, VSTRING *);
extern SMTP_SESSION *smtp_session_activate(int, VSTRING *, VSTRING *);
extern int smtp_rset(SMTP_STATE *);
extern int smtp_quit(SMTP_STATE *);
+ /*
+ * A connection is re-usable if session->expire_time is > 0 and the
+ * expiration time has not been reached. This is subtle because the timer
+ * can expire between sending a command and receiving the reply for that
+ * command.
+ *
+ * But wait, there is more! When SMTP command pipelining is enabled, there are
+ * two protocol loops that execute at very different times: one loop that
+ * generates commands, and one loop that receives replies to those commands.
+ * These will be called "sender loop" and "receiver loop", respectively. At
+ * well-defined protocol synchronization points, the sender loop pauses to
+ * let the receiver loop catch up.
+ *
+ * When we choose to reuse a connection, both the sender and receiver protocol
+ * loops end with "." (mail delivery) or "RSET" (address probe). When we
+ * choose not to reuse, both the sender and receiver protocol loops end with
+ * "QUIT". The problem is that we must make the same protocol choices in
+ * both the sender and receiver loops, even though those loops may execute
+ * at completely different times.
+ *
+ * We "freeze" the choice in the sender loop, just before we generate "." or
+ * "RSET". The reader loop leaves the connection cachable even if the timer
+ * expires by the time the response arrives. The connection cleanup code
+ * will call smtp_quit() for connections with an expired cache expiration
+ * timer.
+ *
+ * We could have made the programmer's life a lot simpler by not making a
+ * choice at all, and always leaving it up to the connection cleanup code to
+ * call smtp_quit() for connections with an expired cache expiration timer.
+ *
+ * As a general principle, neither the sender loop nor the receiver loop must
+ * modify the connection caching state, if that can affect the receiver
+ * state machine for not-yet processed replies to already-generated
+ * commands. This restriction does not apply when we have to exit the
+ * protocol loops prematurely due to e.g., timeout or connection loss, so
+ * that those pending replies will never be received.
+ *
+ * But wait, there is even more! Only the first good connection for a specific
+ * destination may be cached under both the next-hop destination name and
+ * the server address; connections to alternate servers must be cached under
+ * the server address alone. This means we must distinguish between bad
+ * connections and other reasons why connections cannot be cached.
+ */
+#define THIS_SESSION_IS_CACHED \
+ (session->expire_time > 0)
+
+#define THIS_SESSION_IS_EXPIRED \
+ (THIS_SESSION_IS_CACHED \
+ && session->expire_time < vstream_ftime(session->stream))
+
+#define THIS_SESSION_IS_BAD \
+ (session->expire_time < 0)
+
+#define DONT_CACHE_THIS_SESSION \
+ (session->expire_time = 0)
+
+#define DONT_CACHE_BAD_SESSION \
+ (session->expire_time = -1)
+
+#define CACHE_THIS_SESSION_UNTIL(when) \
+ (session->expire_time = (when))
+
/*
* smtp_chat.c
*/
/*
/* typedef struct {
/* .in +4
-/* int code;
-/* char *dsn;
-/* char *str;
+/* int code; /* SMTP code, not sanitized */
+/* char *dsn; /* enhanced status, sanitized */
+/* char *str; /* unmodified SMTP reply */
/* VSTRING *dsn_buf;
/* VSTRING *str_buf;
/* .in -4
/* smtp_chat_cmd() formats a command and sends it to an SMTP server.
/* Optionally, the command is logged.
/*
-/* smtp_chat_resp() reads one SMTP server response. It separates the
-/* numerical status code from the text, and concatenates multi-line
-/* responses to one string, using a newline as separator.
-/* Optionally, the server response is logged.
-/*
+/* smtp_chat_resp() reads one SMTP server response. It extracts
+/* the SMTP reply code and enhanced status code from the text,
+/* and concatenates multi-line responses to one string, using
+/* a newline as separator. Optionally, the server response
+/* is logged.
+/* .IP \(bu
+/* Postfix never sanitizes the extracted SMTP reply code except
+/* to ensure that it is a three-digit code. A malformed reply
+/* results in a null extracted SMTP reply code value.
+/* .IP \(bu
+/* Postfix always sanitizes the extracted enhanced status code.
+/* When the server's SMTP status code is 2xx, 4xx or 5xx,
+/* Postfix requires that the first digit of the server's
+/* enhanced status code matches the first digit of the server's
+/* SMTP status code. In case of a mis-match, or when the
+/* server specified no status code, the extracted enhanced
+/* status code is set to 2.0.0, 4.0.0 or 5.0.0 instead. With
+/* SMTP reply codes other than 2xx, 4xx or 5xx, the extracted
+/* enhanced status code is set to a default value of 5.5.0
+/* (protocol error) for reasons outlined under the next bullet.
+/* .IP \(bu
+/* Since the SMTP reply code may violate the protocol even
+/* when it is correctly formatted, Postfix uses the sanitized
+/* extracted enhanced status code to decide whether an error
+/* condition is permanent or transient. This means that the
+/* caller may have to update the enhanced status code when it
+/* discovers that a server reply violates the SMTP protocol,
+/* even though it was correctly formatted. This happens when
+/* the client and server get out of step due to a broken proxy
+/* agent.
+/* .PP
/* smtp_chat_notify() sends a copy of the SMTP transaction log
/* to the postmaster for review. The postmaster notice is sent only
/* when delivery is possible immediately. It is an error to call
int ch;
char *bind_addr;
char *bind_var;
+ time_t start_time;
smtp_errno = SMTP_ERR_NONE; /* Paranoia */
if (msg_verbose)
msg_info("%s: trying: %s[%s] port %d...",
myname, addr->name, hostaddr.buf, ntohs(port));
+ start_time = time((time_t *) 0);
if (var_smtp_conn_tmout > 0) {
non_blocking(sock, NON_BLOCKING);
conn_stat = timed_connect(sock, sa, salen, var_smtp_conn_tmout);
/*
* Bundle up what we have into a nice SMTP_SESSION object.
*/
- return (smtp_session_alloc(stream, dest, addr->name,
- hostaddr.buf, port, sess_flags));
+ return (smtp_session_alloc(stream, dest, addr->name, hostaddr.buf,
+ port, start_time, sess_flags));
}
/* smtp_parse_destination - parse destination */
static void smtp_cleanup_session(SMTP_STATE *state)
{
+ DELIVER_REQUEST *request = state->request;
SMTP_SESSION *session = state->session;
+ int bad_session;
/*
* Inform the postmaster of trouble.
* hosts. In fact, this is the only benefit of caching logical to
* physical bindings; caching a session under its own hostname provides
* no performance benefit, given the way smtp_connect() works.
- *
- * XXX Should not cache TLS sessions unless we are using a single-session,
- * in-process, cache. And if we did, we should passivate VSTREAM objects
- * in addition to passivating SMTP_SESSION objects.
*/
- if (session->reuse_count > 0) {
+ bad_session = THIS_SESSION_IS_BAD; /* smtp_quit() may fail */
+ if (THIS_SESSION_IS_EXPIRED)
+ smtp_quit(state); /* also disables caching */
+ if (THIS_SESSION_IS_CACHED) {
smtp_save_session(state);
- if (HAVE_NEXTHOP_STATE(state))
- FREE_NEXTHOP_STATE(state);
} else {
smtp_session_free(session);
}
state->session = 0;
+ /*
+ * If this session was good, reset the logical next-hop state, so that we
+ * won't cache connections to alternate servers under the logical
+ * next-hop destination. Otherwise we could end up skipping over the
+ * available and more preferred servers.
+ */
+ if (HAVE_NEXTHOP_STATE(state) && !bad_session)
+ FREE_NEXTHOP_STATE(state);
+
/*
* Clean up the lists with todo and dropped recipients.
*/
smtp_rcpt_cleanup(state);
+
+ /*
+ * Reset profiling info.
+ *
+ * XXX When one delivery request results in multiple sessions, the set-up
+ * and transmission latencies of the earlier sessions will count as
+ * connection set-up time for the later sessions.
+ *
+ * XXX On the other hand, when we first try to connect to one or more dead
+ * hosts before we reach a good host, then all that time must be counted
+ * as connection set-up time for the session with the good host.
+ *
+ * XXX So this set-up attribution problem exists only when we actually
+ * engage in a session, spend a lot of time delivering a message, find
+ * that it fails, and then connect to an alternate host.
+ */
+ memset((char *) &request->msg_stats.conn_setup_done, 0,
+ sizeof(request->msg_stats.conn_setup_done));
+ memset((char *) &request->msg_stats.deliver_done, 0,
+ sizeof(request->msg_stats.deliver_done));
+ request->msg_stats.reuse_count = 0;
}
/* smtp_scrub_address_list - delete all cached addresses from list */
/* accordingly.
/*
/* smtp_rset() sends a single RSET command and waits for the
-/* response. In case of no response, or negative response, it
-/* turns off connection caching.
+/* response. In case of a negative reply it sets the
+/* CANT_RSET_THIS_SESSION flag.
/*
/* smtp_quit() sends a single QUIT command and waits for the
/* response if configured to do so. It always turns off connection
/* perform an SMTP conversation, not necessarily the ability
/* to deliver mail, or the achievement of server happiness.
/*
+/* In case of a rejected or failed connection, a connection
+/* is marked as "bad, do not cache". Otherwise, connection
+/* caching may be turned off (without being marked "bad") at
+/* the discretion of the code that implements the individual
+/* protocol steps.
+/*
/* Warnings: corrupt message file. A corrupt message is marked
/* as "corrupt" by changing its queue file permissions.
/* BUGS
* SMTP connection either, because the conversation is in an unknown
* state.
*/
- session->reuse_count = 0;
+ DONT_CACHE_THIS_SESSION;
/*
* The actual TLS handshake may succeed, but tls_client_start() may fail
#define SENDING_MAIL \
(recv_state <= SMTP_STATE_DOT)
-#define THIS_SESSION_IS_CACHED \
- (session->reuse_count > 0)
-
-#define DONT_CACHE_THIS_SESSION \
- (session->reuse_count = 0)
-
#define CANT_RSET_THIS_SESSION \
(session->features |= SMTP_FEATURE_RSET_REJECTED)
* Build the MAIL FROM command.
*/
case SMTP_STATE_MAIL:
+ request->msg_stats.reuse_count = session->reuse_count;
+ GETTIMEOFDAY(&request->msg_stats.conn_setup_done);
REWRITE_ADDRESS(session->scratch2, request->sender);
QUOTE_ADDRESS(session->scratch, vstring_str(session->scratch2));
vstring_sprintf(next_command, "MAIL FROM:<%s>",
/*
* Build the "." command before we have seen the DATA response.
+ *
+ * Changing the connection caching state here is safe because it
+ * affects none of the not-yet processed replies to
+ * already-generated commands.
*/
case SMTP_STATE_DOT:
vstring_strcpy(next_command, ".");
+ if (THIS_SESSION_IS_EXPIRED)
+ DONT_CACHE_THIS_SESSION;
next_state = THIS_SESSION_IS_CACHED ?
SMTP_STATE_LAST : SMTP_STATE_QUIT;
break;
* when it has verified all recipients; or it is entered by the
* receiver when all recipients are verified or rejected, and is
* then left before the bottom of the main loop.
+ *
+ * Changing the connection caching state here is safe because there
+ * are no not-yet processed replies to already-generated
+ * commands.
*/
case SMTP_STATE_ABORT:
vstring_strcpy(next_command, "RSET");
+ if (THIS_SESSION_IS_EXPIRED)
+ DONT_CACHE_THIS_SESSION;
next_state = THIS_SESSION_IS_CACHED ?
SMTP_STATE_LAST : SMTP_STATE_QUIT;
break;
* Build the QUIT command before we have seen the "." or RSET
* response. This is entered as initial state from smtp_quit(),
* or is reached near the end of any non-cached session.
+ *
+ * Changing the connection caching state here is safe. If this
+ * command is pipelined together with a preceding command, then
+ * connection caching was already turned off. Do not clobber the
+ * "bad connection" flag.
*/
case SMTP_STATE_QUIT:
vstring_strcpy(next_command, "QUIT");
next_state = SMTP_STATE_LAST;
- DONT_CACHE_THIS_SESSION;
+ if (THIS_SESSION_IS_CACHED)
+ DONT_CACHE_THIS_SESSION;
break;
/*
* delivered.
*/
case SMTP_STATE_DOT:
+ GETTIMEOFDAY(&request->msg_stats.deliver_done);
if (nrcpt > 0) {
if (resp->code / 100 != 2) {
smtp_mesg_fail(state, session->host, resp,
}
}
}
+
+ /*
+ * XXX Do not change the connection caching state here,
+ * even if the connection caching timer expired between
+ * generating the command and processing the reply,
+ * otherwise the sender and receiver loops get out of
+ * sync. The caller will call smtp_quit() if appropriate.
+ */
recv_state = (var_skip_quit_resp || THIS_SESSION_IS_CACHED ?
SMTP_STATE_LAST : SMTP_STATE_QUIT);
break;
/*
- * Receive the RSET response, and disable session caching
- * in case of failure.
+ * Receive the RSET response.
+ *
+ * The SMTP_STATE_ABORT sender state is entered by the
+ * sender when it has verified all recipients; or it is
+ * entered by the receiver when all recipients are
+ * verified or rejected, and is then left before the
+ * bottom of the main loop.
+ *
+ * XXX Do not change the connection caching state here, even
+ * if the server rejected RSET or if the connection
+ * caching timer expired between generating the command
+ * and processing the reply, otherwise the sender and
+ * receiver loops get out of sync. The caller will call
+ * smtp_quit() if appropriate.
*/
case SMTP_STATE_ABORT:
- if (resp->code / 100 != 2)
- DONT_CACHE_THIS_SESSION;
recv_state = (var_skip_quit_resp || THIS_SESSION_IS_CACHED ?
SMTP_STATE_LAST : SMTP_STATE_QUIT);
break;
send_state = recv_state = SMTP_STATE_ABORT;
send_rcpt = recv_rcpt = 0;
vstring_strcpy(next_command, "RSET");
+ if (THIS_SESSION_IS_EXPIRED)
+ DONT_CACHE_THIS_SESSION;
next_state = THIS_SESSION_IS_CACHED ?
SMTP_STATE_LAST : SMTP_STATE_QUIT;
/* XXX Also: record if non-delivering session. */
} else if (prev_type == REC_TYPE_CONT) /* missing newline */
smtp_fputs("", 0, session->stream);
if ((session->features & SMTP_FEATURE_MAYBEPIX) != 0
- && request->arrival_time < vstream_ftime(session->stream)
+ && request->msg_stats.incoming_arrival < vstream_ftime(session->stream)
- var_smtp_pix_thresh) {
msg_info("%s: enabling PIX <CRLF>.<CRLF> workaround for %s",
request->queue_id, session->namaddr);
dsn.action = "relayed";
status = sent(DEL_REQ_TRACE_FLAGS(request->flags),
- request->queue_id, request->arrival_time, rcpt,
+ request->queue_id, &request->msg_stats, rcpt,
session->namaddr, &dsn);
if (status == 0)
if (request->flags & DEL_REQ_FLAG_SUCCESS)
/* SYNOPSIS
/* #include "smtp.h"
/*
-/* SMTP_SESSION *smtp_session_alloc(stream, dest, host, addr, port, flags)
+/* SMTP_SESSION *smtp_session_alloc(stream, dest, host, addr,
+/* port, start, flags)
/* VSTREAM *stream;
/* char *dest;
/* char *host;
/* char *addr;
/* unsigned port;
+/* time_t start;
/* int flags;
/*
/* void smtp_session_free(session)
/* The address of the host that we are connected to.
/* .IP port
/* The remote port, network byte order.
+/* .IP start
+/* The time when this connection was opened.
/* .IP flags
/* Zero or more of the following:
/* .RS
SMTP_SESSION *smtp_session_alloc(VSTREAM *stream, const char *dest,
const char *host, const char *addr,
- unsigned port, int flags)
+ unsigned port, time_t start,
+ int flags)
{
SMTP_SESSION *session;
session->scratch = vstring_alloc(100);
session->scratch2 = vstring_alloc(100);
smtp_chat_init(session);
- session->features = 0;
session->mime_state = 0;
session->sndbufsize = 0;
session->send_proto_helo = 0;
if (flags & SMTP_SESS_FLAG_CACHE)
- session->reuse_count = var_smtp_reuse_limit;
+ CACHE_THIS_SESSION_UNTIL(start + var_smtp_reuse_time);
else
- session->reuse_count = 0;
+ DONT_CACHE_THIS_SESSION;
+ session->reuse_count = 0;
#ifdef USE_SASL_AUTH
smtp_sasl_connect(session);
* how many non-delivering mail transactions there were during this
* session, and perhaps other statistics, so that we don't reuse a
* session too much.
+ *
+ * XXX Be sure to use unsigned types in the format string. Sign characters
+ * would be rejected by the alldig() test on the reading end.
*/
- vstring_sprintf(endp_prop, "%s\n%s\n%s\n%u\n%u\n%u\n%u",
+ vstring_sprintf(endp_prop, "%u\n%s\n%s\n%s\n%u\n%u\n%lu\n%u",
+ session->reuse_count,
session->dest, session->host,
session->addr, session->port,
session->features & SMTP_FEATURE_ENDPOINT_MASK,
- session->reuse_count,
+ (long) session->expire_time,
session->sndbufsize);
/*
const char *addr;
unsigned port;
unsigned features; /* server features */
- unsigned reuse_count; /* how reuses left */
+ time_t expire_time; /* session re-use expiration time */
+ unsigned reuse_count; /* # times reused */
unsigned sndbufsize; /* PIPELINING buffer size */
/*
* suitable for zero-length fields.
*/
endp_props = STR(endp_prop);
+ if ((prop = mystrtok(&endp_props, "\n")) == 0 || !alldig(prop)) {
+ msg_warn("%s: bad cached session reuse count property", myname);
+ return (0);
+ }
+ reuse_count = atoi(prop);
if ((dest = mystrtok(&endp_props, "\n")) == 0) {
msg_warn("%s: missing cached session destination property", myname);
return (0);
features = atoi(prop);
if ((prop = mystrtok(&endp_props, "\n")) == 0 || !alldig(prop)) {
- msg_warn("%s: bad cached session reuse_count property", myname);
+ msg_warn("%s: bad cached session expiration time property", myname);
return (0);
}
- reuse_count = atoi(prop);
+#ifdef MISSING_STRTOUL
+ expire_time = strtol(prop, 0, 10);
+#else
+ expire_time = strtoul(prop, 0, 10);
+#endif
if ((prop = mystrtok(&endp_props, "\n")) == 0 || !alldig(prop)) {
msg_warn("%s: bad cached session sndbufsize property", myname);
/*
* Allright, bundle up what we have sofar.
*/
- session = smtp_session_alloc(vstream_fdopen(fd, O_RDWR),
- dest, host, addr, port, SMTP_SESS_FLAG_NONE);
+ session = smtp_session_alloc(vstream_fdopen(fd, O_RDWR), dest, host,
+ addr, port, (time_t) 0, SMTP_SESS_FLAG_NONE);
session->features = (features | SMTP_FEATURE_FROM_CACHE);
- session->reuse_count = reuse_count - 1;
+ CACHE_THIS_SESSION_UNTIL(expire_time);
+ session->reuse_count = ++reuse_count;
session->sndbufsize = sndbufsize;
if (msg_verbose)
- msg_info("%s: dest=%s host=%s addr=%s port=%u features=0x%x, reuse=%u, sndbuf=%u",
- myname, dest, host, addr, ntohs(port), features, reuse_count, sndbufsize);
+ msg_info("%s: dest=%s host=%s addr=%s port=%u features=0x%x, "
+ "ttl=%ld, reuse=%d, sndbuf=%u",
+ myname, dest, host, addr, ntohs(port), features,
+ (long) (expire_time - time((time_t *) 0)), reuse_count,
+ sndbufsize);
/*
* Re-activate the SASL attributes.
SMTP_SESSION *session = state->session;
RECIPIENT *rcpt;
int status;
- int soft_error = (dsn->dtext[0] == '4');
+ int soft_error = (dsn->status[0] == '4');
int nrcpt;
/*
* the recipient for delivery to a backup server.
*/
else {
+
+ /*
+ * If we are still in the connection set-up phase, update the set-up
+ * completion time here, otherwise the time spent in set-up latency
+ * will be attributed as message transfer latency.
+ *
+ * All remaining recipients have failed at this point, so we update the
+ * delivery completion time stamp so that multiple recipient status
+ * records show the same delay values.
+ */
+ if (request->msg_stats.conn_setup_done.tv_sec == 0) {
+ GETTIMEOFDAY(&request->msg_stats.conn_setup_done);
+ request->msg_stats.deliver_done =
+ request->msg_stats.conn_setup_done;
+ } else
+ GETTIMEOFDAY(&request->msg_stats.deliver_done);
+
for (nrcpt = 0; nrcpt < SMTP_RCPT_LEFT(state); nrcpt++) {
rcpt = request->rcpt_list.info + nrcpt;
if (SMTP_RCPT_ISMARKED(rcpt))
continue;
status = (soft_error ? defer_append : bounce_append)
(DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
- request->arrival_time, rcpt,
+ &request->msg_stats, rcpt,
session ? session->namaddr : "none", dsn);
if (status == 0)
deliver_completed(state->src, rcpt->offset);
* Don't cache this session. We can't talk to this server.
*/
if (throttle_queue && session)
- session->reuse_count = 0;
+ DONT_CACHE_BAD_SESSION;
return (-1);
}
va_start(ap, format);
vsmtp_fill_dsn(state, &dsn, mta_name, resp->dsn, resp->str, format, ap);
va_end(ap);
- soft_error = dsn.dtext[0] == '4';
+ soft_error = dsn.status[0] == '4';
if (state->session && mta_name)
smtp_check_code(state->session, resp->code);
else {
status = (soft_error ? defer_append : bounce_append)
(DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
- request->arrival_time, rcpt,
+ &request->msg_stats, rcpt,
session ? session->namaddr : "none", &dsn);
if (status == 0)
deliver_completed(state->src, rcpt->offset);
smtpd_check.o: ../../include/match_ops.h
smtpd_check.o: ../../include/match_parent_style.h
smtpd_check.o: ../../include/msg.h
+smtpd_check.o: ../../include/msg_stats.h
smtpd_check.o: ../../include/myaddrinfo.h
smtpd_check.o: ../../include/mymalloc.h
smtpd_check.o: ../../include/namadr_list.h
/* Reject the specified commands with a hard (5xx) error code.
/* This option implies \fB-p\fR.
/* .sp
-/* Examples of commands are HELO, EHLO, LHLO, MAIL, RCPT, VRFY,
+/* Examples of commands are CONNECT, HELO, EHLO, LHLO, MAIL, RCPT, VRFY,
/* DATA, ., RSET, NOOP, and QUIT. Separate command names by
/* white space or commas, and use quotes to protect white space
/* from the shell. Command names are case-insensitive.
/* Disconnect (without replying) after receiving one of the
/* specified commands.
/* .sp
-/* Examples of commands are HELO, EHLO, LHLO, MAIL, RCPT, VRFY,
+/* Examples of commands are CONNECT, HELO, EHLO, LHLO, MAIL, RCPT, VRFY,
/* DATA, ., RSET, NOOP, and QUIT. Separate command names by
/* white space or commas, and use quotes to protect white space
/* from the shell. Command names are case-insensitive.
/* Reject the specified commands with a soft (4xx) error code.
/* This option implies \fB-p\fR.
/* .sp
-/* Examples of commands are HELO, EHLO, LHLO, MAIL, RCPT, VRFY,
+/* Examples of commands are CONNECT, HELO, EHLO, LHLO, MAIL, RCPT, VRFY,
/* DATA, ., RSET, NOOP, and QUIT. Separate command names by
/* white space or commas, and use quotes to protect white space
/* from the shell. Command names are case-insensitive.
/* .IP "\fB-s \fIcommand,command,...\fR"
/* Log the named commands to syslogd.
/* .sp
-/* Examples of commands are HELO, EHLO, LHLO, MAIL, RCPT, VRFY,
+/* Examples of commands are CONNECT, HELO, EHLO, LHLO, MAIL, RCPT, VRFY,
/* DATA, ., RSET, NOOP, and QUIT. Separate command names by
/* white space or commas, and use quotes to protect white space
/* from the shell. Command names are case-insensitive.
quit_count++;
}
+/* conn_response - respond to connect command */
+
+static void conn_response(SINK_STATE *state)
+{
+ if (pretend_pix)
+ smtp_printf(state->stream, "220 ********");
+ else if (disable_esmtp)
+ smtp_printf(state->stream, "220 %s", var_myhostname);
+ else
+ smtp_printf(state->stream, "220 %s ESMTP", var_myhostname);
+ smtp_flush(state->stream);
+}
+
/* data_read - read data from socket */
static int data_read(SINK_STATE *state)
#define FLAG_DISCONNECT (1<<4) /* disconnect */
static SINK_COMMAND command_table[] = {
+ "connect", conn_response, hard_err_resp, soft_err_resp, 0,
"helo", helo_response, hard_err_resp, soft_err_resp, 0,
"ehlo", ehlo_response, hard_err_resp, soft_err_resp, 0,
"lhlo", ehlo_response, hard_err_resp, soft_err_resp, 0,
myfree(saved_cmds);
}
+/* command_resp - respond to command */
+
+static int command_resp(SINK_STATE *state, SINK_COMMAND *cmdp, const char *command, char *args)
+{
+ /* We use raw syslog. Sanitize data content and length. */
+ if (cmdp->flags & FLAG_SYSLOG)
+ syslog(LOG_INFO, "%s %.100s", command, printable(args, '?'));
+ if (cmdp->flags & FLAG_DISCONNECT)
+ return (-1);
+ if (cmdp->flags & FLAG_HARD_ERR) {
+ cmdp->hard_response(state);
+ return (0);
+ }
+ if (cmdp->flags & FLAG_SOFT_ERR) {
+ cmdp->soft_response(state);
+ return (0);
+ }
+ if (cmdp->response == data_response && fixed_delay > 0) {
+ event_request_timer(data_event, (char *) state, fixed_delay);
+ } else {
+ cmdp->response(state);
+ if (cmdp->response == quit_response)
+ return (-1);
+ }
+ return (0);
+}
+
/* command_read - talk the SMTP protocol, server side */
static int command_read(SINK_STATE *state)
smtp_flush(state->stream);
return (0);
}
- /* We use raw syslog. Sanitize data content and length. */
- if (cmdp->flags & FLAG_SYSLOG)
- syslog(LOG_INFO, "%s %.100s", command, printable(ptr, '?'));
- if (cmdp->flags & FLAG_DISCONNECT)
- return (-1);
- if (cmdp->flags & FLAG_HARD_ERR) {
- cmdp->hard_response(state);
- return (0);
- }
- if (cmdp->flags & FLAG_SOFT_ERR) {
- cmdp->soft_response(state);
- return (0);
- }
- if (cmdp->response == data_response && fixed_delay > 0) {
- event_request_timer(data_event, (char *) state, fixed_delay);
- } else {
- cmdp->response(state);
- if (cmdp->response == quit_response)
- return (-1);
- }
- return (0);
+ return (command_resp(state, cmdp, command, ptr));
}
/* read_timeout - handle timer event */
return;
case 0:
- if (pretend_pix)
- smtp_printf(state->stream, "220 ********");
- else if (disable_esmtp)
- smtp_printf(state->stream, "220 %s", var_myhostname);
- else
- smtp_printf(state->stream, "220 %s ESMTP", var_myhostname);
- smtp_flush(state->stream);
- event_enable_read(fd, read_event, (char *) state);
- event_request_timer(read_timeout, (char *) state, var_tmout);
+ if (command_resp(state, command_table, "connect", "") < 0)
+ disconnect(state);
+ else {
+ event_enable_read(fd, read_event, (char *) state);
+ event_request_timer(read_timeout, (char *) state, var_tmout);
+ }
}
}
}
tls_stream.o: tls.h
tls_stream.o: tls_stream.c
tls_verify.o: ../../include/msg.h
+tls_verify.o: ../../include/mymalloc.h
tls_verify.o: ../../include/sys_defs.h
tls_verify.o: ../../include/vbuf.h
tls_verify.o: ../../include/vstream.h
sane_accept.o: sane_accept.c
sane_accept.o: sane_accept.h
sane_accept.o: sys_defs.h
-sane_basename.o: msg.h
-sane_basename.o: mymalloc.c
-sane_basename.o: mymalloc.h
sane_basename.o: sane_basename.c
sane_basename.o: stringops.h
sane_basename.o: sys_defs.h
* 4.4BSD and close derivatives.
*/
#if defined(FREEBSD2) || defined(FREEBSD3) || defined(FREEBSD4) \
- || defined(FREEBSD5) \
+ || defined(FREEBSD5) || defined(FREEBSD6) \
|| defined(BSDI2) || defined(BSDI3) || defined(BSDI4) \
|| defined(OPENBSD2) || defined(OPENBSD3) \
|| defined(NETBSD1) || defined(NETBSD2) \
#define fpos_t long
#define MISSING_SETENV
#define MISSING_STRERROR
+#define MISSING_STRTOUL
#define _PATH_MAILDIR "/var/spool/mail"
#define _PATH_BSHELL "/bin/sh"
#define _PATH_DEFPATH "/usr/bin:/usr/ucb"
verify.o: ../../include/mail_proto.h
verify.o: ../../include/mail_server.h
verify.o: ../../include/msg.h
+verify.o: ../../include/msg_stats.h
verify.o: ../../include/mymalloc.h
verify.o: ../../include/post_mail.h
verify.o: ../../include/recipient_list.h
# do not edit below this line - it is generated by 'make depend'
deliver_attr.o: ../../include/argv.h
+deliver_attr.o: ../../include/attr.h
deliver_attr.o: ../../include/deliver_request.h
deliver_attr.o: ../../include/dict.h
deliver_attr.o: ../../include/dsn.h
deliver_attr.o: ../../include/maps.h
deliver_attr.o: ../../include/mbox_conf.h
deliver_attr.o: ../../include/msg.h
+deliver_attr.o: ../../include/msg_stats.h
deliver_attr.o: ../../include/recipient_list.h
deliver_attr.o: ../../include/sys_defs.h
deliver_attr.o: ../../include/vbuf.h
deliver_attr.o: deliver_attr.c
deliver_attr.o: virtual.h
mailbox.o: ../../include/argv.h
+mailbox.o: ../../include/attr.h
mailbox.o: ../../include/bounce.h
mailbox.o: ../../include/defer.h
mailbox.o: ../../include/deliver_request.h
mailbox.o: ../../include/mbox_conf.h
mailbox.o: ../../include/mbox_open.h
mailbox.o: ../../include/msg.h
+mailbox.o: ../../include/msg_stats.h
mailbox.o: ../../include/mymalloc.h
mailbox.o: ../../include/recipient_list.h
mailbox.o: ../../include/safe_open.h
mailbox.o: mailbox.c
mailbox.o: virtual.h
maildir.o: ../../include/argv.h
+maildir.o: ../../include/attr.h
maildir.o: ../../include/bounce.h
maildir.o: ../../include/defer.h
maildir.o: ../../include/deliver_request.h
maildir.o: ../../include/mbox_conf.h
maildir.o: ../../include/mbox_open.h
maildir.o: ../../include/msg.h
+maildir.o: ../../include/msg_stats.h
maildir.o: ../../include/mymalloc.h
maildir.o: ../../include/recipient_list.h
maildir.o: ../../include/safe_open.h
maildir.o: maildir.c
maildir.o: virtual.h
recipient.o: ../../include/argv.h
+recipient.o: ../../include/attr.h
recipient.o: ../../include/bounce.h
recipient.o: ../../include/deliver_request.h
recipient.o: ../../include/dict.h
recipient.o: ../../include/maps.h
recipient.o: ../../include/mbox_conf.h
recipient.o: ../../include/msg.h
+recipient.o: ../../include/msg_stats.h
recipient.o: ../../include/mymalloc.h
recipient.o: ../../include/recipient_list.h
recipient.o: ../../include/stringops.h
recipient.o: recipient.c
recipient.o: virtual.h
unknown.o: ../../include/argv.h
+unknown.o: ../../include/attr.h
unknown.o: ../../include/bounce.h
unknown.o: ../../include/deliver_request.h
unknown.o: ../../include/dict.h
unknown.o: ../../include/maps.h
unknown.o: ../../include/mbox_conf.h
unknown.o: ../../include/msg.h
+unknown.o: ../../include/msg_stats.h
unknown.o: ../../include/recipient_list.h
unknown.o: ../../include/sys_defs.h
unknown.o: ../../include/vbuf.h
unknown.o: unknown.c
unknown.o: virtual.h
virtual.o: ../../include/argv.h
+virtual.o: ../../include/attr.h
virtual.o: ../../include/deliver_completed.h
virtual.o: ../../include/deliver_request.h
virtual.o: ../../include/dict.h
virtual.o: ../../include/maps.h
virtual.o: ../../include/mbox_conf.h
virtual.o: ../../include/msg.h
+virtual.o: ../../include/msg_stats.h
virtual.o: ../../include/recipient_list.h
virtual.o: ../../include/set_eugid.h
virtual.o: ../../include/sys_defs.h
state.msg_attr.dsn_envid = rqst->dsn_envid;
state.msg_attr.dsn_ret = rqst->dsn_ret;
state.msg_attr.relay = service;
- state.msg_attr.arrival_time = rqst->arrival_time;
+ state.msg_attr.msg_stats = rqst->msg_stats;
RESET_USER_ATTR(usr_attr, state.level);
state.request = rqst;
char *user; /* recipient lookup handle */
const char *delivered; /* for loop detection */
char *relay; /* relay host */
- long arrival_time; /* arrival time */
+ MSG_STATS msg_stats; /* time profile */
DSN_BUF *why; /* delivery status */
DSN dsn; /* delivery status */
} DELIVER_ATTR;
#define BOUNCE_FLAGS(request) DEL_REQ_TRACE_FLAGS((request)->flags)
#define BOUNCE_ATTR(attr) \
- attr.queue_id, attr.arrival_time, &attr.rcpt, attr.relay, \
+ attr.queue_id, &attr.msg_stats, &attr.rcpt, attr.relay, \
DSN_FROM_DSN_BUF(&attr.dsn, attr.why)
#define SENT_ATTR(attr) \
- attr.queue_id, attr.arrival_time, &attr.rcpt, attr.relay, \
+ attr.queue_id, &attr.msg_stats, &attr.rcpt, attr.relay, \
DSN_FROM_DSN_BUF(&attr.dsn, attr.why)
#define COPY_ATTR(attr) \
attr.sender, attr.rcpt.orig_addr, attr.delivered, attr.fp