-TPIPE_ATTR
-TPIPE_PARAMS
-TPLMYSQL
+-TPOST_MAIL_STATE
-TQMGR_ENTRY
-TQMGR_JOB
-TQMGR_MESSAGE
code had grown into a monster and needed to be replaced.
trivial-rewrite/transport.c.
+20021115
+
+ Start implementing recipient verification. For now this is
+ done by adding trace flags to queue files. In case of a
+ verification request, a delivery agent does not deliver,
+ deliver, it just records what would happen.
+
+ This required instrumenting the bounce/defer/sent logging
+ routines to send their data to the right place depending
+ on the type of delivery request.
+
+20021116
+
+ New trace service. This is used for reporting if a recipient
+ is deliverable (sendmail -bv) and for producing a record
+ of delivery attempts (sendmail -v). The report is sent via
+ email, using the bounce daemon. Files: global/trace.[hc].
+
+ This required replacing the bounce/defer logfile format by
+ an extensible name=value format. Files: global/bounce_log.c,
+ bounce/bounce_append_service.c.
+
+20021117
+
+ New address verification service with simple expiration
+ and refresh policy. Storage can be in-core or in permanent
+ table. The daemon is appropriately called "verify". Files:
+ global/verify_clnt.[hc], verify/verify.c.
+
+20021118
+
+ Cleaning up the code for tracing and verification. Files:
+ global/{log_adhoc,bounce,defer,trace,verify}.[hc].
+
+20021119
+
+ New address_verification_negative_cache = yes/no parameter
+ controls whether Postfix stores the result of negatieve
+ address verification probes. This reduces cache pollution
+ but causes Postfix to send a probe for each address
+ verification service query. File: verify/verify.c.
+
+ Added optimistic caching to the verify daemon, so that one
+ failed probe will not clobber a known to be good address.
+ As long as some probes succeeed, a good address will stay
+ cached as OK.
+
+ Cleaning up of the bounce daemon's code for bounce, delayed
+ mail warning and trace notification. Files: bounce/*.[hc],
+ global/bounce_log.c.
+
+20021120
+
+ Changed the probe's sender address to "postmaster" so that
+ we get better information about the address we're testing.
+ File: verify/verify.c.
+
+ Added some paranoia to the routine that reads data from
+ the address verification cache. Ignore data that is obviously
+ bogus. File: verify/verify.c.
+
20021121
Bugfix: garbage in "user@garbage"@domain address forms may
cause the SMTP or LMTP client to terminate with a fatal
error exit because garbage/tcp is not an existing service.
This cannot be abused to cause the SMTP or LMTP client to
- send data into unauthorized ports. Files: *qmgr/qmgr_message.c,
+ send data into unauthorized ports. Files: *qmgr/qmgr_message.c,
trivial-rewrite/resolve.c.
+20021124
+
+ Bugfix: don't use same VSTRING buffer for reading and writing.
+ File: verify/verify.c.
+
20021128
Feature: hashed hold queue support, with hashing turned on
SMTP clients. Files: smtp/smtp_connect.c, lmtp/lmtp_connect.c,
util/host_port.[hc].
+20021130
+
+ Cleanup: defer mail when recipient verification takes too
+ long. File: smtpd/smtpd_proto.c.
+
+ Feature: new reject_multi_recipient_bounce restriction, to
+ reject "MAIL FROM: <>" with multiple recipients. File:
+ smtpd/smtpd_check.c.
+
20021201
Compatibility: ignore the new Sendmail -A option. File:
not prepend X-Original-To: addresses to maildir files.
Omission spotted by Matthias Andree.
+ Specify "address_verify_sender=" or "address_verify_sender=<>"
+ to use a null sender address while doing address verification
+ probes. Beware, doing so may trigger false negatives
+ because some sites reject mail from the null sender, even
+ though this is required by RFC standards.
+
Bugfix: too many levels of dereferencing while testing for
missing reject_rbl_mumble domain names. Patrik Rak. File:
smtpd/smtpd_check.c.
suddenly lose all their mail because local_recipient_maps
is now turned on by default.
+20021210
+
+ Feature: recipient address verification, using the code
+ that already implements sender address verification. Based
+ on suggestion by Matthias Andree. Files: src/smtpd/smtpd.c,
+ src/smtpd/smtpd_check.c.
+
20021211
Performance: doubled the default process limit (50->100)
and default queue manager active queue message/recipient
- limits (10k->20k). File: global/mail_params.h.
+ limits (10k->20k). File: global/mail_params.h.
+
+ Bugfix: the change that begot us multiple trivial-rewrite
+ processes (good) also gave us multiple verify daemons (bad).
+ File: conf/post-install.
20021212
and do transport map lookups before relocated map lookups.
Files: trivial-rewrite/resolve.c, trivial-rewrite/transport.c.
+ Shortened the verify server's negative cache refresh time
+ from 12 hours to 2 hours. File: global/mail_params.h.
+
Admin friendliness: the SMTP server now reports "User
unknown in {local recipient | virtual alias | virtual
mailbox | relay recipient} table". This will make trouble
error transport without updating the nexthop information.
File: trivial-rewrite/resolve.c.
+ Robustness: don't probe the sender address when probed for
+ our own address verification probe sender address. File:
+ smtpd/smtpd_check.c.
+
Performance: don't do UCE checks (which may result in 4xx
SMTP reply codes, and thus, repeated delivery attempts)
when we already know that the recipient does not exist.
site already ran Postfix with local_recipient_maps enabled.
Files: smtpd/smtpd.c, smtpd/smtpd_check.c, conf/post-install.
+20021218
+
+ Feature: specify unverified_recipient_reject_code=250 or
+ unverified_sender_reject_code=250 to accept mail for an
+ address that is known to bounce. File: smtpd/smtpd_check.c.
+
20021219
Bugfix: longjmp() while sending "go away" without setjmp()
shooting easier but also reveals information that is nobody
elses business.
+20021221
+
+ Workaround: don't allow the transport map to override the
+ virtual alias class (error:User unknown) result. File:
+ trivial-rewrite/transport.c.
+
Open problems:
Low: after successful delivery, per-queue window += 1/window,
src/lmtp src/trivial-rewrite src/qmgr src/smtp src/bounce src/pipe \
src/showq src/postalias src/postcat src/postconf src/postdrop \
src/postkick src/postlock src/postlog src/postmap src/postqueue \
- src/postsuper src/nqmgr src/qmqpd src/spawn src/flush src/virtual
+ src/postsuper src/nqmgr src/qmqpd src/spawn src/flush src/verify \
+ src/virtual
MANDIRS = proto man html
default: update
--- /dev/null
+Sender address verification
+===========================
+
+Sender address verification blocks mail from an unknown sender
+address until after the address is verified. An address is verified
+by probing the nearest MTA for that address, without actually
+delivering mail to it (SMTP interruptus). Probe messages are like
+normail mail, but are discarded instead of being deferred or bounced.
+
+Normal mail will suffer only a short one-time delay of up to 9
+seconds while address verification happens for the first time.
+When verification takes longer than 9 seconds, the Postfix SMTP
+server defers the message with a 450 reply. Normal mail clients
+will connect again after some delay. Once an address status is
+known, the status is cached and Postfix replies immediately.
+
+Address verification is turned on with the "reject_unverified_sender"
+sender restriction. To find out how this would affect your mail,
+specify "warn_if_reject reject_unverified_sender" so that you can
+see what mail would be blocked:
+
+ smtpd_sender_restrictions =
+ ...
+ check_sender_access hash:/etc/postfix/sender_access
+ reject_unknown_sender_domain
+ warn_if_reject reject_unverified_sender
+ ...
+
+This is also a good way to populate your cache with address
+verification results before you start to actually reject mail.
+
+The sender_access restriction is needed to whitelist domains that
+are known to be OK. See the section titled "Limitations" at the
+end of this document.
+
+The "reject_unknown_sender_domain" restriction blocks mail from
+non-existent domains. Putting this before "reject_unverified_sender"
+avoids the overhead of generating unnecessary probe messages.
+
+The unverified_sender_reject_code parameter (default 450) specifies
+how Postfix replies when a sender address is known to bounce.
+Change this setting into 550 when you trust Postfix's judgments.
+
+Caching
+=======
+
+NOTE: By default, address verification information is not stored
+in a persistent file. You have to specify one in main.cf (see
+below). Persistent storage is off by default because it may need
+more disk space than is available in your root file system.
+
+Address verification information is cached by the Postfix verify
+daemon. Postfix has a bunch of parameters that control the caching
+of positive and negative results. Refer to the verify(8) manual
+page or the sample-verify.cf file for details.
+
+The address_verify_map (NOTE: singular) configuration parameter
+specifies an optional persistent database for sender address
+verification results. If you don't specify a file, all address
+verification information is lost after "postfix reload" or "postfix
+stop".
+
+If your root file system has sufficient space, try:
+
+ address_verify_map = btree:/etc/postfix/verify
+
+NOTE: Do not put this file in a file system that fills up. When
+the address verification table gets corrupted the world comes to
+an end and YOU will have to MANUALLY fix things as described in
+the next section. Meanwhile you will not receive mail via SMTP.
+
+The verify daemon process will create a new database when none
+exists, and will open/create the file before it enters the chroot
+jail or before it drops root privileges.
+
+Managing the address verification database
+==========================================
+
+Right now, no tools are provided to manage the address verification
+database. If the file gets too big, or if it gets corrupted, you
+can manually delete the file and run "postfix reload". The new
+verify daemon process will then create a new, empty, database.
+
+Limitations
+===========
+
+Postfix probes the nearest MTA for the sender domain without actually
+sending mail. If that MTA accepts the recipient, then Postfix
+assumes that the address is deliverable, even when the address will
+bounce AFTER that MTA accepts it.
+
+You will probably want to put a whitelist before the address
+verification restriction, so that you can exclude known to be OK
+domains or addresses from verification. Although Postfix will not
+mark a known-to-be-good address as bad after a probe fails, it is
+better to be safe than sorry.
+
+ smtpd_sender_restrictions =
+ ...
+ check_sender_access hash:/etc/postfix/sender_access
+ reject_unknown_sender_domain
+ reject_unverified_sender
+ ...
+
+NOTE: You will have to whitelist sites such as securityfocus.com
+and other sites that operate mailing lists that use a different
+sender address for each posting (VERP). Such addresses pollute
+the address verification cache quickly, and generate unnecessary
+sender verification probes.
+===============================================================
+WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+===============================================================
+The sender/recipient address verification code is lightly documented
+and has been tested lightly. The code is proof-of-concept quality
+and must not be used on high-volume sites. Use at your own risk.
+===============================================================
+WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+===============================================================
+
In the text below, incompatible changes are labeled with the Postfix
snapshot that introduced the change. If you upgrade from a later
Postfix version, then you do not have to worry about that particular
date. Snapshots change only the release date, unless they include
the same bugfixes as a patch release.
-Incompatible changes with Postfix snapshot 1.1.12-20021219
-==========================================================
-
-The use of the XVERP extension in the SMTP MAIL FROM command is
-now limited to SMTP clients that match the hostnames, domains or
-networks listed with the authorized_verp_clients parameter (default:
-$mynetworks).
-
-Incompatible changes with Postfix snapshot 1.1.12-20021209
-==========================================================
-
-This release adds a new "relay" service to the Postfix master.cf
-file. If your Postfix is unable to connect to the "relay" service
-then you have not properly followed the installation procedure.
-
-The Postfix SMTP server now rejects mail for $mydestination domain
-recipients that it does not know about. This keeps undeliverable
-mail out of your queue.
-
-To avoid losing mail when upgrading from Postfix 1.1, you need to
-review the LOCAL_RECIPIENT_README file if one of the following is
-true:
-
-- You define $mydestination domain recipients in files other than
- /etc/passwd or /etc/aliases. For example, you define $mydestination
- domain recipients in the $virtual_mailbox_maps files.
-- You run the Postfix SMTP server chrooted (see master.cf).
-- You redefined the local delivery agent in master.cf.
-- You redefined the "local_transport" setting in main.cf.
-- You use the mailbox_transport feature of the Postfix local delivery agent.
-- You use the fallback_transport feature of the Postfix local delivery agent.
-- You use the luser_relay feature of the Postfix local delivery agent.
-
-Postfix no longer defaults to the "smtp" transport for all non-local
-destinations. This may affect your defer_transports settings. In
-particular, Postfix now uses the "relay" mail delivery transport
-for delivery to domains matching $relay_domains. The old "smtp"
-transport is now the default mail delivery transport for non-local
-domains that do not match relay_domains.
-
-The "virtual_maps" configuration parameter is now called
-"virtual_alias_maps", for consistency with "virtual_mailbox_maps".
-Default settings are backwards compatible with Postfix 1.1.
-
-Postfix-style virtual domains are now called virtual alias domains.
-Sendmail-style virtual domains are no longer documented. This part
-of Postfix was too confusing.
-
-The default queue directory hash_queue_depth setting is reduced to
-1 level of subdirectories per Postfix queue. This improves "mailq"
-performance on most systems, but can result in poorer worst-case
-performance on systems with lots of mail in the queue.
-
-The "reject_maps_rbl" restriction is going away. The SMTP server
-logs a warning and suggests using the more flexible "reject_rbl_client"
-instead.
-
-The "check_relay_domains" restriction is going away. The SMTP server
-logs a warning and suggests using "reject_unauth_destination"
-instead.
-
-The Postfix SMTP client no longer expands CNAMEs in MAIL FROM or
-RCPT TO addresses (as permitted by RFC 2821).
-
-The Postfix installation procedure no longer sets the "chattr +S"
-bit on Linux queue directories. Wietse has gotten too annoyed with
-naive reviewers who complain about performance without having a
-clue of what they are comparing.
-
-Major changes with Postfix snapshot 1.1.12-20021209
-===================================================
-
-This release introduces separation of lookup tables for addresses
-and for domain names of virtual domains.
-
-- virtual_maps is replaced by virtual_alias_maps (for address
- lookups) and virtual_alias_domains (for the names of what were
- formerly called "Postfix-style virtual domains").
-
- For backwards compatibility with Postfix version 1.1, the new
- virtual_alias_maps parameter defaults to $virtual_maps, and the
- new virtual_alias_domains parameter defaults to $virtual_alias_maps.
-
-- virtual_mailbox_maps now has a companion parameter called
- virtual_mailbox_domains (for the names of domains served by the
- virtual delivery agent). virtual_mailbox_maps is now used for
- address lookups only.
-
- For backwards compatibility with Postfix version 1.1,, the new
- virtual_mailbox_domains parameter defaults to $virtual_mailbox_maps.
-
-This release introduces the concept of address domain classes, each
-having its own default mail delivery transport:
-
- Destination matches Default transport Default name
- --------------------------------------------------------------
- $mydestination or
- $inet_interfaces $local_transport local
- $virtual_alias_domains (not applicable) (not applicable)
- $virtual_mailbox_domains $virtual_transport virtual
- $relay_domains $relay_transport relay
- other $default_transport smtp
-
-The benefits of these changes are:
-
-- You no longer need to specify all the virtual(8) domains in the
- Postfix transport map. The virtual(8) delivery agent has
- become a first-class citizen just like local(8) or smtp(8).
-
-- On mail gateway systems, separation of inbound mail relay traffic
- from outbound traffic. This eliminates a problem where inbound
- mail deliveries could become resource starved in the presence of
- a high volume of outbound mail.
-
-- The SMTP server rejects unknown recipients in a more consistent
- manner than was possible with previous Postfix versions.
-
-See the ADDRESS_CLASS_README file for a description of address
-classes, their benefits, and their incompatibilities.
-
-Finally, regular expression maps are now allowed with local delivery
-agent alias tables and with all virtual delivery agent lookup tables.
-However, regular expression substitution of $1 etc. is still
-forbidden for security reasons.
-
-Incompatible changes with Postfix snapshot 1.1.11-20021108
-==========================================================
-
-The behavior of the SMTP server's defer_if_permit flag has changed,
-in order to maximize the opportunity to permanently reject mail
-without opening opportunities for losing legitimate mail.
-
-The flag is still set when an UCE reject restriction fails due to
-a temporary (DNS) problem, to prevent unwanted mail from slipping
-through. However, the flag is no longer tested at the end of client,
-helo or sender restrictions. Instead, the flag is now tested at
-the end of the ETRN and recipient restrictions only.
-
-The behavior of the warn_if_reject restriction has changed. It no
-longer activates any pending defer_if_permit or defer_if_reject
-decisions (the defer_if_reject flag is set when some UCE permit
-restriction fails due to a temporary (DNS) problem, to avoid loss
-of legitimate mail).
-
-Instead of setting the defer_if_permit flag, a failing reject
-restriction after warn_if_reject now merely logs that it would have
-caused mail to be deferred.
-
-A failing permit restriction after warn_if_reject still raises the
-defer_if_reject flag, to avoid loss of legitimate mail.
-
-Incompatible changes with Postfix snapshot 1.1.11-20021028
-==========================================================
-
-Logfile formats have changed. This may affect logfile processing
-software. The queue file format is still compatible with Postfix
-version 1.1 (stable release).
-
-- The Postfix SMTP server UCE reject etc. logging now includes the
-queue ID, the mail protocol (SMTP or ESMTP), and the hostname that
-was received with the HELO or EHLO command, if available.
-
-- The Postfix header/body_checks logging now includes the mail
-protocol (SMTP, ESMTP, QMQP) and the hostname that was received
-with the SMTP HELO or EHLO command, if available.
-
-The Postfix status=sent/bounced/deferred logging now shows the
-original recipient address (as received before any address rewriting
-or aliasing). The original recipient address is logged only when
-it differs from the final recipient address.
-
-Major changes with Postfix snapshot 1.1.11-20021028
-===================================================
-
-Postfix logs more information, as described in the "incompatibilities"
-section above.
-
-The local(8) and virtual(8) delivery agents now record the original
-recipient address in the X-Original-To: message header. This header
-can also be emitted by the pipe(8) delivery agent.
-
-Major changes with Postfix snapshot 1.1.11-20021024
-===================================================
-
-New proxy_interfaces parameter, for sites behind a network address
-translation gateway or other type of proxy. Specify all the proxy
-network addresses here, to avoid avoid mail delivery loops.
-
-Incompatible changes with Postfix snapshot 1.1.11-20021015
-==========================================================
-
-The Postfix LMTP client no longer lowercases email addresses in
-MAIL FROM and RCPT TO commands.
-
-Incompatible changes with Postfix snapshot 1.1.11-20021013
-==========================================================
-
-The default Linux kernel lock style for mailbox delivery is changed
-from flock() to fcntl(). This has no impact if your system uses
-procmail for local delivery, if you use maildir-style mailboxes,
-or when mailbox access software locks mailboxes with username.lock
-files (which is usually the case with non-maildir mailboxes).
-
-Major changes with Postfix snapshot 1.1.11-20021013
-===================================================
-
-The body_checks_max_size parameter limits the amount of text per
-message body segment (or attachment, if you prefer to use that
-term) that is subjected to body_checks inspection. The default
-limit is 50 kbytes. This speeds up the processing of mail with
-large attachments.
-
-Updated MacOS X support by Gerben Wierda. See the auxiliary/MacOSX
-directory.
-
-Incompatible changes with Postfix snapshot 1.1.11-20020923
-==========================================================
-
-Subtle change in ${name?result} macro expansions: the expansion
-no longer happens when $name is an empty string. This probably
-makes more sense than the old behavior.
-
-The default RBL "reject" server reply now includes an indication
-of *what* is being rejected: Client host, Helo command, Sender
-address, or Recipient address.
-
-Major changes with Postfix snapshot 1.1.11-20020923
-===================================================
-
-Complete rewrite of the RBL blacklisting code. The names of RBL
-restrictions are now based on a suggestion that was made by Liviu
-Daia in October 2001. See conf/sample-smtpd.cf or html/uce.html
-for details.
-
-Feature: "reject_rbl_client rbl.domain.tld" for client IP address
-blacklisting. Based on code by LaMont Jones. The old "reject_maps_rbl"
-is now implemented as a wrapper around the reject_rbl_client code.
-
-Feature: "reject_rhsbl_sender rbl.domain.tld" for sender domain
-blacklisting. Also: reject_rhsbl_client and reject_rhsbl_recipient
-for client and recipient domain blacklisting.
-
-"rbl_reply_maps" configuration parameter for lookup tables with
-template responses per RBL server. Based on code by LaMont Jones.
-If no reply template is found the default template is used as
-specified with the default_rbl_reply configuration parameter. The
-template responses support $name expansion of client, helo, sender,
-recipient and RBL related attributes.
-
-"smtpd_expansion_filter" configuration parameter to control what
-characters are allowed in the expansion of template reply $name
-macros. Characters outside the allowed set are replaced by "_".
-
-Incompatible changes with Postfix snapshot 1.1.11-20020917
-==========================================================
-
-The relayhost setting now behaves as documented, i.e. you can no
-longer specify multiple destinations.
-
-In regexp lookup tables, the form /pattern1/!/pattern2/ is going
-away. Use the cleaner and more flexible "if !/pattern2/..endif"
-form. The old form still exists but is no longer documented.
-
-Major changes with Postfix snapshot 1.1.11-20020917
-===================================================
-
-Speedups of regexp table lookups by optimizing for the $number
-substitutions that are actually present in the right-hand side.
-Based on a suggestion by Liviu Daia.
-
-Speedups of regexp and pcre tables, using IF..ENDIF support. Based
-on an idea by Bert Driehuis. To protect a block of patterns, use:
-
- if /pattern1/
- /pattern2/ result2
- /pattern3/ result3
- endif
-
-IF..ENDIF can nest. Don't specify blanks at the beginning of lines
-inside IF..ENDIF, because lines beginning with whitespace are
-appended to the previous line. More details about the syntax are
-given in the pcre_table(5) and regexp_table(5) manual pages.
-
-Incompatible changes with Postfix snapshot 1.1.11-20020906
-==========================================================
-
-The permit_mx_backup restriction is made more strict. With older
-versions, some DNS failures would cause mail to be accepted anyway,
-and some DNS failures would cause mail to be rejected by later
-restrictions in the same restriction list. The improved version
-will defer delivery when Postfix could make the wrong decision.
-
-Major changes with Postfix snapshot 1.1.11-20020906
-===================================================
-
-More sophisticated handling of UCE-related DNS lookup errors.
-These cause Postfix to not give up so easily, so that some deliveries
-will not have to be deferred after all. This affects the following
-restrictions:
-
-- After DNS lookup failure, permit_mx_backup will now accept the
-request if a subsequent restriction would cause the request to be
-accepted anyway, and will defer the request if a subsequent
-restriction would cause the request to be rejected.
-
-- After DNS lookup failure, reject_unknown_hostname (the hostname
-given in HELO/EHLO commands) reject_unknown_sender_domain and
-reject_unknown_recipient_domain will now reject the request if a
-subsequent restriction would cause the request to be rejected
-anyway, and will defer the request if a subsequent restriction
-would cause the request to be accepted.
-
-Specify "smtpd_data_restrictions = reject_unauth_pipelining" to
-block mail from SMTP clients that send message content before
-Postfix has replied to the SMTP DATA command.
-
-Incompatible changes with Postfix snapshot 1.1.11-20020819
-==========================================================
-
-The qmgr_site_hog_factor feature is gone (this would defer mail
-delivery for sites that occupy too much space in the active queue,
-and be a real performance drain due to excessive disk I/O). The
-new qmgr_clog_warn_time feature (see below) provides more useful
-suggestions for dealing with Postfix congestion.
-
-LDAP API version 1 is no longer supported. The memory allocation
-and deallocation strategy has changed too much to maintain both
-version 1 and 2 at the same time.
-
-In mailq output, the queue ID is followed by the ! character when
-the message is in the "hold" queue (see below). This may break
-programs that process mailq output.
-
-The "permit_naked_ip_address" restriction on HELO command syntax
-is unsafe when used with most smtpd_XXX_restrictions, and will go
-away. The user is now requested to use "permit_mynetworks" instead.
-
-The smtpd_sasl_local_domain setting now defaults to the null string,
-rather than $myhostname. This seems to work better with Cyrus SASL
-version 2. This change may cause incompatibility with the saslpasswd2
-command.
-
-Major changes with Postfix snapshot 1.1.11-20020819
-===================================================
-
-When the Postfix local delivery agent detects a mail delivery loop
-(usually the result of mis-configured mail pickup software), the
-undeliverable mail is now sent to the mailing list owner instead
-of the envelope sender address (usually the original poster who
-has no guilt, and who cannot fix the problem).
-
-New "hold" queue for mail that should not be delivered. "postsuper
--h" puts mail on hold, and "postsuper -H" releases mail, moving
-mail that was "on hold" to the deferred queue.
-
-New header/body HOLD action that causes mail to be placed on the
-"hold" queue. Presently, all you can do with mail "on hold" is to
-examine it with postcat, to take it "off hold" with "postsuper -H",
-or to destroy it with "postsuper -d". See conf/sample-filter.cf.
-
-The Postfix queue manager now warns when mail for some destination
-is piling up in the active queue, and suggests a variety of remedies
-to speed up delivery (increase per-destination concurrency limit,
-increase active queue size, use a separate delivery transport,
-increase per-transport process limit). The qmgr_clog_warn_time
-parameter controls the time between warnings. To disable these
-warnings, specify "qmgr_clog_warn_time = 0".
-
-Incompatible changes with Postfix snapshot 1.1.11-20020717
-==========================================================
-
-The default timeout for establishing an SMTP connection has been
-reduced to 30 seconds, because many systems have an atrociously
-large default timeout value.
-
-The Postfix SMTP client now logs a warning when the same domain is
-listed in main.cf:mydestination as well as a Postfix-style virtual
-map. Such a mis-configuration may cause mail for users to be rejected
-with "user unknown".
-
-Postfix no longer strips multiple '.' characters from the end of
-an email address or domain name. Only one '.' is tolerated.
-
-The SMTP server reject_unknown_{sender,recipient}_domain etc.
-restrictions now also attempt to look up AAAA (IPV6 address) records.
-
-Major changes with Postfix snapshot 1.1.11-20020717
-===================================================
-
-The masquerade_domains feature now supports exceptions. Prepend
-a ! character to a domain name in order to not strip its subdomain
-structure. More information in conf/sample-rewrite.cf.
-
-The Postfix virtual delivery agent supports catch-all entries
-(@domain.tld) in lookup tables. These match users that do not
-have a specific user@domain.tld entry. The virtual delivery agent
-now ignores address extensions (user+foo@domain.tld) when searching
-its lookup tables, but displays the extensions in Delivered-To:
-message headers.
-
-Incompatible changes with Postfix snapshot 1.1.11-20020610
-==========================================================
-
-Regexp-based transport maps now see the entire recipient address
-instead of only the destination domain name.
+Incompatible changes with Postfix snapshot 1.1.11-trace-20021119
+================================================================
-Major changes with Postfix snapshot 1.1.11-20020610
-===================================================
+After upgrading an existing system you must use "postfix reload".
+This is because many internal protocols have changed.
-A bizarre feature, sender-based routing, that could be useful in
-combination with user@domain address lookups in the transport map.
+The file format of bounce/defer logfiles has changed from the old
+one-line ad-hoc format to a more structured multi-line format. For
+backwards compatibility, Postfix now creates bounce/defer logfile
+entries that contain both the old and the new format, so that you
+can go back to an older Postfix release without losing information.
+Old Postfix versions will warn about malformed logfile entries,
+but should work properly. To disable backwards compatibility specify
+"backwards_bounce_logfile_compatibility = no" in main.cf.
-An actually useful feature, user@domain address lookups in the
-transport map. This feature also understands address extensions.
-Transport maps still support lookup keys in the form of domain
-names, but only with non-regexp tables. Specify <> in order to
-match the null address. More in the transport(5) manual page.
+The behavior of "sendmail -v" has changed. One -v option now sends
+an email report with the status of each delivery attempt. Multiple
+-v options behave as before: turn on verbose logging in the sendmail
+and and postdrop commands.
-Together with sender-based routing, and a dual Postfix setup.
-user@domain transport map lookups could fulfill people's wishes to
-have multiple SMTP personalities for sending and receiving mail,
-including bounce processing. Details will have to be hammered out
-by users, as Wietse is now completely tied up by other business
-for the next three weeks.
+The Postfix upgrade procedure will add two new services to your
+master.cf file: "trace" and "verify". These servers can run inside
+a chroot jail, have no interaction with users, and don't talk to
+the network.
-Incompatible changes with Postfix snapshot 1.1.11-20020528
-==========================================================
-
-With PCRE pattern matching, the `.' metacharacter now matches all
-characters including newline characters. This makes PCRE pattern
-matching more convenient to use with multi-line message headers,
-and also makes PCRE more compatible with regexp pattern matching.
-The pcre_table(5) manual page has been greatly revised.
-
-Major changes with Postfix snapshot 1.1.11-20020528
-===================================================
-
-Postfix can enforce specific aspects of the MIME standards while
-receiving mail.
-
-* Specify "strict_7bit_headers = yes" to disallow 8-bit characters
- in message headers. These are always illegal.
-
-* Specify "strict_8bitmime_body = yes" to block mail with 8-bit
- content that is not properly labeled as 8-bit MIME. This blocks
- mail from poorly written mail software, including (bounces from
- qmail, bounces from Postfix before snapshot 20020514, and Majordomo
- approval requests) that contain valid 8BITMIME mail.
-
-* Specify "strict_8bitmime = yes" to turn on both strict_7bit_headers
- and strict_8bitmime_body.
-
-* Specify "strict_mime_encoding_domain = yes" to block mail from
- poorly written mail software. More details in conf/sample-mime.cf.
-
-Incompatible changes with Postfix snapshot 1.1.11-20020527
-==========================================================
-
-Message headers in MIME attachments etc. are no longer matched by
-body_checks, one input line at a time. They are now by default
-matched by header_checks, one multi-line header at a time. To get
-the old behavior, specify "disable_mime_input_processing = yes",
-or specify separate patterns for header_checks, mime_header_checks
-and nested_header_checks. See conf/sample-mime.cf for details.
-
-Postfix now rejects mail if the MIME multipart structure is nested
-more than mime_nesting_limit levels (default: 20) when MIME input
-processing is enabled while receiving mail, or when Postfix is
-performing 8BITMIME to 7BIT conversion while delivering mail.
-
-Postfix now recognizes "name :" as a valid message header, but
-normalizes it to "name:" for consistency (actually, there is so
-much code in Postfix that would break with "name :" that there is
-little choice, except to not recognize "name :" headers).
-
-Queue files created with the header/body_checks "FILTER" feature
-are not compatible with "postqueue -r" (move queue files back to
-the maildrop directory) of previous Postfix releases.
-
-Major changes with Postfix snapshot 1.1.11-20020527
-===================================================
-
-Postfix now has real MIME support. This improves content filtering
-efficiency and accuracy, and improves inter-operability with mail
-systems that cannot receive 8-bit mail. See conf/sample-mime.cf
-for details.
-
-Postfix header_checks now properly recognize MIME headers in
-attachments. This is much more efficient than previous versions
-that recognized MIME headers via body_checks. MIME headers are
-now processed one multi-line header at a time, instead of one body
-line at a time.
-
-In fact, Postfix now has three classes of header patterns:
-header_checks (for primary message headers except MIME headers),
-mime_header_checks (for MIME headers), and nested_header_checks
-(for headers of attached email messages except MIME headers). By
-default, all headers are matched with header_checks. To get the
-the old behavior, specify "disable_mime_input_processing = yes".
-More details in conf/sample-filter.cf.
-
-Selective content filtering. In header/body_check patterns, specify
-"FILTER transport:nexthop" for mail that needs filtering. This
-requires different cleanup servers before and after the filter,
-with header/body checks turned off in the second cleanup server.
-More info about content filtering is in the Postfix FILTER_README
-file. Examples for this new feature still need to be developed.
-This feature overrides the main.cf content_filter setting.
-
-The Postfix SMTP client will now convert 8BITMIME mail to 7BIT when
-delivering to an SMTP server that does not announce 8BITMIME support.
-To disable, specify "disable_mime_output_conversion = yes". However,
-this conversion is required by RFC standards.
-
-Incompatible changes with Postfix snapshot 1.1.10-20020514
-==========================================================
-
-For safety reasons, the permit_mx_backup restriction no longer
-accepts mail for user@domain@domain. To recover the old behavior,
-specify "resolve_dequoted_address = no" which opens up a completely
-different can of worms as described a few paragraphs down in this
-document.
-
-Major changes with Postfix snapshot 1.1.9-20020513
-==================================================
-
-Updated LDAP client module with better handling of dead LDAP servers,
-and with configurable filtering of query results.
-
-In order to allow user@domain@domain addresses from untrusted
-systems, specify "resolve_dequoted_address = no" in main.cf (when
-resolving mail, quote the address localpart as per RFC 822, so that
-@ or % or ! operators in the address localpart remain invisible).
-Although this behavior is technically more correct, it also opens
-opportunities for mail relay attacks when Postfix provides backup
-MX service for Sendmail systems.
-
-Incompatible changes with Postfix snapshot 1.1.9-20020512
+Major changes with Postfix snapshot 1.1.11-trace-20021119
=========================================================
-The Postfix SMTP client no longer uses the CNAME expanded recipient
-address when logging delivery or when bouncing mail. This makes
-trouble shooting somewhat easier.
-
-Postfix snapshot 1.1.9-20020512 queue files contain records that
-are incompatible with "postqueue -r" on all Postfix versions prior
-to 1.1 and release candidates. This happens whenever the sender
-specifies MIME body type information via the SMTP `MAIL FROM'
-command, via the `sendmail -B' command line option, or via the
-Content-Transfer-Encoding: message header.
-
-Postfix snapshot 1.1.9-20020512 queue files may contain records
-that are incompatible with "postqueue -r" on previous 1.1 Postfix
-versions and release candidates. This happens whenever the sender
-specifies the MIME body type only via the Content-Transfer-Encoding:
-message header, and not via `MAIL FROM' or `sendmail -B'.
-
-Major changes with Postfix snapshot 1.1.9-20020512
-==================================================
-
-The Postfix SMTP and LMTP clients now properly pass on the MIME
-body type information (7BIT or 8BITMIME), provided that the sender
-properly specifies MIME body type information via the SMTP MAIL
-FROM command, via the sendmail -B command line option, or via MIME
-message headers. This includes mail that is returned as undeliverable.
-Implementing MIME body type propagation was a low priority because
-qmail didn't implement this, either. However, Postfix will not
-convert 8BITMIME content into 7BIT, and probably never will.
-
-Incompatible changes with Postfix snapshot 1.1.9-20020509
-=========================================================
-
-The Postfix SMTP server no longer honors OK access rules for
-user@domain@postfix-style.virtual.domain, to close a relaying
-loophole with postfix-style virtual domains that have @domain.name
-catch-all patterns.
-
-The appearance of user@domain1@domain2 addresses has changed. In
-mail headers, such addresses are now properly quoted as
-"user@domain1"@domain2. As a side effect, this quoted form is now
-also expected on the left-hand side of virtual and canonical lookup
-tables, but only by some of the Postfix components. For now, it
-is better not to use user@domain1@domain2 address forms on the
-left-hand side of lookup tables.
-
-Incompatible changes with Postfix snapshot 1.1.8-20020508
-=========================================================
-
-The Postfix SMTP server by default no longer accepts mail for
-user@domain@postfix-style.virtual.domain, to close a relaying
-loophole with postfix-style virtual domains that have @domain.name
-catch-all patterns.
-
-Incompatible changes with Postfix snapshot 1.1.8-20020505
-=========================================================
-
-In the Postfix transport table, the meaning of null delivery
-transport and nexhop information fields has changed. As of now, a
-null delivery transport or nexthop information field means "do not
-modify": use the delivery transport or nexthop information that
-would be used if no transport table did not exist. This change
-results in the following incompatible changes in behavior:
-
-- A null delivery transport field no longer defaults to
-$default_transport. It now defaults to $local_transport or
-$default_transport depending on the destination.
-
-- A null nexthop information field no longer overrides the main.cf
-relayhost setting. To override the relayhost, specify explicit
-nexthop information in the Postfix transport table.
-
-The postalias command now copies the source file read permissions
-to the result file when creating a table for the first time. Until
-now, the result file was created with default read permissions.
-This change makes postalias more similar to postmap.
-
-The postalias and postmap commands now drop super-user privileges
-when processing a non-root source file. The file is now processed
-as the source file owner, and the owner must therefore have permission
-to update the result file. Specify the "-o" flag to get the old
-behavior (process non-root files with root privileges).
-
-The read buffer size for Berkeley DB lookup tables was decreased
-from 1MByte to 256kByte. Specify "berkeley_db_read_buffer_size =
-1048576" to get the old read buffer size.
-
-Major changes with Postfix snapshot 1.1.8-20020505
-==================================================
-
-Friendlier behavior of Postfix transport tables. There is a new
-"*" wildcard pattern that matches any domain. The meaning of a null
-delivery transport or nexhop information field has changed to "do
-not modify": use the information that would be used if the transport
-table did not exist. This change makes it easier to route internal
-mail (everything under my.domain) directly: you no longer need to
-specify explicit "local" transport table entries for the local
-machine. For more information, including examples, see the updated
-transport(5) manual page.
-
-Finer control over Berkeley DB memory usage, and more efficient
-usage of memory in applications that open lots of tables. The
-parameter "berkeley_db_create_buffer_size" (default: 16 MBytes)
-specifies the buffer size for the postmap and postalias commands.
-The parameter "berkeley_db_read_buffer_size" (default: 256 kBytes)
-speficies the buffer size for all other applications. For more
-information, see the last paragraphs of the DB_README file.
-
-Major changes with Postfix snapshot 1.1.7-20020331
-==================================================
-
-Support for the Cyrus SASL version 2 library, contributed by Jason
-Hoos. This adds some new functionality that was not available in
-Cyrus SASL version 1, and provides bit-rot insurance for the time
-when Cyrus SASL version 1 eventually stops working.
-
-A new smtp_helo_name parameter that specifies the hostname to be
-used in HELO or EHLO commands; this can be more convenient than
-changing the myhostname parameter setting.
-
-Choice between multiple instances of internal services: bounce,
-cleanup, defer, error, flush, pickup, queue, rewrite, showq. This
-allows you to use different cleanup server settings for different
-SMTP server instances. For example, specify in the master.cf file:
-
- localhost:10025 ... smtpd -o cleanup_service_name=cleanup2 ...
- cleanup2 ... cleanup -o header_checks= body_checks= ...
-
-Incompatible changes with Postfix version 1.1.6 (released 20020326)
-===================================================================
-
-The Postfix SMTP client now breaks message header or body lines
-that are longer than $smtp_line_length_limit characters (default:
-990). Earlier Postfix versions broke lines at $line_length_limit
-characters (default: 2048). Postfix versions before 20010611 did
-not break long lines at all. Reportedly, some mail servers refuse
-to receive mail with lines that exceed the 1000 character limit
-that is specified by the SMTP standard.
-
-The Postfix SMTP client now breaks long message header or body
-lines by inserting <CR> <LF> <SPACE>. Earlier Postfix versions
-broke long lines by inserting <CR> <LF> only. This broke MIME
-encapsulation, causing MIME attachments to "disappear" with Postfix
-versions after 20010611.
-
-Postfix now discards text when a logical message header exceeds
-$header_size_limit characters (default: 102400). Earlier Postfix
-versions would place excess text, and all following text, in the
-message body. The same thing was done when a physical header line
-exceeded $line_length_limit characters (default: 2048). Both
-behaviors broke MIME encapsulation, causing MIME attachments to
-"disappear" with all previous Postfix versions.
-
-Incompatible changes with Postfix version 1.1.3 (released 20020201)
-===================================================================
-
-In Postfix SMTPD access tables, Postfix now uses <> as the default
-lookup key for the null address, in order to work around bugs in
-some Berkeley DB implementations. This behavior is controlled with
-the smtpd_null_access_lookup_key configuration parameter.
-
-On SCO 3.2 UNIX, the input rate flow control is now turned off by
-default, because of limitations in the SCO UNIX kernel.
-
-Incompatible changes with Postfix version 1.1.2 (released 20020125)
-===================================================================
-
-Postfix now detects if the run-time Berkeley DB library routines
-do not match the major version number of the compile-time include
-file that was used for compiling Postfix. The software issues a
-warning and aborts in case of a discrepancy. If it didn't, the
-software was certain to crash with a segmentation violation.
-
-Incompatible changes with Postfix version 1.1.1 (released 20020122)
-===================================================================
-
-When the postmap command creates a non-existent result file, the
-new file inherits the group/other read permissions of the source
-file.
-
-Incompatible changes with Postfix version 1.1.0 (released 20020117)
-===================================================================
-
-Changes are listed in order of decreasing importance, not release
-date.
-
-[snapshot-20010709] This release introduces a new queue file record
-type that is used only for messages that actually use VERP (variable
-envelope return path) support. With this sole exception, the queue
-file format is entirely backwards compatible with the previous
-official Postfix release (20010228, a.k.a. Postfix 1.0.0).
-
-[snapshot-20020106] This release modifies the existing master.cf
-file. The local pickup service is now unprivileged, and the cleanup
-and flush service are now "public". Should you have to back out to
-a previous release, then you must 1) edit the master.cf file, make
-the pickup service "privileged", and make the cleanup and flush
-services "private"; 2) "chmod 755 /var/spool/postfix/public". To
-revert to a world-writable mail submission directory, "chmod 1733
-/var/spool/postfix/maildrop".
-
-[snapshot-20020106, snapshot-20010808, snapshot-20011103,
-snapshot-20011121] You must stop and restart Postfix because of
-incompatible changes in the local Postfix security model and in
-the Postfix internal protocols. Old and new components will not
-work together.
-
-[snapshot-20020106] Simpler local Postfix security model.
-
-- No world-writable maildrop directory. Postfix now always uses
- the set-gid postdrop command for local mail submissions. The
- local mail pickup daemon is now an unprivileged process.
-
-- No world-accessible pickup and queue manager server FIFOs.
-
-- New set-gid postqueue command for the queue list/flush operations
- that used to implemented by the Postfix sendmail command.
-
-[snapshot-20020106..15] Simpler Postfix installation and upgrading.
-
-- All installation settings are now kept in the main.cf file, and
- better default settings are now generated for system dependent
- pathnames such as sendmail_path etc. The install.cf file is no
- longer used, except when upgrading from an older Postfix version.
-
-- Non-default installation parameter settings can (but do not have
- to) be specified on the "make install" or "make upgrade" command
- line as name=value arguments.
-
-- New postfix-files database (in /etc/postfix) with (pathname,
- owner, permission) information about all Postfix-related files.
-
-- New postfix-install script replaces the awkward INSTALL.sh script.
- This is driven by the postfix-files database. It has better
- support for building packages for distribution to other systems.
- See PACKAGE_README for details.
-
-- New post-install script (in /etc/postfix) for post-installation
- maintenance of directory/file permissions and ownership (this is
- used by "postfix check"). Example:
-
- # postfix stop
- # post-install set-permissions mail_owner=username setgid_group=groupname
- # postfix start
-
-[snapshot-20020106] Postfix will not run if it detects that the
-postfix user or group ID are shared with other accounts on the
-system. The checks aren't exhaustive (that would be too resource
-consuming) but should be sufficient to encourage packagers and
-developers to do the right thing. To fix the problem, use the above
-post-install command, after you have created the appropriate new
-mail_owner or setgid_group user or group IDs.
-
-[snapshot-20020106] If you run multiple Postfix instances on the
-same machine you now have to specify their configuration directories
-in the default main.cf file as "alternate_config_directories =
-/dir1 /dir2 ...". Otherwise, some Postfix commands will no longer
-work: the set-group ID postdrop command for mail submission and
-the set-group ID postqueue command for queue listing/flushing.
-
-[snapshot-20010808] The default setting for the maps_rbl_domains
-parameter is now "empty", because mail-abuse.org has become a
-subscription-based service. The names of the RBL parameters haven't
-changed.
-
-[snapshot-20020106] Postfix SMTP access maps will no longer return
-OK for non-local multi-domain recipient mail addresses (user@dom1@dom2,
-user%dom1@dom2, etcetera); the lookup now returns DUNNO (undetermined).
-Non-local multi-domain recipient addresses were already prohibited
-from matching the permit_mx_backup and the relay_domains-based
-restrictions.
-
-[snapshot-20011210] Stricter checking of Postfix chroot configurations.
-The Postfix startup procedure now warns if "system" directories
-(etc, bin, lib, usr) under the Postfix top-level queue directory
-are not owned by the super-user (usually the result of well-intended,
-but misguided, applications of "chown -R postfix /var/spool/postfix).
-
-[snapshot-20011008] The Postfix SMTP server now rejects requests
-with a generic "try again later" status (451 Server configuration
-error) when it detects an error in smtp_{client, helo, sender,
-recipient, etrn}_restrictions settings. More details about the
-problem are logged to the syslogd; sending such information to
-random clients would be inappropriate.
-
-[snapshot-20011008] Postfix no longer flushes the entire mail queue
-after receiving an ETRN request for a random domain name. Requests
-for domains that do not match $fast_flush_domains are now rejected
-instead.
-
-[snapshot-20011226] Postfix configuration file comments no longer
-continue on the next line when that next line starts with whitespace.
-This change avoids surprises, but it may cause unexpected behavior
-with existing, improperly formatted, configuration files. Caveat
-user. Comment lines are allowed to begin with whitespace. Multi-line
-input is no longer terminated by a comment line, by an all whitespace
-line, or by an empty line.
-
-[snapshot-20010714] Postfix delivery agents now refuse to create
-a missing maildir or mail spool subdirectory when its parent
-directory is world writable. This is necessary to prevent security
-problems with maildirs or with hashed mailboxes under a world
-writable mail spool directory.
-
-[snapshot-20010525] As per RFC 2821, the Postfix SMTP client now
-always sends EHLO at the beginning of an SMTP session. Specify
-"smtp_always_send_ehlo = no" for the old behavior, which is to send
-EHLO only when the server greeting banner contains the word ESMTP.
-
-[snapshot-20010525] As per RFC 2821, an EHLO command in the middle
-of an SMTP session resets the Postfix SMTP server state just like
-RSET. This behavior cannot be disabled.
-
-[snapshot-20010709] The SMTP client now by default breaks lines >
-2048 characters, to avoid mail delivery problems with fragile SMTP
-server software. To get the old behavior back, specify "smtp_break_lines
-= no" in the Postfix main.cf file.
-
-[snapshot-20010709] With recipient_delimiter=+ (or any character
-other than -) Postfix will now recognize address extensions even
-with owner-foo+extension addresses. This change was necessary to
-make VERP useful for mailing list bounce processing.
-
-[snapshot-20010610] The Postfix pipe delivery agent no longer
-automatically case-folds the expansion of $user, $extension or
-$mailbox command-line macros. Specify the 'u' flag to get the old
-behavior.
-
-[snapshot-20011210] The Postfix sendmail command no longer exits
-with status 1 when mail submission fails, but instead returns a
-sendmail-compatible status code as defined in /usr/include/sysexits.h.
-
-Major changes with Postfix version 1.1.0 (Released 20020117)
-============================================================
-
-Changes are listed in order of decreasing importance, not release
-date.
-
-The nqmgr queue manager is now bundled with Postfix. It implements
-a smarter scheduling strategy that allows ordinary mail to slip
-past mailing list mail, resulting in better response. This queue
-manager is expected to become the default queue manager shortly.
-
-[snapshot-20010709, snapshot-20010808] VERP (variable envelope
-return path) support. This is enabled by default, including in
-the SMTP server. See the VERP_README file for instructions. Specify
-"disable_verp_bounces = yes" to have Postfix send one RFC-standard,
-non-VERP, bounce report for multi-recipient mail, even when VERP
-style delivery was requested. This reduces the explosive behavior
-of bounces when sending mail to a list.
-
-[snapshot-20010709] QMQP server support, so that Postfix can be
-used as a backend mailer for the ezmlm-idx mailing list manager.
-You still need qmail to drive ezmlm and to process mailing list
-bounces. The QMQP service is disabled by default. To enable, follow
-the instructions in the QMQP_README file.
-
-[snapshot-20010709] You can now reject unknown virtual(8) recipients
-at the SMTP port by specifying a "domain.name whatever" entry in
-the tables specified with virtual_mailbox_maps, similar to Postfix
-virtual(5) domains. [virtual(8) is the Postfix virtual delivery
-agent, virtual(5) is the Postfix virtual map. The two implement
-virtual domains in a very different manner.]
-
-[snapshot-20011121] Configurable host/domain name wildcard matching
-behavior: choice between "pattern `domain.name' matches string
-`host.domain.name'" (this is to be deprecated in the future) and
-"pattern `.domain.name' matches string `host.domain.name'" (this
-is to be preferred in the future). The configuration parameter
-"parent_domain_matches_subdomains" specifies which Postfix features
-use the behavior that will become deprecated.
-
-[snapshot-20010808] Variable coupling between message receiving
-rates and message delivery rates. When the message receiving rate
-exceeds the message delivery rate, an SMTP server will pause for
-$in_flow_delay seconds before accepting a message. This delay
-gives Postfix a chance catch up and access the disk, while still
-allowing new mail to arrive. This feature currently has effect
-only when mail arrives via a small number of SMTP clients.
-
-[snapshot-20010610, snapshot-20011121, snapshot-20011210] Workarounds
-for a bug in old versions of the CISCO PIX firewall software that
-caused mail to be resent repeatedly. The workaround has no effect
-for other mail deliveries. The workaround is turned off when mail
-is queued for less than $smtp_pix_workaround_threshold_time seconds
-(default: 500 seconds) so that the workaround is normally enabled
-only for deferred mail. The delay before sending .<CR><LF> is now
-controlled by the $smtp_pix_workaround_delay_time setting (default:
-10 seconds).
-
-[snapshot-20011226] Postfix will now do null address lookups in
-SMTPD access maps. If your access maps cannot store or look up
-null string key values, specify "smtpd_null_access_lookup_key =
-<>" and the null sender address will be looked up as <> instead.
-
-[snapshot-20011210] More usable virtual delivery agent, thanks to
-a new "static" map type by Jeff Miller that always returns its map
-name as the lookup result. This eliminates the need for per-recipient
-user ID and group ID tables. See the VIRTUAL_README file for more
-details.
-
-[snapshot-20011125] Anti-sender spoofing. New main.cf parameter
-smtpd_sender_login_maps that specifies the (SASL) login name that
-owns a MAIL FROM sender address. Specify a regexp table in order
-to require a simple one-to-one mapping. New SMTPD restriction
-reject_sender_login_mismatch that refuses a MAIL FROM address when
-$smtpd_sender_login_maps specifies an owner but the client is not
-(SASL) logged in as the MAIL FROM address owner, or when a client
-is (SASL) logged in but does not own the address according to
-$smtpd_sender_login_maps.
-
-[snapshot-20011121] The mailbox_command_maps parameter allows you
-to configure the external delivery command per user (local delivery
-agent only). This feature has precedence over the mailbox_command
-and home_mailbox settings.
-
-[snapshot-20011121] New "warn_if_reject" smtpd UCE restriction that
-only warns if the restriction that follows would reject mail. Look
-for file records that contain the string "reject_warning".
-
-[snapshot-20011127] New header/body_check result "WARN" to make
-Postfix log a warning about a header/body line without rejecting
-the content.
-
-[snapshot-20011103] In header/body_check files, REJECT can now be
-followed by text that is sent to the originator. That feature was
-stuck waiting for years, pending the internal protocol revision.
-
-[snapshot-20011008] The permit_mx_backup feature allows you to
-specify network address blocks via the permit_mx_backup_networks
-parameter. This requires that the primary MX hosts for the given
-destination match the specified network blocks. When no value is
-given for permit_mx_backup_networks, Postfix will accept mail
-whenever the local MTA is listed in the DNS as an MX relay host
-for a destination, even when you never gave permission to do so.
-
-[snapshot-20010709] Specify "mail_spool_directory = /var/mail/"
-(note the trailing "/" character) to enable maildir format for
-/var/mail/username.
-
-[snapshot-20010808] Finer control over address masquerading. The
-masquerade_classes parameter now controls header and envelope sender
-and recipient addresses. With earlier Postfix versions, address
-masquerading rewrote all addresses except for the envelope recipient.
-
-[snapshot-20010610] The pipe mail delivery agent now supports proper
-quoting of white space and other special characters in the expansions
-of the $sender and $recipient command-line macros. This was necessary
-for correct operation of the "simple" content filter, and is also
-recommended for delivery via UUCP or BSMTP.
-
-[snapshot-20010610] The pipe mail delivery agent now supports case
-folding the localpart and/or domain part of expansions of the
-$nexthop, $recipient, $user, $extension or $mailbox command-line
-macros. This is recommended for mail delivery via UUCP. Bug: $nexthop
-is always case folded because of problems in the queue manager
-code.
-
-[snapshot-20010525] This release contains many little revisions of
-little details in the light of the new RFC 2821 and RFC 2822
-standards. Changes that may affect interoperability are listed
-above under "incompatible changes". Other little details are
-discussed in comments in the source code.
-
-[snapshot-20010502] The Postfix SMTP client now by default randomly
-shuffles destination IP addresses of equal preference (whether
-obtained via MX lookup or otherwise). Reportedly, this is needed
-for sites that use Bernstein's dnscache program. Specify
-"smtp_randomize_addresses = no" to disable this behavior. Based on
-shuffling code by Aleph1.
-
-[snapshot-20011127] New parameter smtpd_noop_commands to specify
-a list of commands that the Postfix SMTP server treats as NOOP
-commands (no syntax check, no state change). This is a workaround
-for misbehaving clients that send unsupported commands such as
-ONEX.
-
-[snapshot-20010502] "postmap -q -" and "postmap -d -" read key
-values from standard input, which makes it easier to drive them
-from another program. The same feature was added to the postalias
-command.
-
-[snapshot-20010502] The postsuper command now has a command-line
-option to delete queue files. In principle this command can be
-used while Postfix is running, but there is a possibility of deleting
-the wrong queue file when Postfix deletes a queue file and reuses
-the queue ID for a new message. In that case, postsuper will delete
-the new message.
-
-[snapshot-20010525] The postsuper queue maintenance tool now renames
-files whose name (queue ID) does not match the message file inode
-number. This is necessary after a Postfix mail queue is restored
-from another machine or from backups. The feature is selected with
-the -s option, which is the default, and runs whenever Postfix is
-started.
-
-[snapshot-20010525] The postsuper queue maintenance tool has a new
--r (requeue) option for subjecting some or all queue files to
-another iteration of address rewriting. This is useful after the
-virtual or canonical maps have changed.
-
-[snapshot-20010525] The postsuper queue maintenance tool was extended
-with options to read queue IDs from standard input. This makes the
-tool easier to drive from scripts.
-
-[snapshot-20010329] Better support for running multiple Postfix
-instances on one machine. Each instance can be recognized by its
-logging (defaults: "syslog_name = postfix", "syslog_facility =
-mail").
-
-Major incompatible changes with release-20010228 Patch 01 (a.k.a. Postfix 1.0.1)
-================================================================================
-
-This release changes the names of the "fast ETRN" logfiles with
-delayed mail per destination. These files are maintained by the
-Postfix "fast flush" daemon. The old scheme failed with addresses
-of the form user@[ip.address] and user@a.domain.name. In order to
-populate the new "fast ETRN" logfiles, execute the command "sendmail
--q". The old "fast ETRN" logfiles go away by themselves (default:
-after 7 days).
-
-Major incompatible changes with release-20010228 (a.k.a. Postfix 1.0.0)
-=======================================================================
-
-[snapshot-20010225] POSTFIX NO LONGER RELAYS MAIL FOR CLIENTS IN
-THE ENTIRE CLASS A/B/C NETWORK. To get the old behavior, specify
-"mynetworks_style = class" in the main.cf file. The default
-(mynetworks_style = subnet) is to relay for clients in the local
-IP subnet. See conf/main.cf.
-
-[snapshot-20001005, snapshot-20010225] You must execute "postfix
-stop" before installing this release. Some recommended parameter
-settings have changed, and a new entry must be added to the master.cf
-file before you can start Postfix again.
-
-1 - The recommended Postfix configuration no longer uses flat
- directories for the "incoming" "active", "bounce", and "defer"
- queue directories. The "flush" directory for the new "flush"
- service directory should not be flat either.
-
- Upon start-up, Postfix checks if the hash_queue_names configuration
- parameter is properly set up, and will add any queue directory
- names that are missing.
-
-2 - In order to improve performance of one-to-one mail deliveries
- the queue manager will now look at up to 10000 queue files
- (was: 1000). The default qmgr_message_active_limit setting
- was changed accordingly.
-
- If you have a non-default qmgr_message_active_limit in main.cf,
- you may want adjust it.
-
-3 - The new "flush" service needs to be configured in master.cf.
-
- Upon start-up, Postfix checks if the new "flush" service is
- configured in the master.cf file, and will add an entry if it
- is missing.
-
-Should you wish to back out to a previous Postfix release there is
-no need to undo the above queue configuration changes.
-
-[snapshot-20000921] The protocol between queue manager and delivery
-agents has changed. This means that you cannot mix the Postfix
-queue manager or delivery agents with those of Postfix versions
-prior to 20000921. This change does not affect Postfix queue file
-formats.
-
-[snapshot-20000529] This release introduces an incompatible queue
-file format change ONLY when content filtering is enabled (see text
-in FILTER_README). Old Postfix queue files will work fine, but
-queue files with the new content filtering info will not work with
-Postfix versions before 20000529. Postfix logs a warning and moves
-incompatible queue files to the "corrupt" mail queue subdirectory.
-
-Minor incompatible changes with release-20010228
-================================================
-
-[snapshot-20010225] The incoming and deferred queue directories
-are now hashed by default. This improves the performance considerably
-under heavy load, at the cost of a small but noticeable slowdown
-when one runs "mailq" on an unloaded system.
-
-[snapshot-20010222] Postfix no longer automatically delivers
-recipients one at a time when their domain is listed in $mydestination.
-This change solves delivery performance problems with delivery via
-LMTP, with virus scanning, and with firewall relays that forward
-all mail for $mydestination to an inside host.
-
-The "one recipient at a time" delivery behavior is now controlled
-by the per-transport recipient limit (xxx_destination_recipient_limit,
-where xxx is the name of the delivery mechanism). This parameter
-controls the number of recipients that can be sent in one delivery
-(surprise).
-
-The setting of the per-transport recipient limit also controls the
-meaning of the per-transport destination concurrency limit (named
-xxx_destination_concurrency_limit, where xxx is again the name of
-the delivery mechanism):
-
- 1) When the per-transport recipient limit is 1 (i.e., send one
- recipient per delivery), the per-transport destination concurrency
- limit controls the number of simultaneous deliveries to the
- same recipient. This is the default behavior for delivery via
- the Postfix local delivery agent.
-
- 2) When the per-transport recipient limit is > 1 (i.e., send
- multiple recipients per delivery), the per-transport destination
- concurrency limit controls the number of simultaneous deliveries
- to the same domain. This is the default behavior for all other
- Postfix delivery agents.
-
-[snapshot-20010128] The Postfix local delivery agent now enforces
-mailbox file size limits (default: mailbox_size_limit = 51200000).
-This limit affects all file write access by the local delivery
-agent or by a process run by the local delivery agent. The purpose
-of this parameter is to act as a safety for run-away software. It
-cannot be a substitute for a file quota management system. Specify
-a limit of 0 to disable.
-
-[snapshot-20010128] REJECT in header/body_checks is now flagged as
-policy violation rather than bounce, for consistency in postmaster
-notifications.
-
-[snapshot-20010128] The default RBL (real-time blackhole lists)
-domain examples have been changed from *.vix.com to *.mail-abuse.org.
-
-[snapshot-20001210] Several interfaces of libutil and libglobal
-routines have changed. This may break third-party code written
-for Postfix. In particular, the safe_open() routine has changed,
-the way the preferred locking method is specified in the sys_defs.h
-file, as well as all routines that perform file locking. When
-compiling third-party code written for Postfix, the incompatibilities
-will be detected by the compiler provided that #include file
-dependencies are properly maintained.
-
-[snapshot-20001210] When delivering to /file/name (as directed in
-an alias or .forward file), the local delivery agent now logs a
-warning when it is unable to create a /file/name.lock file. Mail
-is still delivered as before.
-
-[snapshot-20001210] The "sun_mailtool_compatibility" feature is
-going away (a compatibility mode that turns off kernel locks on
-mailbox files). It still works, but a warning is logged. Instead
-of using "sun_mailtool_compatibility", specify the mailbox locking
-strategy as "mailbox_delivery_lock = dotlock".
-
-[snapshot-20001210] The Postfix SMTP client now skips SMTP server
-replies that do not start with "CODE SPACE" or with "CODE HYPHEN"
-and flags them as protocol errors. Older Postfix SMTP clients
-silently treated "CODE TEXT" as "CODE SPACE TEXT", i.e. as a valid
-SMTP reply.
-
-[snapshot-20001121] On RedHat Linux 7.0, you must install the
-db3-devel RPM before you can compile the Postfix source code.
-
-[snapshot-20000924] The postmaster address in the "sorry" text at
-the top of bounced mail is now just postmaster, not postmaster@machine.
-The idea is to refer users to their own postmaster.
-
-[snapshot-20000921] The notation of [host:port] in transport tables
-etc. is going away but it is still supported. The preferred form
-is now [host]:port. This change is necessary to support IPV6
-address forms which use ":" as part of a numeric IP address. In a
-future release, Postfix will log a warning when it encounters the
-[host:port] form.
-
-[snapshot-20000921] In mail headers, Errors-To:, Reply-To: and
-Return-Receipt: addresses are now rewritten as a sender address
-(was: recipient).
-
-[snapshot-20000921] Postfix no longer inserts Sender: message
-headers.
-
-[snapshot-20000921] The queue manager now logs the original number
-of recipients when opening a queue file (example: from=<>, size=3502,
-nrcpt=1).
-
-[snapshot-20000921] The local delivery agent no longer appends a
-blank line to mail that is delivered to external command.
-
-[snapshot-20000921] The pipe delivery agent no longer appends a
-blank line when the F flag is specified (in the master.cf file).
-Specify the B flag if you need that blank line.
-
-[snapshot-20000507] As required by RFC 822, Postfix now inserts a
-generic destination message header when no destination header is
-present. The text is specified via the undisclosed_recipients_header
-configuration parameter (default: "To: undisclosed-recipients:;").
-
-[snapshot-20000507] The Postfix sendmail command treats a line with
-only `.' as the end of input, for the sake of sendmail compatibility.
-To disable this feature, specify the sendmail-compatible `-i' or
-`-oi' flags on the sendmail command line.
-
-[snapshot-20000507] For the sake of Sendmail compatibility, the
-Postfix SMTP client skips over SMTP servers that greet with a 4XX
-or 5XX reply code, treating them as unreachable servers. To obtain
-prior behavior (4XX=retry, 5XX=bounce), specify "smtp_skip_4xx_greeting
-= no" and "smtp_skip_5xx_greeting = no".
-
-Major changes with release-20010228
-===================================
-
-Postfix produces DSN formatted bounced/delayed mail notifications.
-The human-readable text still exists, so that users will not have
-to be unnecessarily confused by all the ugliness of RFC 1894. Full
-DSN support will be later.
-
-This release introduces full content filtering through an external
-process. This involves an incompatible change in queue file format.
-Mail is delivered to content filtering software via an existing
-mail delivery agent, and is re-injected into Postfix via an existing
-mail submission agent. See examples in the FILTER_README file.
-Depending on how the filter is implemented, you can expect to lose
-a factor of 2 to 4 in delivery performance of SMTP transit mail,
-more if the content filtering software needs lots of CPU or memory.
-
-Specify "body_checks = regexp:/etc/postfix/body_checks" for a quick
-and dirty emergency content filter that looks at non-header lines
-one line at a time (including MIME headers inside the message body).
-Details in conf/sample-filter.cf.
-
-The header_checks and body_checks features can be used to strip
-out unwanted data. Specify IGNORE on the right-hand side and the
-data will disappear from the mail.
-
-Support for SASL (RFC 2554) authentication in the SMTP server and
-in the SMTP and LMTP clients. See the SASL_README file for more
-details. This file still needs better examples.
-
-Postfix now ships with an LMTP delivery agent that can deliver over
-local/remote TCP sockets and over local UNIX-domain sockets. The
-LMTP_README file gives example, but still needs to be revised.
-
-Fast "ETRN" and "sendmail -qR". Postfix maintains per-destination
-logfiles with information about what mail is queued for selected
-destinations. See the file ETRN_README for details.
-
-The mailbox locking style is now fully configurable at runtime.
-The new configuration parameter is called "mailbox_delivery_lock".
-Depending on the operating system type, mailboxes can be locked
-with one or more of "flock", "fcntl" or "dotlock". The command
-"postconf -l" shows the available locking styles. The default
-mailbox locking style is system dependent. This change affects
-all mailbox and all "/file/name" deliveries by the Postfix local
-delivery agent.
-
-Minor changes with release-20010228
-===================================
-
-You can now specify multiple SMTP destinations in the relayhost
-and fallback_relay configuration parameters. The destinations are
-tried in the specified order. Specify host or host:port (perform
-MX record lookups), [host] or [host]:port (no MX record lookups),
-[address] or [address]:port (numerical IP address).
-
-The "mailbox_transport" and "fallback_transport" parameters now
-understand the form "transport:nexthop", with suitable defaults
-when either transport or nexthop are omitted, just like in the
-Postfix transport map. This allows you to specify for example,
-"mailbox_transport = lmtp:unix:/file/name".
-
-The local_transport and default_transport configuration parameters
-can now be specified in transport:destination notation, just like
-the mailbox_transport and fallback_transport parameters. The
-:destination part is optional. However, these parameters take only
-one destination, unlike relayhost and fallback-relay which take
-any number of destinations.
-
-More general virtual domain support. Postfix now supports both
-Sendmail-style virtual domains and Postfix-style virtual domains.
-Details and examples are given in the revised virtual manual page.
-
-- With Sendmail-style virtual domains, local users/aliases/mailing
- lists are visible as localname@virtual.domain. This is convenient
- if you want to host mailing lists under virtual domains.
-
-- With Postfix-style virtual domains, local users/aliases/mailing
- lists are not visible as localname@virtual.domain. Each virtual
- domain has its own separate name space.
-
-More general "soft bounce" feature. Specify "soft_bounce = yes"
-in main.cf to prevent the SMTP server from bouncing mail while you
-are testing configurations. Until this release the SMTP server was
-not aware of soft bounces.
-
-Workarounds for non-standard RFC 2554 (AUTH command) implementations.
-Specify "broken_sasl_auth_clients = yes" to enable SMTP server
-support for old Microsoft client applications. The Postfix SMTP
-client supports non-standard RFC 2554 servers by default.
-
-All time-related configuration parameters now accept a one-letter
-suffix to indicate the time unit (s: second, m: minute, h: hour,
-d: day, w: week). The exceptions are the LDAP and MYSQL modules
-which are maintained separately.
-
-New "import_environment" and "export_environment" configuration
-parameters provide explicit control over what environment variables
-Postfix will import, and what environment variables Postfix will
-pass on to a non-Postfix process.
-
-In order to improve performance of one-to-one deliveries, Postfix
-by default now looks at up to 10000 messages at a time (was: 1000).
-
-Specify "syslog_facility = log_local1" etc. to separate the logging
-from multiple Postfix instances. However, a non-default logging
-facility takes effect only after process initialization. Errors
-during command-line parsing are still logged with the default syslog
-facility, as are errors while processing the main.cf file.
-
-Postfix now strips out Content-Length: headers in incoming mail to
-avoid confusion in mail user agents.
-
-Specify "require_home_directory = yes" to prevent mail from being
-delivered to a user whose home directory is not mounted. This
-feature is implemented by the Postfix local delivery agent.
-
-The pipe mailer has a size limit (size=nnn) command-line argument.
-
-The pipe delivery agent has a configurable end-of-line attribute.
-Specify "pipe ... eol=\r\n" for delivery mechanisms that require
-CRLF record delimiters. The eol attribute understands the following
-C-style escape sequences: \a \b \f \n \r \t \v \nnn \\.
-
-In master.cf you can selectively override main.cf configuration
-parameters, for example: "smtpd -o myhostname=foo.com".
-
-In main.cf, specify "smtp_bind_address=x.x.x.x" to bind SMTP
-connections to a specific local interface. Or override the default
-setting in master.cf with "smtp -o smtp_bind_address=x.x.x.x".
-For now, you must specify a numeric IP address.
-
-Questionable feature: with "smtp_always_send_ehlo = yes", the SMTP
-client sends EHLO regardless of the content of the SMTP server's
-greeting.
-
-Specify "-d key" to postalias or postmap in order to remove one
-key. This still needs to be generalized to multi-key removal (e.g.,
-read keys from stdin).
-
-Comments in Postfix configuration files no longer contain troff
-formatting codes. The text is now generated from prototype files
-in a new "proto" subdirectory.
-
-Major changes with postfix-19991231:
-====================================
-
-- It is now much more difficult to configure Postfix as an open
-relay. The SMTP server requires that "smtpd_recipient_restrictions"
-contains at least one restriction that by default refuses mail (as
-is the default). There were too many accidents with changes to
-the UCE restrictions.
-
-- The relay_domains parameter no longer needs to contain $virtual_maps.
-
-- Overhauled FAQ (html/faq.html) with many more examples.
-
-- Updated UCE documentation (html/uce.html) with more examples.
-More UCE configuration examples in sample configuration files.
-
-- Several little improvements to the installation procedure:
-relative symlinks, configurable directory for scratch files so the
-installation can be done without write access to the build tree.
-
-- Updated LDAP client code (John Hensley).
-
-- Updated mysql client code (Scott Cotton).
-
-- The SMTP server now rejects mail for unknown users in virtual
-domains that are defined by Postfix virtual maps.
-
-- The SMTP server can reject mail for unknown local users. Specify
-"local_recipient_maps = $alias_maps, unix:passwd.byname" if your
-local mail is delivered by a UNIX-style local delivery agent. See
-example in conf/main.cf.
-
-- Use "disable_vrfy_command = yes" to disable the SMTP VRFY command.
-This prevents some forms of address harvesting.
-
-- The sendmail "-f" option now understands <user> and even understands
-forms with RFC 822-style comments.
-
-- New "qmgr_fudge_factor" parameter allows you to balance mailing
-list performance against response time for one-to-one mail. The
-fudge factor controls what percentage of delivery resources Postfix
-will devote to one message. With 100%, delivery of one message
-does not begin before delivery of the previous message is completed.
-This is good for list performance, bad for one-to-one mail. With
-10%, response time for one-to-one mail improves much, but list
-performance suffers: in the worst case, people near the start of a
-mailing list get a burst of postings today, while people near the
-end of the list get that same burst of postings a whole day later.
-
-- It is now relatively safe to configure 550 status codes for the
-main.cf unknown_address_reject_code or unknown_client_reject_code
-parameters. The SMTP server now always sends a 450 (try again)
-reply code when an UCE restriction fails due to a soft DNS error,
-regardless of what main.cf specifies.
-
-- The RBL checks now show the content of TXT records (Simon J Mudd).
-
-- The Postfix SMTP server now understands a wider range of illegal
-address forms in MAIL FROM and RCPT TO commands. In order to disable
-illegal forms, specify "strict_rfc821_envelopes = yes". This also
-disables support for MAIL FROM and RCPT TO addresses without <>.
-
-- Per-client/helo/sender/recipient UCE restrictions (fully-recursive
-UCE restriction parser). See the RESTRICTION_CLASS file for details.
-
-- Use "postmap -q key" or "postalias -q key" for testing Postfix
-lookup tables or alias files.
-
-- Use "postconf -e name=value..." to edit the main.cf file. This
-is easier and safer than editing the main.cf file by hand. The
-edits are done on a temporary copy that is renamed into place.
-
-- Use "postconf -m" to display all supported lookup table types
-(Scott Cotton).
-
-- New "permit_auth_destination" UCE restriction for finer-grained
-access control (Jesper Skriver).
-
-Incompatible changes with postfix-19990906
-==========================================
-
-- On systems that use user.lock files to protect system mailboxes
-against simultaneous updates, Postfix now uses /file/name.lock
-files while delivering to files specified in aliases/forward/include
-files. This is a no-op when the recipient lacks directory write
-permission.
-
-- The LDAP client code no longer looks up a name containing "*"
-because it could be abused. See the LDAP_README file for how to
-restore previous behavior.
-
-- The Postfix to PCRE interface now expects PCRE version 2.08.
-Postfix is no longer compatible with PCRE versions prior to 2.06.
-
-Major changes with postfix-19990906
-===================================
-
-Several bugfixes, none related to security. See the HISTORY file
-for a complete list of changes.
-
-- Postfix is now distributed under IBM Public License Version 1.0
-which does not carry the controversial termination clause. The new
-license does have a requirement that contributors make source code
-available.
-
-- INSTALL.sh install/upgrade procedure that replaces existing
-programs and shell scripts instead of overwriting them, and that
-leaves existing queue files and configuration files alone.
-
-- The ugly Delivered-To: header can now be turned off selectively.
-The default setting is: "prepend_delivered_header = command, file,
-forward". Turning off the Delivered-To: header when forwarding
-mail is not recommended.
-
-- mysql client support by Scott Cotton and Joshua Marcus, Internet
-Consultants Group, Inc. See the file MYSQL_README for instructions.
-
-- reject_unauth_destination SMTP recipient restriction that rejects
-destinations not in $relay_domains. Unlike the check_relay_domains
-restriction, reject_unauth_destination ignores the client hostname.
-By Lamont Jones of Hewlett-Packard.
-
-- reject_unauth_pipelining SMTP *anything* restriction to stop mail
-from spammers that improperly use SMTP command pipelining to speed
-up their deliveries.
-
-- Postfix "sendmail" now issues a warning and drops privileges if
-installed set-uid root.
-
-- No more duplicate delivery when "postfix reload" is immediately
-followed by "sendmail -q".
-
-- No more "invalid argument" errors when a Postfix daemon opens a
-DB/DBM file while some other process is changing the file.
-
-- Portability to the Mac OS X Server, Reliant Unix, AIX 3.2.5 and
-Ultrix 4.3.
-
-Incompatible changes with postfix-19990601:
-===========================================
-
-- The SMTP server now delays all UCE restrictions until the RCPT
-TO, VRFY or ETRN command. This makes the restrictions more useful,
-because many SMTP clients do not expect negative responses earlier
-in the protocol. In order to restore the old behavior, specify
-"smtpd_delay_reject = no" in /etc/postfix/main.cf.
-
-- The Postfix local delivery agent no longer automatically propagates
-address extensions to aliases/include/forward addresses. Specify
-"propagate_unmatched_extensions = canonical, virtual, alias, forward,
-include" to restore the old behavior.
-
-- The Postfix local delivery agent no longer does $name expansion
-on words found in the mailbox_command configuration parameter. This
-makes it easier to specify shell syntax. See conf/main.cf.
-
-- The luser_relay syntax has changed. You can specify one address;
-it is subjected to $user, etc. expansions. See conf/main.cf.
-
-- File system reorganization: daemon executables are now in the
-libexec subdirectory, command executables in the bin subdirectory.
-The INSTALL instructions now recommend installing daemons and
-commands into separate directories.
-
-Major changes with postfix-19990601:
-=====================================
-
-- New USER, EXTENSION, LOCAL, DOMAIN and RECIPIENT environment
-variables for delivery to command (including mailbox_command) by
-the local delivery agent. As you might expect, the information is
-censored. The list of acceptable characters is specified with the
-command_expansion_filter configuration parameter. Unacceptable
-characters are replaced by underscores. See html/local.8.html.
-
-- Specify "forward_path = /var/forward/$user" to avoid looking up
-.forward files in user home directories. The default value is
-$home/.forward$recipient_delimiter$extension, $home/.forward.
-Initial code by Philip A. Prindeville, Mirapoint, Inc., USA.
-
-- Conditional $name expansion in forward_path and luser_relay.
-Available names are: $user (bare user name) $shell (user login
-shell), $home (user home directory), $local (everything to the left
-of @), $extension (optional address extension), $domain (everything
-to the right of @), $recipient (the complete address) and
-$recipient_delimiter. A simple $name expands as usual. ${name?value}
-expands to value when $name is defined. ${name:value} expands to
-value when $name is not defined. With ${name?value} and ${name:value},
-the value is subject to another iteration of $name expansion.
-
-- POSIX regular expression support, enabled by default on 4.4BSD,
-LINUX, HP-UX, and Solaris 2.5 and later. See conf/sample-regexp.cf.
-Initial code by Lamont Jones, Hewlett-Packard, borrowing heavily
-from the PCRE implementation by Andrew McNamara, connect.com.au
-Pty. Ltd., Australia.
-
-- Regular expression checks for message headers. This requires
-support for POSIX or for PCRE regular expressions. Specify
-"header_checks = regexp:/file/name" or "header_checks = pcre:/file/name",
-and specify "/^header-name: badstuff/ REJECT" in the pattern file
-(patterns are case-insensitive by default). Code by Lamont Jones,
-Hewlett-Packard. It is to be expected that full content filtering
-will be delegated to an external command.
-
-- Regular expression support for all lookup tables, including access
-control (full mail addresses only), address rewriting (canonical/virtual,
-full mail addresses only) and transport tables (full domain names
-only). However, regular expressions are not allowed for aliases,
-because that would open up security exposures.
-
-- Automatic detection of changes to DB or DBM lookup tables. This
-eliminates the need to run "postfix reload" after each change to
-the SMTP access table, or to the canonical, virtual, transport or
-aliases tables.
-
-- New error mailer. Specify ".domain.name error:domain is undeliverable"
-in the transport table to bounce mail for entire domains.
-
-- No more Postfix lockups on Solaris (knock on wood). The code no
-longer uses Solaris UNIX-domain sockets, because they are still
-broken, even with Solaris 7.
-
-- Workaround for the Solaris mailtool, which keeps an exclusive
-kernel lock on the mailbox while its window is not iconified (specify
-"sun_mailtool_compatibility = yes" in main.cf).
-
-- Questionable workaround for Solaris, which reportedly loses
-long-lived exclusive locks that are held by the master daemon.
-
-- New reject_unknown_{sender,recipient}_domain restrictions for
-sender and recipient mail addresses that distinguish between soft
-errors (always 450) and hard errors (unknown_address_reject_code,
-default 450).
-
-- MIME-encapsulated bounce messages, making it easier to recover
-bounced mail. Initial implementation by Philip A. Prindeville,
-Mirapoint, Inc., USA. Support for RFC 1892 (multipart/report) and
-RFC 1894 (DSN) will have to wait until Postfix internals have been
-revised to support RFC 1893.
-
-- Separately configurable "postmaster" addresses for single bounces
-(bounce_notice_recipient), double bounces (2bounce_notice_recipient),
-delayed mail (delay_notice_recipient), and for mailer error reports
-(error_notice_recipient). See conf/main.cf.
-
-- Questionable feature: specify "best_mx_transport = local" if
-this machine is the best MX host for domains not in mydestinations.
-
-Incompatible changes with postfix-19990317:
-===========================================
-
-- You MUST install the new version of /etc/postfix/postfix-script.
-
-- The pipe mailer "flags" syntax has changed. You now explicitly
-MUST specify the R flag in order to generate a Return-Path: message
-header (as needed by, for example, cyrus).
-
-Major changes with postfix-19990317:
-====================================
-
-A detailed record of changes is given in the HISTORY file.
-
-- Less postmaster mail. Undeliverable bounce messages (double
-bounces) are now discarded. Specify "notify_classes = 2bounce..."
-to get copies of double bounces. Specify "notify_classes = bounce..."
-to get copies of normal and double bounces.
-
-- Improved LDAP client code by John Hensley of Merit Network, USA.
-See LDAP_README for details.
-
-- Perl-compatible regular expression support for lookup maps by
-Andrew McNamara, connect.com.au Pty. Ltd., Australia.. Example:
-"check_recipient_access pcre:/etc/postfix/sample-pcre.cf". Regular
-expressions provide a powerful tool not only for SMTP access control
-but also for address rewriting. See PCRE_README for details.
-
-- Automatic notification of delayed mail (disabled by default).
-With "delay_warning_time = 4", Postfix informs senders when mail
-has not been delivered after 4 hours. Initial version of the code
-by Daniel Eisenbud, University of California at Berkeley. In order
-to get postmaster copies of such warnings, specify "notify_classes
-= delay...".
-
-- More configurable local delivery: "mail_spool_directory" to
-specify the UNIX mail spool directory; "mailbox_transport" to
-delegate all mailbox delivery to, for example, cyrus, and
-"fallback_transport" to delegate delivery of only non-UNIX users.
-And all this without losing local aliases and local .forward
-processing. See config/main.cf and config/master.cf.
-
-- Several changes to improve Postfix behavior under worst-case
-conditions (frequent Postfix restarts/reloads combined with lots
-if inbound mail, intermittent connectivity problems, SMTP servers
-that become comatose after receiving QUIT).
-
-- More NFS-friendly mailbox delivery. The local delivery agent
-now avoids using root privileges where possible.
-
-- For sites that do not receive mail at all, mydestination can now
-be an empty string. Be sure to set up a transport table entry to
-prevent mail from looping.
-
-- New "postsuper" utility to clean up stale files from Postfix
-queues.
-
-- Workaround for BSD select() collisions that cause performance
-problems on large BSD systems.
-
-- Several questionable but useful features to capture mail:
-"always_bcc = address" to capture a copy of every message that
-enters the system, and "luser_relay = address" to capture mail for
-unknown recipients (does not work when mailbox_transport or
-fallback_transport are being used).
-
-- Junk mail controls: new reject_non_fqdn_{hostname,sender,recipient}
-restrictions to reject non-FQDN arguments in HELO, MAIL FROM and
-RCPT TO commands, and stricter checking of numeric HELO arguments.
-
-- "fallback_relay" feature for sites that use DNS but that can't
-talk to the entire world. The fall-back relay gets the mail when
-a destination is not found in the DNS or when the destination is
-found but not reachable.
-
-- Several questionable controls that can help to keep mail going:
-specify "smtp_skip_4xx_greeting = yes" to skip SMTP servers that
-greet with 4XX, "ignore_mx_lookup_error = yes" to look up an A
-record when a DNS server does not respond to an MX query.
-
-Incompatible changes with postfix-beta-19990122-pl01:
-=====================================================
-
-None.
-
-Major changes with postfix-beta-19990122-pl01:
-==============================================
-
-- Restrict who may use ETRN and what domains may be specified.
-Example: "smtpd_etrn_restrictions = permit_mynetworks, reject".
-
-- BIFF notifications. For compatibility reasons this feature is
-on by default. Specify "biff = no" in main.cf if your machine has
-lots of shell users.
-
-- With "soft_bounce = yes", defer delivery instead of bouncing
-mail. This is a safety net for configuration errors with delivery
-agents. It has no effect on errors in virtual maps, canonical maps,
-or in junk mail restrictions.
-
-- Specify "owner_request_special = no" to turn off special treatment
-of owner-foo and foo-request addresses.
-
-Incompatible changes with postfix-beta-19990122:
-================================================
-
-- The syntax of the transport table has changed. An entry like:
-
- customer.org smtp:[gateway.customer.org]
-
- no longer forwards mail for anything.customer.org. For that you
- need to specify:
-
- customer.org smtp:[gateway.customer.org]
- .customer.org smtp:[gateway.customer.org]
-
- This change makes transport tables more compatible with
- sendmail mailer tables.
-
-- The format of syslog records has changed. A client is now always
-logged as hostname[address]; the pickup daemon logs queue file uid
-and sender address.
-
-Major changes with postfix-beta-19990122:
-=========================================
-
-- Junk mail restrictions can now be postponed to the RCPT TO command.
-Specify: "smtpd_recipient_restrictions = reject_maps_rbl...".
-
-- More flexible interface for delivery to e.g., cyrus IMAP without
-need for PERL scripts to munge recipient addresses. In addition to
-$sender, $nexthop and $recipient, the pipe mailer now also supports
-$user, $extension and $mailbox.
-
-- New mail now has precedence over deferred mail, plus some other
-tweaks to make bulk mail go faster. But it ain't no cure for massive
-network outages.
-
-- Watchdog timer for systems that cause the Postfix queue manager
-to lock up, so it recovers without human intervention.
-
-- Delivery to qmail-style maildir files, which is good for NFS
-environments. Specify "home_mailbox = Maildir/", or specify
-/file/name/ in aliases or in .forward files. The trailing / is
-required to turn on maildir delivery.
+New sender address verification blocks mail from addresses that
+are not deliverable. This is turned on with the reject_unverified_sender
+UCE restriction. Addresses are verified by probing, that is, by
+sending mail that is not actually delivered (SMTP interruptus).
+Detailed information is in the SENDER_VERIFICATION_README file
+and sample-verify.cf.
-- Incremental updates of aliases and maps. Specify "postmap -i
-mapname" and it will read new entries from stdin.
+Address verification uses the new "verify" daemon that maintains
+a database. The necessary entry is automatically added to master.cf
+when you upgrade.
-- Newaliases will now update more than one alias database.
-Specify the names with the main.cf "alias_database" parameter.
+New "sendmail -bv" option. Postfix probes the specified recipient
+addresses without actually delivering mail, and sends back an email
+delivery report. This is useful for testing address rewriting and
+address routing of both envelope and header addresses. This feature
+currently does not access or update the sender address verification
+database.
-- Address masquerading exceptions to prevent users from being
-masqueraded. Specify "masquerade_exceptions = root".
+Improved "sendmail -v" behavior. Postfix delivers mail as usual,
+and emails a report of all the delivery attempts to the originator.
-- A pipelined SMTP client. Deliveries to Postfix, qmail, LSOFT,
-zmailer, and exim (once it's fixed) speed up by some 30% for short
-messages with one recipient, with more for multi-recipient mails.
+Bounce reports now show the original recipient information in
+addition to the final recipient that was already available.
-- Hook for local delivery to "|command" via the smrsh restricted
-shell, to restrict what commands may be used in .forward etc. files.
-Specify "local_command_shell = /some/where/smrsh -c".
+Both "sendmail -bv" and "sendmail -v" use the new "trace" daemon
+that is automatically added to master.cf when you upgrade.
--- /dev/null
+In the text below, incompatible changes are labeled with the Postfix
+snapshot that introduced the change. If you upgrade from a later
+Postfix version, then you do not have to worry about that particular
+incompatibility.
+
+Official Postfix releases are called a.b.c where a=major release
+number, b=minor release number, c=patchlevel. Snapshot releases
+are now called a.b.c-yyyymmdd where yyyymmdd is the release date
+(yyyy=year, mm=month, dd=day). The mail_release_date configuration
+parameter contains the release date (both for official release and
+snapshot release). Patches change the patchlevel and the release
+date. Snapshots change only the release date, unless they include
+the same bugfixes as a patch release.
+
+Incompatible changes with Postfix version 1.1.0 (released 20020117)
+===================================================================
+
+Changes are listed in order of decreasing importance, not release
+date.
+
+[snapshot-20010709] This release introduces a new queue file record
+type that is used only for messages that actually use VERP (variable
+envelope return path) support. With this sole exception, the queue
+file format is entirely backwards compatible with the previous
+official Postfix release (20010228, a.k.a. Postfix 1.0.0).
+
+[snapshot-20020106] This release modifies the existing master.cf
+file. The local pickup service is now unprivileged, and the cleanup
+and flush service are now "public". Should you have to back out to
+a previous release, then you must 1) edit the master.cf file, make
+the pickup service "privileged", and make the cleanup and flush
+services "private"; 2) "chmod 755 /var/spool/postfix/public". To
+revert to a world-writable mail submission directory, "chmod 1733
+/var/spool/postfix/maildrop".
+
+[snapshot-20020106, snapshot-20010808, snapshot-20011103,
+snapshot-20011121] You must stop and restart Postfix because of
+incompatible changes in the local Postfix security model and in
+the Postfix internal protocols. Old and new components will not
+work together.
+
+[snapshot-20020106] Simpler local Postfix security model.
+
+- No world-writable maildrop directory. Postfix now always uses
+ the set-gid postdrop command for local mail submissions. The
+ local mail pickup daemon is now an unprivileged process.
+
+- No world-accessible pickup and queue manager server FIFOs.
+
+- New set-gid postqueue command for the queue list/flush operations
+ that used to implemented by the Postfix sendmail command.
+
+[snapshot-20020106..15] Simpler Postfix installation and upgrading.
+
+- All installation settings are now kept in the main.cf file, and
+ better default settings are now generated for system dependent
+ pathnames such as sendmail_path etc. The install.cf file is no
+ longer used, except when upgrading from an older Postfix version.
+
+- Non-default installation parameter settings can (but do not have
+ to) be specified on the "make install" or "make upgrade" command
+ line as name=value arguments.
+
+- New postfix-files database (in /etc/postfix) with (pathname,
+ owner, permission) information about all Postfix-related files.
+
+- New postfix-install script replaces the awkward INSTALL.sh script.
+ This is driven by the postfix-files database. It has better
+ support for building packages for distribution to other systems.
+ See PACKAGE_README for details.
+
+- New post-install script (in /etc/postfix) for post-installation
+ maintenance of directory/file permissions and ownership (this is
+ used by "postfix check"). Example:
+
+ # postfix stop
+ # post-install set-permissions mail_owner=username setgid_group=groupname
+ # postfix start
+
+[snapshot-20020106] Postfix will not run if it detects that the
+postfix user or group ID are shared with other accounts on the
+system. The checks aren't exhaustive (that would be too resource
+consuming) but should be sufficient to encourage packagers and
+developers to do the right thing. To fix the problem, use the above
+post-install command, after you have created the appropriate new
+mail_owner or setgid_group user or group IDs.
+
+[snapshot-20020106] If you run multiple Postfix instances on the
+same machine you now have to specify their configuration directories
+in the default main.cf file as "alternate_config_directories =
+/dir1 /dir2 ...". Otherwise, some Postfix commands will no longer
+work: the set-group ID postdrop command for mail submission and
+the set-group ID postqueue command for queue listing/flushing.
+
+[snapshot-20010808] The default setting for the maps_rbl_domains
+parameter is now "empty", because mail-abuse.org has become a
+subscription-based service. The names of the RBL parameters haven't
+changed.
+
+[snapshot-20020106] Postfix SMTP access maps will no longer return
+OK for non-local multi-domain recipient mail addresses (user@dom1@dom2,
+user%dom1@dom2, etcetera); the lookup now returns DUNNO (undetermined).
+Non-local multi-domain recipient addresses were already prohibited
+from matching the permit_mx_backup and the relay_domains-based
+restrictions.
+
+[snapshot-20011210] Stricter checking of Postfix chroot configurations.
+The Postfix startup procedure now warns if "system" directories
+(etc, bin, lib, usr) under the Postfix top-level queue directory
+are not owned by the super-user (usually the result of well-intended,
+but misguided, applications of "chown -R postfix /var/spool/postfix).
+
+[snapshot-20011008] The Postfix SMTP server now rejects requests
+with a generic "try again later" status (451 Server configuration
+error) when it detects an error in smtp_{client, helo, sender,
+recipient, etrn}_restrictions settings. More details about the
+problem are logged to the syslogd; sending such information to
+random clients would be inappropriate.
+
+[snapshot-20011008] Postfix no longer flushes the entire mail queue
+after receiving an ETRN request for a random domain name. Requests
+for domains that do not match $fast_flush_domains are now rejected
+instead.
+
+[snapshot-20011226] Postfix configuration file comments no longer
+continue on the next line when that next line starts with whitespace.
+This change avoids surprises, but it may cause unexpected behavior
+with existing, improperly formatted, configuration files. Caveat
+user. Comment lines are allowed to begin with whitespace. Multi-line
+input is no longer terminated by a comment line, by an all whitespace
+line, or by an empty line.
+
+[snapshot-20010714] Postfix delivery agents now refuse to create
+a missing maildir or mail spool subdirectory when its parent
+directory is world writable. This is necessary to prevent security
+problems with maildirs or with hashed mailboxes under a world
+writable mail spool directory.
+
+[snapshot-20010525] As per RFC 2821, the Postfix SMTP client now
+always sends EHLO at the beginning of an SMTP session. Specify
+"smtp_always_send_ehlo = no" for the old behavior, which is to send
+EHLO only when the server greeting banner contains the word ESMTP.
+
+[snapshot-20010525] As per RFC 2821, an EHLO command in the middle
+of an SMTP session resets the Postfix SMTP server state just like
+RSET. This behavior cannot be disabled.
+
+[snapshot-20010709] The SMTP client now by default breaks lines >
+2048 characters, to avoid mail delivery problems with fragile SMTP
+server software. To get the old behavior back, specify "smtp_break_lines
+= no" in the Postfix main.cf file.
+
+[snapshot-20010709] With recipient_delimiter=+ (or any character
+other than -) Postfix will now recognize address extensions even
+with owner-foo+extension addresses. This change was necessary to
+make VERP useful for mailing list bounce processing.
+
+[snapshot-20010610] The Postfix pipe delivery agent no longer
+automatically case-folds the expansion of $user, $extension or
+$mailbox command-line macros. Specify the 'u' flag to get the old
+behavior.
+
+[snapshot-20011210] The Postfix sendmail command no longer exits
+with status 1 when mail submission fails, but instead returns a
+sendmail-compatible status code as defined in /usr/include/sysexits.h.
+
+Major changes with Postfix version 1.1.0 (Released 20020117)
+============================================================
+
+Changes are listed in order of decreasing importance, not release
+date.
+
+The nqmgr queue manager is now bundled with Postfix. It implements
+a smarter scheduling strategy that allows ordinary mail to slip
+past mailing list mail, resulting in better response. This queue
+manager is expected to become the default queue manager shortly.
+
+[snapshot-20010709, snapshot-20010808] VERP (variable envelope
+return path) support. This is enabled by default, including in
+the SMTP server. See the VERP_README file for instructions. Specify
+"disable_verp_bounces = yes" to have Postfix send one RFC-standard,
+non-VERP, bounce report for multi-recipient mail, even when VERP
+style delivery was requested. This reduces the explosive behavior
+of bounces when sending mail to a list.
+
+[snapshot-20010709] QMQP server support, so that Postfix can be
+used as a backend mailer for the ezmlm-idx mailing list manager.
+You still need qmail to drive ezmlm and to process mailing list
+bounces. The QMQP service is disabled by default. To enable, follow
+the instructions in the QMQP_README file.
+
+[snapshot-20010709] You can now reject unknown virtual(8) recipients
+at the SMTP port by specifying a "domain.name whatever" entry in
+the tables specified with virtual_mailbox_maps, similar to Postfix
+virtual(5) domains. [virtual(8) is the Postfix virtual delivery
+agent, virtual(5) is the Postfix virtual map. The two implement
+virtual domains in a very different manner.]
+
+[snapshot-20011121] Configurable host/domain name wildcard matching
+behavior: choice between "pattern `domain.name' matches string
+`host.domain.name'" (this is to be deprecated in the future) and
+"pattern `.domain.name' matches string `host.domain.name'" (this
+is to be preferred in the future). The configuration parameter
+"parent_domain_matches_subdomains" specifies which Postfix features
+use the behavior that will become deprecated.
+
+[snapshot-20010808] Variable coupling between message receiving
+rates and message delivery rates. When the message receiving rate
+exceeds the message delivery rate, an SMTP server will pause for
+$in_flow_delay seconds before accepting a message. This delay
+gives Postfix a chance catch up and access the disk, while still
+allowing new mail to arrive. This feature currently has effect
+only when mail arrives via a small number of SMTP clients.
+
+[snapshot-20010610, snapshot-20011121, snapshot-20011210] Workarounds
+for a bug in old versions of the CISCO PIX firewall software that
+caused mail to be resent repeatedly. The workaround has no effect
+for other mail deliveries. The workaround is turned off when mail
+is queued for less than $smtp_pix_workaround_threshold_time seconds
+(default: 500 seconds) so that the workaround is normally enabled
+only for deferred mail. The delay before sending .<CR><LF> is now
+controlled by the $smtp_pix_workaround_delay_time setting (default:
+10 seconds).
+
+[snapshot-20011226] Postfix will now do null address lookups in
+SMTPD access maps. If your access maps cannot store or look up
+null string key values, specify "smtpd_null_access_lookup_key =
+<>" and the null sender address will be looked up as <> instead.
+
+[snapshot-20011210] More usable virtual delivery agent, thanks to
+a new "static" map type by Jeff Miller that always returns its map
+name as the lookup result. This eliminates the need for per-recipient
+user ID and group ID tables. See the VIRTUAL_README file for more
+details.
+
+[snapshot-20011125] Anti-sender spoofing. New main.cf parameter
+smtpd_sender_login_maps that specifies the (SASL) login name that
+owns a MAIL FROM sender address. Specify a regexp table in order
+to require a simple one-to-one mapping. New SMTPD restriction
+reject_sender_login_mismatch that refuses a MAIL FROM address when
+$smtpd_sender_login_maps specifies an owner but the client is not
+(SASL) logged in as the MAIL FROM address owner, or when a client
+is (SASL) logged in but does not own the address according to
+$smtpd_sender_login_maps.
+
+[snapshot-20011121] The mailbox_command_maps parameter allows you
+to configure the external delivery command per user (local delivery
+agent only). This feature has precedence over the mailbox_command
+and home_mailbox settings.
+
+[snapshot-20011121] New "warn_if_reject" smtpd UCE restriction that
+only warns if the restriction that follows would reject mail. Look
+for file records that contain the string "reject_warning".
+
+[snapshot-20011127] New header/body_check result "WARN" to make
+Postfix log a warning about a header/body line without rejecting
+the content.
+
+[snapshot-20011103] In header/body_check files, REJECT can now be
+followed by text that is sent to the originator. That feature was
+stuck waiting for years, pending the internal protocol revision.
+
+[snapshot-20011008] The permit_mx_backup feature allows you to
+specify network address blocks via the permit_mx_backup_networks
+parameter. This requires that the primary MX hosts for the given
+destination match the specified network blocks. When no value is
+given for permit_mx_backup_networks, Postfix will accept mail
+whenever the local MTA is listed in the DNS as an MX relay host
+for a destination, even when you never gave permission to do so.
+
+[snapshot-20010709] Specify "mail_spool_directory = /var/mail/"
+(note the trailing "/" character) to enable maildir format for
+/var/mail/username.
+
+[snapshot-20010808] Finer control over address masquerading. The
+masquerade_classes parameter now controls header and envelope sender
+and recipient addresses. With earlier Postfix versions, address
+masquerading rewrote all addresses except for the envelope recipient.
+
+[snapshot-20010610] The pipe mail delivery agent now supports proper
+quoting of white space and other special characters in the expansions
+of the $sender and $recipient command-line macros. This was necessary
+for correct operation of the "simple" content filter, and is also
+recommended for delivery via UUCP or BSMTP.
+
+[snapshot-20010610] The pipe mail delivery agent now supports case
+folding the localpart and/or domain part of expansions of the
+$nexthop, $recipient, $user, $extension or $mailbox command-line
+macros. This is recommended for mail delivery via UUCP. Bug: $nexthop
+is always case folded because of problems in the queue manager
+code.
+
+[snapshot-20010525] This release contains many little revisions of
+little details in the light of the new RFC 2821 and RFC 2822
+standards. Changes that may affect interoperability are listed
+above under "incompatible changes". Other little details are
+discussed in comments in the source code.
+
+[snapshot-20010502] The Postfix SMTP client now by default randomly
+shuffles destination IP addresses of equal preference (whether
+obtained via MX lookup or otherwise). Reportedly, this is needed
+for sites that use Bernstein's dnscache program. Specify
+"smtp_randomize_addresses = no" to disable this behavior. Based on
+shuffling code by Aleph1.
+
+[snapshot-20011127] New parameter smtpd_noop_commands to specify
+a list of commands that the Postfix SMTP server treats as NOOP
+commands (no syntax check, no state change). This is a workaround
+for misbehaving clients that send unsupported commands such as
+ONEX.
+
+[snapshot-20010502] "postmap -q -" and "postmap -d -" read key
+values from standard input, which makes it easier to drive them
+from another program. The same feature was added to the postalias
+command.
+
+[snapshot-20010502] The postsuper command now has a command-line
+option to delete queue files. In principle this command can be
+used while Postfix is running, but there is a possibility of deleting
+the wrong queue file when Postfix deletes a queue file and reuses
+the queue ID for a new message. In that case, postsuper will delete
+the new message.
+
+[snapshot-20010525] The postsuper queue maintenance tool now renames
+files whose name (queue ID) does not match the message file inode
+number. This is necessary after a Postfix mail queue is restored
+from another machine or from backups. The feature is selected with
+the -s option, which is the default, and runs whenever Postfix is
+started.
+
+[snapshot-20010525] The postsuper queue maintenance tool has a new
+-r (requeue) option for subjecting some or all queue files to
+another iteration of address rewriting. This is useful after the
+virtual or canonical maps have changed.
+
+[snapshot-20010525] The postsuper queue maintenance tool was extended
+with options to read queue IDs from standard input. This makes the
+tool easier to drive from scripts.
+
+[snapshot-20010329] Better support for running multiple Postfix
+instances on one machine. Each instance can be recognized by its
+logging (defaults: "syslog_name = postfix", "syslog_facility =
+mail").
+
+Major incompatible changes with release-20010228 Patch 01 (a.k.a. Postfix 1.0.1)
+================================================================================
+
+This release changes the names of the "fast ETRN" logfiles with
+delayed mail per destination. These files are maintained by the
+Postfix "fast flush" daemon. The old scheme failed with addresses
+of the form user@[ip.address] and user@a.domain.name. In order to
+populate the new "fast ETRN" logfiles, execute the command "sendmail
+-q". The old "fast ETRN" logfiles go away by themselves (default:
+after 7 days).
+
+Major incompatible changes with release-20010228 (a.k.a. Postfix 1.0.0)
+=======================================================================
+
+[snapshot-20010225] POSTFIX NO LONGER RELAYS MAIL FOR CLIENTS IN
+THE ENTIRE CLASS A/B/C NETWORK. To get the old behavior, specify
+"mynetworks_style = class" in the main.cf file. The default
+(mynetworks_style = subnet) is to relay for clients in the local
+IP subnet. See conf/main.cf.
+
+[snapshot-20001005, snapshot-20010225] You must execute "postfix
+stop" before installing this release. Some recommended parameter
+settings have changed, and a new entry must be added to the master.cf
+file before you can start Postfix again.
+
+1 - The recommended Postfix configuration no longer uses flat
+ directories for the "incoming" "active", "bounce", and "defer"
+ queue directories. The "flush" directory for the new "flush"
+ service directory should not be flat either.
+
+ Upon start-up, Postfix checks if the hash_queue_names configuration
+ parameter is properly set up, and will add any queue directory
+ names that are missing.
+
+2 - In order to improve performance of one-to-one mail deliveries
+ the queue manager will now look at up to 10000 queue files
+ (was: 1000). The default qmgr_message_active_limit setting
+ was changed accordingly.
+
+ If you have a non-default qmgr_message_active_limit in main.cf,
+ you may want adjust it.
+
+3 - The new "flush" service needs to be configured in master.cf.
+
+ Upon start-up, Postfix checks if the new "flush" service is
+ configured in the master.cf file, and will add an entry if it
+ is missing.
+
+Should you wish to back out to a previous Postfix release there is
+no need to undo the above queue configuration changes.
+
+[snapshot-20000921] The protocol between queue manager and delivery
+agents has changed. This means that you cannot mix the Postfix
+queue manager or delivery agents with those of Postfix versions
+prior to 20000921. This change does not affect Postfix queue file
+formats.
+
+[snapshot-20000529] This release introduces an incompatible queue
+file format change ONLY when content filtering is enabled (see text
+in FILTER_README). Old Postfix queue files will work fine, but
+queue files with the new content filtering info will not work with
+Postfix versions before 20000529. Postfix logs a warning and moves
+incompatible queue files to the "corrupt" mail queue subdirectory.
+
+Minor incompatible changes with release-20010228
+================================================
+
+[snapshot-20010225] The incoming and deferred queue directories
+are now hashed by default. This improves the performance considerably
+under heavy load, at the cost of a small but noticeable slowdown
+when one runs "mailq" on an unloaded system.
+
+[snapshot-20010222] Postfix no longer automatically delivers
+recipients one at a time when their domain is listed in $mydestination.
+This change solves delivery performance problems with delivery via
+LMTP, with virus scanning, and with firewall relays that forward
+all mail for $mydestination to an inside host.
+
+The "one recipient at a time" delivery behavior is now controlled
+by the per-transport recipient limit (xxx_destination_recipient_limit,
+where xxx is the name of the delivery mechanism). This parameter
+controls the number of recipients that can be sent in one delivery
+(surprise).
+
+The setting of the per-transport recipient limit also controls the
+meaning of the per-transport destination concurrency limit (named
+xxx_destination_concurrency_limit, where xxx is again the name of
+the delivery mechanism):
+
+ 1) When the per-transport recipient limit is 1 (i.e., send one
+ recipient per delivery), the per-transport destination concurrency
+ limit controls the number of simultaneous deliveries to the
+ same recipient. This is the default behavior for delivery via
+ the Postfix local delivery agent.
+
+ 2) When the per-transport recipient limit is > 1 (i.e., send
+ multiple recipients per delivery), the per-transport destination
+ concurrency limit controls the number of simultaneous deliveries
+ to the same domain. This is the default behavior for all other
+ Postfix delivery agents.
+
+[snapshot-20010128] The Postfix local delivery agent now enforces
+mailbox file size limits (default: mailbox_size_limit = 51200000).
+This limit affects all file write access by the local delivery
+agent or by a process run by the local delivery agent. The purpose
+of this parameter is to act as a safety for run-away software. It
+cannot be a substitute for a file quota management system. Specify
+a limit of 0 to disable.
+
+[snapshot-20010128] REJECT in header/body_checks is now flagged as
+policy violation rather than bounce, for consistency in postmaster
+notifications.
+
+[snapshot-20010128] The default RBL (real-time blackhole lists)
+domain examples have been changed from *.vix.com to *.mail-abuse.org.
+
+[snapshot-20001210] Several interfaces of libutil and libglobal
+routines have changed. This may break third-party code written
+for Postfix. In particular, the safe_open() routine has changed,
+the way the preferred locking method is specified in the sys_defs.h
+file, as well as all routines that perform file locking. When
+compiling third-party code written for Postfix, the incompatibilities
+will be detected by the compiler provided that #include file
+dependencies are properly maintained.
+
+[snapshot-20001210] When delivering to /file/name (as directed in
+an alias or .forward file), the local delivery agent now logs a
+warning when it is unable to create a /file/name.lock file. Mail
+is still delivered as before.
+
+[snapshot-20001210] The "sun_mailtool_compatibility" feature is
+going away (a compatibility mode that turns off kernel locks on
+mailbox files). It still works, but a warning is logged. Instead
+of using "sun_mailtool_compatibility", specify the mailbox locking
+strategy as "mailbox_delivery_lock = dotlock".
+
+[snapshot-20001210] The Postfix SMTP client now skips SMTP server
+replies that do not start with "CODE SPACE" or with "CODE HYPHEN"
+and flags them as protocol errors. Older Postfix SMTP clients
+silently treated "CODE TEXT" as "CODE SPACE TEXT", i.e. as a valid
+SMTP reply.
+
+[snapshot-20001121] On RedHat Linux 7.0, you must install the
+db3-devel RPM before you can compile the Postfix source code.
+
+[snapshot-20000924] The postmaster address in the "sorry" text at
+the top of bounced mail is now just postmaster, not postmaster@machine.
+The idea is to refer users to their own postmaster.
+
+[snapshot-20000921] The notation of [host:port] in transport tables
+etc. is going away but it is still supported. The preferred form
+is now [host]:port. This change is necessary to support IPV6
+address forms which use ":" as part of a numeric IP address. In a
+future release, Postfix will log a warning when it encounters the
+[host:port] form.
+
+[snapshot-20000921] In mail headers, Errors-To:, Reply-To: and
+Return-Receipt: addresses are now rewritten as a sender address
+(was: recipient).
+
+[snapshot-20000921] Postfix no longer inserts Sender: message
+headers.
+
+[snapshot-20000921] The queue manager now logs the original number
+of recipients when opening a queue file (example: from=<>, size=3502,
+nrcpt=1).
+
+[snapshot-20000921] The local delivery agent no longer appends a
+blank line to mail that is delivered to external command.
+
+[snapshot-20000921] The pipe delivery agent no longer appends a
+blank line when the F flag is specified (in the master.cf file).
+Specify the B flag if you need that blank line.
+
+[snapshot-20000507] As required by RFC 822, Postfix now inserts a
+generic destination message header when no destination header is
+present. The text is specified via the undisclosed_recipients_header
+configuration parameter (default: "To: undisclosed-recipients:;").
+
+[snapshot-20000507] The Postfix sendmail command treats a line with
+only `.' as the end of input, for the sake of sendmail compatibility.
+To disable this feature, specify the sendmail-compatible `-i' or
+`-oi' flags on the sendmail command line.
+
+[snapshot-20000507] For the sake of Sendmail compatibility, the
+Postfix SMTP client skips over SMTP servers that greet with a 4XX
+or 5XX reply code, treating them as unreachable servers. To obtain
+prior behavior (4XX=retry, 5XX=bounce), specify "smtp_skip_4xx_greeting
+= no" and "smtp_skip_5xx_greeting = no".
+
+Major changes with release-20010228
+===================================
+
+Postfix produces DSN formatted bounced/delayed mail notifications.
+The human-readable text still exists, so that users will not have
+to be unnecessarily confused by all the ugliness of RFC 1894. Full
+DSN support will be later.
+
+This release introduces full content filtering through an external
+process. This involves an incompatible change in queue file format.
+Mail is delivered to content filtering software via an existing
+mail delivery agent, and is re-injected into Postfix via an existing
+mail submission agent. See examples in the FILTER_README file.
+Depending on how the filter is implemented, you can expect to lose
+a factor of 2 to 4 in delivery performance of SMTP transit mail,
+more if the content filtering software needs lots of CPU or memory.
+
+Specify "body_checks = regexp:/etc/postfix/body_checks" for a quick
+and dirty emergency content filter that looks at non-header lines
+one line at a time (including MIME headers inside the message body).
+Details in conf/sample-filter.cf.
+
+The header_checks and body_checks features can be used to strip
+out unwanted data. Specify IGNORE on the right-hand side and the
+data will disappear from the mail.
+
+Support for SASL (RFC 2554) authentication in the SMTP server and
+in the SMTP and LMTP clients. See the SASL_README file for more
+details. This file still needs better examples.
+
+Postfix now ships with an LMTP delivery agent that can deliver over
+local/remote TCP sockets and over local UNIX-domain sockets. The
+LMTP_README file gives example, but still needs to be revised.
+
+Fast "ETRN" and "sendmail -qR". Postfix maintains per-destination
+logfiles with information about what mail is queued for selected
+destinations. See the file ETRN_README for details.
+
+The mailbox locking style is now fully configurable at runtime.
+The new configuration parameter is called "mailbox_delivery_lock".
+Depending on the operating system type, mailboxes can be locked
+with one or more of "flock", "fcntl" or "dotlock". The command
+"postconf -l" shows the available locking styles. The default
+mailbox locking style is system dependent. This change affects
+all mailbox and all "/file/name" deliveries by the Postfix local
+delivery agent.
+
+Minor changes with release-20010228
+===================================
+
+You can now specify multiple SMTP destinations in the relayhost
+and fallback_relay configuration parameters. The destinations are
+tried in the specified order. Specify host or host:port (perform
+MX record lookups), [host] or [host]:port (no MX record lookups),
+[address] or [address]:port (numerical IP address).
+
+The "mailbox_transport" and "fallback_transport" parameters now
+understand the form "transport:nexthop", with suitable defaults
+when either transport or nexthop are omitted, just like in the
+Postfix transport map. This allows you to specify for example,
+"mailbox_transport = lmtp:unix:/file/name".
+
+The local_transport and default_transport configuration parameters
+can now be specified in transport:destination notation, just like
+the mailbox_transport and fallback_transport parameters. The
+:destination part is optional. However, these parameters take only
+one destination, unlike relayhost and fallback-relay which take
+any number of destinations.
+
+More general virtual domain support. Postfix now supports both
+Sendmail-style virtual domains and Postfix-style virtual domains.
+Details and examples are given in the revised virtual manual page.
+
+- With Sendmail-style virtual domains, local users/aliases/mailing
+ lists are visible as localname@virtual.domain. This is convenient
+ if you want to host mailing lists under virtual domains.
+
+- With Postfix-style virtual domains, local users/aliases/mailing
+ lists are not visible as localname@virtual.domain. Each virtual
+ domain has its own separate name space.
+
+More general "soft bounce" feature. Specify "soft_bounce = yes"
+in main.cf to prevent the SMTP server from bouncing mail while you
+are testing configurations. Until this release the SMTP server was
+not aware of soft bounces.
+
+Workarounds for non-standard RFC 2554 (AUTH command) implementations.
+Specify "broken_sasl_auth_clients = yes" to enable SMTP server
+support for old Microsoft client applications. The Postfix SMTP
+client supports non-standard RFC 2554 servers by default.
+
+All time-related configuration parameters now accept a one-letter
+suffix to indicate the time unit (s: second, m: minute, h: hour,
+d: day, w: week). The exceptions are the LDAP and MYSQL modules
+which are maintained separately.
+
+New "import_environment" and "export_environment" configuration
+parameters provide explicit control over what environment variables
+Postfix will import, and what environment variables Postfix will
+pass on to a non-Postfix process.
+
+In order to improve performance of one-to-one deliveries, Postfix
+by default now looks at up to 10000 messages at a time (was: 1000).
+
+Specify "syslog_facility = log_local1" etc. to separate the logging
+from multiple Postfix instances. However, a non-default logging
+facility takes effect only after process initialization. Errors
+during command-line parsing are still logged with the default syslog
+facility, as are errors while processing the main.cf file.
+
+Postfix now strips out Content-Length: headers in incoming mail to
+avoid confusion in mail user agents.
+
+Specify "require_home_directory = yes" to prevent mail from being
+delivered to a user whose home directory is not mounted. This
+feature is implemented by the Postfix local delivery agent.
+
+The pipe mailer has a size limit (size=nnn) command-line argument.
+
+The pipe delivery agent has a configurable end-of-line attribute.
+Specify "pipe ... eol=\r\n" for delivery mechanisms that require
+CRLF record delimiters. The eol attribute understands the following
+C-style escape sequences: \a \b \f \n \r \t \v \nnn \\.
+
+In master.cf you can selectively override main.cf configuration
+parameters, for example: "smtpd -o myhostname=foo.com".
+
+In main.cf, specify "smtp_bind_address=x.x.x.x" to bind SMTP
+connections to a specific local interface. Or override the default
+setting in master.cf with "smtp -o smtp_bind_address=x.x.x.x".
+For now, you must specify a numeric IP address.
+
+Questionable feature: with "smtp_always_send_ehlo = yes", the SMTP
+client sends EHLO regardless of the content of the SMTP server's
+greeting.
+
+Specify "-d key" to postalias or postmap in order to remove one
+key. This still needs to be generalized to multi-key removal (e.g.,
+read keys from stdin).
+
+Comments in Postfix configuration files no longer contain troff
+formatting codes. The text is now generated from prototype files
+in a new "proto" subdirectory.
+
+Major changes with postfix-19991231:
+====================================
+
+- It is now much more difficult to configure Postfix as an open
+relay. The SMTP server requires that "smtpd_recipient_restrictions"
+contains at least one restriction that by default refuses mail (as
+is the default). There were too many accidents with changes to
+the UCE restrictions.
+
+- The relay_domains parameter no longer needs to contain $virtual_maps.
+
+- Overhauled FAQ (html/faq.html) with many more examples.
+
+- Updated UCE documentation (html/uce.html) with more examples.
+More UCE configuration examples in sample configuration files.
+
+- Several little improvements to the installation procedure:
+relative symlinks, configurable directory for scratch files so the
+installation can be done without write access to the build tree.
+
+- Updated LDAP client code (John Hensley).
+
+- Updated mysql client code (Scott Cotton).
+
+- The SMTP server now rejects mail for unknown users in virtual
+domains that are defined by Postfix virtual maps.
+
+- The SMTP server can reject mail for unknown local users. Specify
+"local_recipient_maps = $alias_maps, unix:passwd.byname" if your
+local mail is delivered by a UNIX-style local delivery agent. See
+example in conf/main.cf.
+
+- Use "disable_vrfy_command = yes" to disable the SMTP VRFY command.
+This prevents some forms of address harvesting.
+
+- The sendmail "-f" option now understands <user> and even understands
+forms with RFC 822-style comments.
+
+- New "qmgr_fudge_factor" parameter allows you to balance mailing
+list performance against response time for one-to-one mail. The
+fudge factor controls what percentage of delivery resources Postfix
+will devote to one message. With 100%, delivery of one message
+does not begin before delivery of the previous message is completed.
+This is good for list performance, bad for one-to-one mail. With
+10%, response time for one-to-one mail improves much, but list
+performance suffers: in the worst case, people near the start of a
+mailing list get a burst of postings today, while people near the
+end of the list get that same burst of postings a whole day later.
+
+- It is now relatively safe to configure 550 status codes for the
+main.cf unknown_address_reject_code or unknown_client_reject_code
+parameters. The SMTP server now always sends a 450 (try again)
+reply code when an UCE restriction fails due to a soft DNS error,
+regardless of what main.cf specifies.
+
+- The RBL checks now show the content of TXT records (Simon J Mudd).
+
+- The Postfix SMTP server now understands a wider range of illegal
+address forms in MAIL FROM and RCPT TO commands. In order to disable
+illegal forms, specify "strict_rfc821_envelopes = yes". This also
+disables support for MAIL FROM and RCPT TO addresses without <>.
+
+- Per-client/helo/sender/recipient UCE restrictions (fully-recursive
+UCE restriction parser). See the RESTRICTION_CLASS file for details.
+
+- Use "postmap -q key" or "postalias -q key" for testing Postfix
+lookup tables or alias files.
+
+- Use "postconf -e name=value..." to edit the main.cf file. This
+is easier and safer than editing the main.cf file by hand. The
+edits are done on a temporary copy that is renamed into place.
+
+- Use "postconf -m" to display all supported lookup table types
+(Scott Cotton).
+
+- New "permit_auth_destination" UCE restriction for finer-grained
+access control (Jesper Skriver).
+
+Incompatible changes with postfix-19990906
+==========================================
+
+- On systems that use user.lock files to protect system mailboxes
+against simultaneous updates, Postfix now uses /file/name.lock
+files while delivering to files specified in aliases/forward/include
+files. This is a no-op when the recipient lacks directory write
+permission.
+
+- The LDAP client code no longer looks up a name containing "*"
+because it could be abused. See the LDAP_README file for how to
+restore previous behavior.
+
+- The Postfix to PCRE interface now expects PCRE version 2.08.
+Postfix is no longer compatible with PCRE versions prior to 2.06.
+
+Major changes with postfix-19990906
+===================================
+
+Several bugfixes, none related to security. See the HISTORY file
+for a complete list of changes.
+
+- Postfix is now distributed under IBM Public License Version 1.0
+which does not carry the controversial termination clause. The new
+license does have a requirement that contributors make source code
+available.
+
+- INSTALL.sh install/upgrade procedure that replaces existing
+programs and shell scripts instead of overwriting them, and that
+leaves existing queue files and configuration files alone.
+
+- The ugly Delivered-To: header can now be turned off selectively.
+The default setting is: "prepend_delivered_header = command, file,
+forward". Turning off the Delivered-To: header when forwarding
+mail is not recommended.
+
+- mysql client support by Scott Cotton and Joshua Marcus, Internet
+Consultants Group, Inc. See the file MYSQL_README for instructions.
+
+- reject_unauth_destination SMTP recipient restriction that rejects
+destinations not in $relay_domains. Unlike the check_relay_domains
+restriction, reject_unauth_destination ignores the client hostname.
+By Lamont Jones of Hewlett-Packard.
+
+- reject_unauth_pipelining SMTP *anything* restriction to stop mail
+from spammers that improperly use SMTP command pipelining to speed
+up their deliveries.
+
+- Postfix "sendmail" now issues a warning and drops privileges if
+installed set-uid root.
+
+- No more duplicate delivery when "postfix reload" is immediately
+followed by "sendmail -q".
+
+- No more "invalid argument" errors when a Postfix daemon opens a
+DB/DBM file while some other process is changing the file.
+
+- Portability to the Mac OS X Server, Reliant Unix, AIX 3.2.5 and
+Ultrix 4.3.
+
+Incompatible changes with postfix-19990601:
+===========================================
+
+- The SMTP server now delays all UCE restrictions until the RCPT
+TO, VRFY or ETRN command. This makes the restrictions more useful,
+because many SMTP clients do not expect negative responses earlier
+in the protocol. In order to restore the old behavior, specify
+"smtpd_delay_reject = no" in /etc/postfix/main.cf.
+
+- The Postfix local delivery agent no longer automatically propagates
+address extensions to aliases/include/forward addresses. Specify
+"propagate_unmatched_extensions = canonical, virtual, alias, forward,
+include" to restore the old behavior.
+
+- The Postfix local delivery agent no longer does $name expansion
+on words found in the mailbox_command configuration parameter. This
+makes it easier to specify shell syntax. See conf/main.cf.
+
+- The luser_relay syntax has changed. You can specify one address;
+it is subjected to $user, etc. expansions. See conf/main.cf.
+
+- File system reorganization: daemon executables are now in the
+libexec subdirectory, command executables in the bin subdirectory.
+The INSTALL instructions now recommend installing daemons and
+commands into separate directories.
+
+Major changes with postfix-19990601:
+=====================================
+
+- New USER, EXTENSION, LOCAL, DOMAIN and RECIPIENT environment
+variables for delivery to command (including mailbox_command) by
+the local delivery agent. As you might expect, the information is
+censored. The list of acceptable characters is specified with the
+command_expansion_filter configuration parameter. Unacceptable
+characters are replaced by underscores. See html/local.8.html.
+
+- Specify "forward_path = /var/forward/$user" to avoid looking up
+.forward files in user home directories. The default value is
+$home/.forward$recipient_delimiter$extension, $home/.forward.
+Initial code by Philip A. Prindeville, Mirapoint, Inc., USA.
+
+- Conditional $name expansion in forward_path and luser_relay.
+Available names are: $user (bare user name) $shell (user login
+shell), $home (user home directory), $local (everything to the left
+of @), $extension (optional address extension), $domain (everything
+to the right of @), $recipient (the complete address) and
+$recipient_delimiter. A simple $name expands as usual. ${name?value}
+expands to value when $name is defined. ${name:value} expands to
+value when $name is not defined. With ${name?value} and ${name:value},
+the value is subject to another iteration of $name expansion.
+
+- POSIX regular expression support, enabled by default on 4.4BSD,
+LINUX, HP-UX, and Solaris 2.5 and later. See conf/sample-regexp.cf.
+Initial code by Lamont Jones, Hewlett-Packard, borrowing heavily
+from the PCRE implementation by Andrew McNamara, connect.com.au
+Pty. Ltd., Australia.
+
+- Regular expression checks for message headers. This requires
+support for POSIX or for PCRE regular expressions. Specify
+"header_checks = regexp:/file/name" or "header_checks = pcre:/file/name",
+and specify "/^header-name: badstuff/ REJECT" in the pattern file
+(patterns are case-insensitive by default). Code by Lamont Jones,
+Hewlett-Packard. It is to be expected that full content filtering
+will be delegated to an external command.
+
+- Regular expression support for all lookup tables, including access
+control (full mail addresses only), address rewriting (canonical/virtual,
+full mail addresses only) and transport tables (full domain names
+only). However, regular expressions are not allowed for aliases,
+because that would open up security exposures.
+
+- Automatic detection of changes to DB or DBM lookup tables. This
+eliminates the need to run "postfix reload" after each change to
+the SMTP access table, or to the canonical, virtual, transport or
+aliases tables.
+
+- New error mailer. Specify ".domain.name error:domain is undeliverable"
+in the transport table to bounce mail for entire domains.
+
+- No more Postfix lockups on Solaris (knock on wood). The code no
+longer uses Solaris UNIX-domain sockets, because they are still
+broken, even with Solaris 7.
+
+- Workaround for the Solaris mailtool, which keeps an exclusive
+kernel lock on the mailbox while its window is not iconified (specify
+"sun_mailtool_compatibility = yes" in main.cf).
+
+- Questionable workaround for Solaris, which reportedly loses
+long-lived exclusive locks that are held by the master daemon.
+
+- New reject_unknown_{sender,recipient}_domain restrictions for
+sender and recipient mail addresses that distinguish between soft
+errors (always 450) and hard errors (unknown_address_reject_code,
+default 450).
+
+- MIME-encapsulated bounce messages, making it easier to recover
+bounced mail. Initial implementation by Philip A. Prindeville,
+Mirapoint, Inc., USA. Support for RFC 1892 (multipart/report) and
+RFC 1894 (DSN) will have to wait until Postfix internals have been
+revised to support RFC 1893.
+
+- Separately configurable "postmaster" addresses for single bounces
+(bounce_notice_recipient), double bounces (2bounce_notice_recipient),
+delayed mail (delay_notice_recipient), and for mailer error reports
+(error_notice_recipient). See conf/main.cf.
+
+- Questionable feature: specify "best_mx_transport = local" if
+this machine is the best MX host for domains not in mydestinations.
+
+Incompatible changes with postfix-19990317:
+===========================================
+
+- You MUST install the new version of /etc/postfix/postfix-script.
+
+- The pipe mailer "flags" syntax has changed. You now explicitly
+MUST specify the R flag in order to generate a Return-Path: message
+header (as needed by, for example, cyrus).
+
+Major changes with postfix-19990317:
+====================================
+
+A detailed record of changes is given in the HISTORY file.
+
+- Less postmaster mail. Undeliverable bounce messages (double
+bounces) are now discarded. Specify "notify_classes = 2bounce..."
+to get copies of double bounces. Specify "notify_classes = bounce..."
+to get copies of normal and double bounces.
+
+- Improved LDAP client code by John Hensley of Merit Network, USA.
+See LDAP_README for details.
+
+- Perl-compatible regular expression support for lookup maps by
+Andrew McNamara, connect.com.au Pty. Ltd., Australia.. Example:
+"check_recipient_access pcre:/etc/postfix/sample-pcre.cf". Regular
+expressions provide a powerful tool not only for SMTP access control
+but also for address rewriting. See PCRE_README for details.
+
+- Automatic notification of delayed mail (disabled by default).
+With "delay_warning_time = 4", Postfix informs senders when mail
+has not been delivered after 4 hours. Initial version of the code
+by Daniel Eisenbud, University of California at Berkeley. In order
+to get postmaster copies of such warnings, specify "notify_classes
+= delay...".
+
+- More configurable local delivery: "mail_spool_directory" to
+specify the UNIX mail spool directory; "mailbox_transport" to
+delegate all mailbox delivery to, for example, cyrus, and
+"fallback_transport" to delegate delivery of only non-UNIX users.
+And all this without losing local aliases and local .forward
+processing. See config/main.cf and config/master.cf.
+
+- Several changes to improve Postfix behavior under worst-case
+conditions (frequent Postfix restarts/reloads combined with lots
+if inbound mail, intermittent connectivity problems, SMTP servers
+that become comatose after receiving QUIT).
+
+- More NFS-friendly mailbox delivery. The local delivery agent
+now avoids using root privileges where possible.
+
+- For sites that do not receive mail at all, mydestination can now
+be an empty string. Be sure to set up a transport table entry to
+prevent mail from looping.
+
+- New "postsuper" utility to clean up stale files from Postfix
+queues.
+
+- Workaround for BSD select() collisions that cause performance
+problems on large BSD systems.
+
+- Several questionable but useful features to capture mail:
+"always_bcc = address" to capture a copy of every message that
+enters the system, and "luser_relay = address" to capture mail for
+unknown recipients (does not work when mailbox_transport or
+fallback_transport are being used).
+
+- Junk mail controls: new reject_non_fqdn_{hostname,sender,recipient}
+restrictions to reject non-FQDN arguments in HELO, MAIL FROM and
+RCPT TO commands, and stricter checking of numeric HELO arguments.
+
+- "fallback_relay" feature for sites that use DNS but that can't
+talk to the entire world. The fall-back relay gets the mail when
+a destination is not found in the DNS or when the destination is
+found but not reachable.
+
+- Several questionable controls that can help to keep mail going:
+specify "smtp_skip_4xx_greeting = yes" to skip SMTP servers that
+greet with 4XX, "ignore_mx_lookup_error = yes" to look up an A
+record when a DNS server does not respond to an MX query.
+
+Incompatible changes with postfix-beta-19990122-pl01:
+=====================================================
+
+None.
+
+Major changes with postfix-beta-19990122-pl01:
+==============================================
+
+- Restrict who may use ETRN and what domains may be specified.
+Example: "smtpd_etrn_restrictions = permit_mynetworks, reject".
+
+- BIFF notifications. For compatibility reasons this feature is
+on by default. Specify "biff = no" in main.cf if your machine has
+lots of shell users.
+
+- With "soft_bounce = yes", defer delivery instead of bouncing
+mail. This is a safety net for configuration errors with delivery
+agents. It has no effect on errors in virtual maps, canonical maps,
+or in junk mail restrictions.
+
+- Specify "owner_request_special = no" to turn off special treatment
+of owner-foo and foo-request addresses.
+
+Incompatible changes with postfix-beta-19990122:
+================================================
+
+- The syntax of the transport table has changed. An entry like:
+
+ customer.org smtp:[gateway.customer.org]
+
+ no longer forwards mail for anything.customer.org. For that you
+ need to specify:
+
+ customer.org smtp:[gateway.customer.org]
+ .customer.org smtp:[gateway.customer.org]
+
+ This change makes transport tables more compatible with
+ sendmail mailer tables.
+
+- The format of syslog records has changed. A client is now always
+logged as hostname[address]; the pickup daemon logs queue file uid
+and sender address.
+
+Major changes with postfix-beta-19990122:
+=========================================
+
+- Junk mail restrictions can now be postponed to the RCPT TO command.
+Specify: "smtpd_recipient_restrictions = reject_maps_rbl...".
+
+- More flexible interface for delivery to e.g., cyrus IMAP without
+need for PERL scripts to munge recipient addresses. In addition to
+$sender, $nexthop and $recipient, the pipe mailer now also supports
+$user, $extension and $mailbox.
+
+- New mail now has precedence over deferred mail, plus some other
+tweaks to make bulk mail go faster. But it ain't no cure for massive
+network outages.
+
+- Watchdog timer for systems that cause the Postfix queue manager
+to lock up, so it recovers without human intervention.
+
+- Delivery to qmail-style maildir files, which is good for NFS
+environments. Specify "home_mailbox = Maildir/", or specify
+/file/name/ in aliases or in .forward files. The trailing / is
+required to turn on maildir delivery.
+
+- Incremental updates of aliases and maps. Specify "postmap -i
+mapname" and it will read new entries from stdin.
+
+- Newaliases will now update more than one alias database.
+Specify the names with the main.cf "alias_database" parameter.
+
+- Address masquerading exceptions to prevent users from being
+masqueraded. Specify "masquerade_exceptions = root".
+
+- A pipelined SMTP client. Deliveries to Postfix, qmail, LSOFT,
+zmailer, and exim (once it's fixed) speed up by some 30% for short
+messages with one recipient, with more for multi-recipient mails.
+
+- Hook for local delivery to "|command" via the smrsh restricted
+shell, to restrict what commands may be used in .forward etc. files.
+Specify "local_command_shell = /some/where/smrsh -c".
--- /dev/null
+In the text below, changes are labeled with the Postfix snapshot
+that introduced the change, and whether the change introduced a
+feature, an incompatibility, or whether the feature is obsolete.
+If you upgrade from a later Postfix version, then you do not have
+to worry about incompatibilities introduced in earlier versions.
+
+Official Postfix releases are called a.b.c where a=major release
+number, b=minor release number, c=patchlevel. Snapshot releases
+are now called a.b.c-yyyymmdd where yyyymmdd is the release date
+(yyyy=year, mm=month, dd=day). The mail_release_date configuration
+parameter contains the release date (both for official release and
+snapshot release). Patches change the patchlevel and the release
+date. Snapshots change only the release date, unless they include
+the same bugfixes as a patch release.
+
+Major changes with Postfix version 2.0.0 (released 20021222)
+============================================================
+
+First comes the bad news - things that may break when you upgrade
+from Postfix 1.1. Then comes the good news - things that evolved
+in snapshots over the past year.
+
+For the release notes of Postfix 1.1 and earlier, see the
+RELEASE_NOTES-1.1 file.
+
+Unknown Recipients are now rejected by default
+==============================================
+
+[Incompatibility 20021209] The Postfix SMTP server now rejects mail
+for $mydestination domain recipients that it does not know about.
+This keeps undeliverable mail out of your queue.
+
+[Incompatibility 20021209] To avoid losing mail when upgrading from
+Postfix 1.1, you need to review the LOCAL_RECIPIENT_README file if
+one of the following is true:
+
+- You define $mydestination domain recipients in files other than
+ /etc/passwd or /etc/aliases. For example, you define $mydestination
+ domain recipients in the $virtual_mailbox_maps files.
+- You run the Postfix SMTP server chrooted (see master.cf).
+- You redefined the local delivery agent in master.cf.
+- You redefined the "local_transport" setting in main.cf.
+- You use the mailbox_transport feature of the Postfix local delivery agent.
+- You use the fallback_transport feature of the Postfix local delivery agent.
+- You use the luser_relay feature of the Postfix local delivery agent.
+
+Name change of virtual domain tables
+====================================
+
+This release introduces separation of lookup tables for addresses
+and for domain names of virtual domains.
+
+[Incompat 20021209] the virtual_maps parameter is replaced by
+virtual_alias_maps (for address lookups) and virtual_alias_domains
+(for the names of what were formerly called "Postfix-style virtual
+domains").
+
+ For backwards compatibility with Postfix version 1.1, the new
+ virtual_alias_maps parameter defaults to $virtual_maps, and the
+ new virtual_alias_domains parameter defaults to $virtual_alias_maps.
+ This means that you can still keep all information about a domain
+ in one file, just like before.
+
+For details, see the virtual(5) and sample-virtual.cf files.
+
+[Incompat 20021209] the virtual_mailbox_maps parameter now has a
+companion parameter called virtual_mailbox_domains (for the names
+of domains served by the virtual delivery agent). virtual_mailbox_maps
+is now used for address lookups only.
+
+ For backwards compatibility with Postfix version 1.1,, the new
+ virtual_mailbox_domains parameter defaults to $virtual_mailbox_maps.
+ This means that you can still keep all information about a domain
+ in one file, just like before.
+
+For details, see the VIRTUAL_README file.
+
+Incompatible queue file format changes
+======================================
+
+[Incompat 20020527] Queue files created with the header/body_checks
+"FILTER" feature are not compatible with "postqueue -r" (move queue
+files back to the maildrop directory) of previous Postfix releases.
+
+[Incompat 20020512] Postfix queue files contain records that are
+incompatible with "postqueue -r" on all Postfix versions prior to
+1.1 and release candidates. This happens whenever the sender
+specifies MIME body type information via the SMTP `MAIL FROM'
+command, via the `sendmail -B' command line option, or via the
+Content-Transfer-Encoding: message header.
+
+[Incompat 20020512] Postfix queue files may contain records that
+are incompatible with "postqueue -r" on previous 1.1 Postfix versions
+and release candidates. This happens whenever the sender specifies
+the MIME body type only via the Content-Transfer-Encoding: message
+header, and not via `MAIL FROM' or `sendmail -B'.
+
+Features that are going away
+============================
+
+[Obsolete 20021209] Sendmail-style virtual domains are no longer
+documented. This part of Postfix was too confusing.
+
+[Obsolete 20021209] The "reject_maps_rbl" restriction is going
+away. The SMTP server now logs a warning and suggests using the
+more flexible "reject_rbl_client" feature instead.
+
+[Obsolete 20021209] The "check_relay_domains" restriction is going
+away. The SMTP server logs a warning and suggests using the more
+robust "reject_unauth_destination" instead.
+
+[Obsolete 20020917] In regexp lookup tables, the form /pattern1/!/pattern2/
+is going away. Use the cleaner and more flexible "if !/pattern2/..endif"
+form. The old form still exists but is no longer documented, and
+causes a warning (suggesting to use the new format) to be logged.
+For details, see "man regexp_table".
+
+[Obsolete 20020819] The qmgr_site_hog_factor feature is gone (this
+would defer mail delivery for sites that occupy too much space in
+the active queue, and be a real performance drain due to excessive
+disk I/O). The new qmgr_clog_warn_time feature (see below) provides
+more useful suggestions for dealing with Postfix congestion.
+
+[Obsolete 20020819] The "permit_naked_ip_address" restriction on
+HELO command syntax is unsafe when used with most smtpd_XXX_restrictions
+and will go away. Postfix logs a warning, suggesting to use
+"permit_mynetworks" instead.
+
+MIME support
+============
+
+[Feature 20020527] Postfix now has real MIME support. This improves
+content filtering efficiency and accuracy, and improves inter-operability
+with mail systems that cannot receive 8-bit mail. See conf/sample-mime.cf
+for details.
+
+[Feature 20020527] Postfix header_checks now properly recognize
+MIME headers in attachments. This is much more efficient than
+previous versions that recognized MIME headers via body_checks.
+MIME headers are now processed one multi-line header at a time,
+instead of one body line at a time. To get the the old behavior,
+specify "disable_mime_input_processing = yes". More details in
+conf/sample-filter.cf.
+
+[Feature 20020527] Postfix now has three classes of header patterns:
+header_checks (for primary message headers except MIME headers),
+mime_header_checks (for MIME headers), and nested_header_checks
+(for headers of attached email messages except MIME headers). By
+default, all headers are matched with header_checks.
+
+[Feature 20020527] The Postfix SMTP client will now convert 8BITMIME
+mail to 7BIT when delivering to an SMTP server that does not announce
+8BITMIME support. To disable, specify "disable_mime_output_conversion
+= yes". However, this conversion is required by RFC standards.
+
+[Feature 20020528] Postfix can enforce specific aspects of the MIME
+standards while receiving mail.
+
+* Specify "strict_7bit_headers = yes" to disallow 8-bit characters
+ in message headers. These are always illegal.
+
+* Specify "strict_8bitmime_body = yes" to block mail with 8-bit
+ content that is not properly labeled as 8-bit MIME. This blocks
+ mail from poorly written mail software, including (bounces from
+ qmail, bounces from Postfix before snapshot 20020514, and Majordomo
+ approval requests) that contain valid 8BITMIME mail.
+
+* Specify "strict_8bitmime = yes" to turn on both strict_7bit_headers
+ and strict_8bitmime_body.
+
+* Specify "strict_mime_encoding_domain = yes" to block mail from
+ poorly written mail software. More details in conf/sample-mime.cf.
+
+[Incompat 20020527] Postfix now rejects mail if the MIME multipart
+structure is nested more than mime_nesting_limit levels (default:
+100) when MIME input processing is enabled while receiving mail, or
+when Postfix is performing 8BITMIME to 7BIT conversion while
+delivering mail.
+
+[Incompat 20020527] Postfix now recognizes "name :" as a valid
+message header, but normalizes it to "name:" for consistency
+(actually, there is so much code in Postfix that would break with
+"name :" that there is little choice, except to not recognize "name
+:" headers).
+
+[Incompat 20020512] Postfix queue files contain records that are
+incompatible with "postqueue -r" on all Postfix versions prior to
+1.1 and release candidates. This happens whenever the sender
+specifies MIME body type information via the SMTP `MAIL FROM'
+command, via the `sendmail -B' command line option, or via the
+Content-Transfer-Encoding: message header.
+
+[Incompat 20020512] Postfix queue files may contain records that
+are incompatible with "postqueue -r" on previous 1.1 Postfix versions
+and release candidates. This happens whenever the sender specifies
+the MIME body type only via the Content-Transfer-Encoding: message
+header, and not via `MAIL FROM' or `sendmail -B'.
+
+[Feature 20020512] The Postfix SMTP and LMTP clients now properly
+pass on the MIME body type information (7BIT or 8BITMIME), provided
+that the sender properly specifies MIME body type information via
+the SMTP MAIL FROM command, via the sendmail -B command line option,
+or via MIME message headers. This includes mail that is returned
+as undeliverable.
+
+Improved performance
+====================
+
+[Incompat 20021209] The default queue directory hash_queue_depth
+setting is reduced to 1 level of subdirectories per Postfix queue.
+This improves "mailq" performance on most systems, but can result
+in poorer worst-case performance on systems with lots of mail in
+the queue.
+
+[Incompat 20021209] The Postfix SMTP client no longer expands CNAMEs
+in MAIL FROM or RCPT TO addresses (as permitted by RFC 2821). This
+eliminates one DNS lookup per sender and recipient, and can make
+a dramatic difference when sending mailing list mail via a relayhost.
+
+[Incompat 20021209] The Postfix installation procedure no longer
+sets the "chattr +S" bit on Linux queue directories. Wietse has
+gotten too annoyed with naive reviewers who complain about performance
+without having a clue of what they are comparing.
+
+[Feature 20021209] On mail gateway systems, separation of inbound
+mail relay traffic from outbound traffic. This eliminates a problem
+where inbound mail deliveries could become resource starved in the
+presence of a high volume of outbound mail.
+
+[Feature 20021013] The body_checks_max_size parameter limits the
+amount of text per message body segment (or attachment, if you
+prefer to use that term) that is subjected to body_checks inspection.
+The default limit is 50 kbytes. This speeds up the processing of
+mail with large attachments.
+
+[Feature 20020917] Speedups of regexp table lookups by optimizing
+for the $number substitutions that are actually present in the
+right-hand side. Based on a suggestion by Liviu Daia.
+
+[Feature 20020917] Speedups of regexp and pcre tables, using
+IF..ENDIF support. Based on an idea by Bert Driehuis. To protect
+a block of patterns, use:
+
+ if /pattern1/
+ /pattern2/ result2
+ /pattern3/ result3
+ endif
+
+IF..ENDIF can nest. Don't specify blanks at the beginning of lines
+inside IF..ENDIF, because lines beginning with whitespace are
+appended to the previous line. More details about the syntax are
+given in the pcre_table(5) and regexp_table(5) manual pages.
+
+[Feature 20020717] The default timeout for establishing an SMTP
+connection has been reduced to 30 seconds, because many systems
+have an atrociously large default timeout value.
+
+[Feature 20020505] Finer control over Berkeley DB memory usage,
+The parameter "berkeley_db_create_buffer_size" (default: 16 MBytes)
+specifies the buffer size for the postmap and postalias commands.
+The parameter "berkeley_db_read_buffer_size" (default: 256 kBytes)
+speficies the buffer size for all other applications. Specify
+"berkeley_db_read_buffer_size = 1048576" to get the old read buffer
+size. For more information, see the last paragraphs of the DB_README
+file.
+
+Improved compatibitity
+======================
+
+[Feature 20020527] The Postfix SMTP client will now convert 8BITMIME
+mail to 7BIT when delivering to an SMTP server that does not announce
+8BITMIME support. To disable, specify "disable_mime_output_conversion
+= yes". However, this conversion is required by RFC standards.
+
+[Feature 20020512] The Postfix SMTP and LMTP clients now properly
+pass on the MIME body type information (7BIT or 8BITMIME), provided
+that the sender properly specifies MIME body type information via
+the SMTP MAIL FROM command, via the sendmail -B command line option,
+or via MIME message headers. This includes mail that is returned
+as undeliverable.
+
+[Incompat 20020326] The Postfix SMTP client now breaks message
+header or body lines that are longer than $smtp_line_length_limit
+characters (default: 990). Earlier Postfix versions broke lines
+at $line_length_limit characters (default: 2048). Postfix versions
+before 20010611 did not break long lines at all. Reportedly, some
+mail servers refuse to receive mail with lines that exceed the 1000
+character limit that is specified by the SMTP standard.
+
+[Incompat 20020326] The Postfix SMTP client now breaks long message
+header or body lines by inserting <CR> <LF> <SPACE>. Earlier
+Postfix versions broke long lines by inserting <CR> <LF> only. This
+broke MIME encapsulation, causing MIME attachments to "disappear"
+with Postfix versions after 20010611.
+
+[Incompat 20020326] Postfix now discards text when a logical message
+header exceeds $header_size_limit characters (default: 102400).
+Earlier Postfix versions would place excess text, and all following
+text, in the message body. The same thing was done when a physical
+header line exceeded $line_length_limit characters (default: 2048).
+Both behaviors broke MIME encapsulation, causing MIME attachments
+to "disappear" with all previous Postfix versions.
+
+[Incompat 20021015] The Postfix LMTP client no longer lowercases email
+addresses in MAIL FROM and RCPT TO commands.
+
+[Incompat 20021013] The default Linux kernel lock style for mailbox
+delivery is changed from flock() to fcntl(). This has no impact if
+your system uses procmail for local delivery, if you use maildir-style
+mailboxes, or when mailbox access software locks mailboxes with
+username.lock files (which is usually the case with non-maildir
+mailboxes).
+
+Address classes
+===============
+
+[Feature 20021209] This release introduces the concept of address
+domain classes, each having its own default mail delivery transport:
+
+ Destination matches Default transport Default name
+ ==============================================================
+ $mydestination or
+ $inet_interfaces $local_transport local
+ $virtual_alias_domains (not applicable) (not applicable)
+ $virtual_mailbox_domains $virtual_transport virtual
+ $relay_domains $relay_transport relay
+ other $default_transport smtp
+
+The benefits of these changes are:
+
+- You no longer need to specify all the virtual(8) domains in the
+ Postfix transport map. The virtual(8) delivery agent has
+ become a first-class citizen just like local(8) or smtp(8).
+
+- On mail gateway systems, separation of inbound mail relay traffic
+ from outbound traffic. This eliminates a problem where inbound
+ mail deliveries could become resource starved in the presence of
+ a high volume of outbound mail.
+
+- The SMTP server rejects unknown recipients in a more consistent
+ manner than was possible with previous Postfix versions.
+
+See the ADDRESS_CLASS_README file for a description of address
+classes, their benefits, and their incompatibilities.
+
+New relay transport in master.cf
+================================
+
+[Incompat 20021209] Postfix no longer defaults to the "smtp"
+transport for all non-local destinations. In particular, Postfix
+now uses the "relay" mail delivery transport for delivery to domains
+matching $relay_domains. This may affect your defer_transports
+settings.
+
+On mail gateway systems, this allows us to separate inbound mail
+relay traffic from outbound traffic, and thereby eliminate a problem
+where inbound mail deliveries could become resource starved in the
+presence of a high volume of outbound mail.
+
+[Incompat 20021209] This release adds a new "relay" service to the
+Postfix master.cf file. This is a clone of the "smtp" service. If
+your Postfix is unable to connect to the "relay" service then you
+have not properly followed the installation procedure.
+
+Revision of RBL blacklisting code
+=================================
+
+[Feature 20020923] Complete rewrite of the RBL blacklisting code.
+The names of RBL restrictions are now based on a suggestion that
+was made by Liviu Daia in October 2001. See conf/sample-smtpd.cf
+or html/uce.html for details.
+
+[Feature 20020923] "reject_rbl_client rbl.domain.tld" for client
+IP address blacklisting. Based on code by LaMont Jones. The old
+"reject_maps_rbl" is now implemented as a wrapper around the
+reject_rbl_client code, and logs a warning that "reject_maps_rbl"
+is going away.
+
+[Feature 20020923] "reject_rhsbl_sender rbl.domain.tld" for sender
+domain blacklisting. Also: reject_rhsbl_client and reject_rhsbl_recipient
+for client and recipient domain blacklisting.
+
+[Feature 20020923] "rbl_reply_maps" configuration parameter for
+lookup tables with template responses per RBL server. Based on code
+by LaMont Jones. If no reply template is found the default template
+is used as specified with the default_rbl_reply configuration
+parameter. The template responses support $name expansion of
+client, helo, sender, recipient and RBL related attributes.
+
+[Incompat 20020923] The default RBL "reject" server reply now
+includes an indication of *what* is being rejected: Client host,
+Helo command, Sender address, or Recipient address. This also
+changes the logfile format.
+
+[Feature 20020923] "smtpd_expansion_filter" configuration parameter
+to control what characters are allowed in the expansion of template
+RBL reply $name macros. Characters outside the allowed set are
+replaced by "_".
+
+More sophisticated handling of UCE-related DNS lookup errors
+============================================================
+
+[Feature 20020906] More sophisticated handling of UCE-related DNS
+lookup errors. These cause Postfix to not give up so easily, so
+that some deliveries will not have to be deferred after all.
+
+[Feature 20020906] The SMTP server sets a defer_if_permit flag when
+an UCE reject restriction fails due to a temporary (DNS) problem,
+to prevent unwanted mail from slipping through. The defer_if_permit
+flag is tested at the end of the ETRN and recipient restrictions.
+
+[Feature 20020906] A similar flag, defer_if_reject, is maintained
+to prevent mail from being rejected because a whitelist operation
+(such as permit_mx_backup) fails due to a temporary (DNS) problem.
+
+[Feature 20020906] The permit_mx_backup restriction is made more
+strict. With older versions, some DNS failures would cause mail to
+be accepted anyway, and some DNS failures would cause mail to be
+rejected by later restrictions in the same restriction list. The
+improved version will defer delivery when Postfix could make the
+wrong decision.
+
+- After DNS lookup failure, permit_mx_backup will now accept the
+request if a subsequent restriction would cause the request to be
+accepted anyway, and will defer the request if a subsequent
+restriction would cause the request to be rejected.
+
+- After DNS lookup failure, reject_unknown_hostname (the hostname
+given in HELO/EHLO commands) reject_unknown_sender_domain and
+reject_unknown_recipient_domain will now reject the request if a
+subsequent restriction would cause the request to be rejected
+anyway, and will defer the request if a subsequent restriction
+would cause the request to be accepted.
+
+[Feature 20020906] Specify "smtpd_data_restrictions =
+reject_unauth_pipelining" to block mail from SMTP clients that send
+message content before Postfix has replied to the SMTP DATA command.
+
+Other UCE related changes
+=========================
+
+[Feature 20020717] The SMTP server reject_unknown_{sender,recipient}_domain
+etc. restrictions now also attempt to look up AAAA (IPV6 address)
+records.
+
+[Incompat 20020513] In order to allow user@domain@domain addresses
+from untrusted systems, specify "allow_untrusted_routing = yes" in
+main.cf. This opens opportunities for mail relay attacks when
+Postfix provides backup MX service for Sendmail systems.
+
+[Incompat 20020514] For safety reasons, the permit_mx_backup
+restriction no longer accepts mail for user@domain@domain. To
+recover the old behavior, specify "allow_untrusted_routing = yes"
+and live with the risk of becoming a relay victim.
+
+[Incompat 20020509] The Postfix SMTP server no longer honors OK
+access rules for user@domain@postfix-style.virtual.domain, to close
+a relaying loophole with postfix-style virtual domains that have
+@domain.name catch-all patterns.
+
+[Incompat 20020201] In Postfix SMTPD access tables, Postfix now
+uses <> as the default lookup key for the null address, in order
+to work around bugs in some Berkeley DB implementations. This
+behavior is controlled with the smtpd_null_access_lookup_key
+configuration parameter.
+
+Changes in transport table lookups
+==================================
+
+[Feature 20020610] user@domain address lookups in the transport
+map. This feature also understands address extensions. Transport
+maps still support lookup keys in the form of domain names, but
+only with non-regexp tables. Specify mailer-daemon@my.host.name
+in order to match the null address. More in the transport(5) manual
+page.
+
+[Feature 20020505] Friendlier behavior of Postfix transport tables.
+There is a new "*" wildcard pattern that always matches. The
+meaning of null delivery transport AND nexhop information field
+has changed to "do not modify": use the information that would be
+used if the transport table did not exist. This change makes it
+easier to route intranet mail (everything under my.domain) directly:
+you no longer need to specify explicit "local" transport table
+entries for every domain name that resolves to the local machine.
+For more information, including examples, see the updated transport(5)
+manual page.
+
+[Incompat 20020610] Regexp/PCRE-based transport maps now see the
+entire recipient address instead of only the destination domain
+name.
+
+[Incompat 20020505, 20021215] The meaning of null delivery transport
+and nexhop fields has changed incompatibly.
+
+- A null delivery transport AND nexthop information field means
+"do not modify": use the delivery transport or nexthop information
+that would be used if no transport table did not exist.
+
+- The delivery transport is not changed with a null delivery
+transport field and non-null nexthop field.
+
+- The nexthop is reset to the recipient domain with a non-null
+transport field and a null nexthop information field.
+
+Address manipulation changes
+============================
+
+[Incompat 20020717] Postfix no longer strips multiple '.' characters
+from the end of an email address or domain name. Only one '.' is
+tolerated.
+
+[Feature 20020717] The masquerade_domains feature now supports
+exceptions. Prepend a ! character to a domain name in order to
+not strip its subdomain structure. More information in
+conf/sample-rewrite.cf.
+
+[Feature 20020717] The Postfix virtual delivery agent supports
+catch-all entries (@domain.tld) in lookup tables. These match users
+that do not have a specific user@domain.tld entry. The virtual
+delivery agent now ignores address extensions (user+foo@domain.tld)
+when searching its lookup tables, but displays the extensions in
+Delivered-To: message headers.
+
+[Feature 20020610] user@domain address lookups in the transport
+map. This feature also understands address extensions. Transport
+maps still support lookup keys in the form of domain names, but
+only with non-regexp tables. Specify mailer-daemon@my.host.name
+in order to match the null address. More in the transport(5) manual
+page.
+
+[Incompat 20020610] Regexp/PCRE-based transport maps now see the
+entire recipient address instead of only the destination domain
+name.
+
+[Incompat 20020513] In order to allow user@domain@domain addresses
+from untrusted systems, specify "allow_untrusted_routing = yes" in
+main.cf. This opens opportunities for mail relay attacks when
+Postfix provides backup MX service for Sendmail systems.
+
+[Incompat 20020509] The Postfix SMTP server no longer honors OK
+access rules for user@domain@postfix-style.virtual.domain, to close
+a relaying loophole with postfix-style virtual domains that have
+@domain.name catch-all patterns.
+
+[Incompat 20020509] The appearance of user@domain1@domain2 addresses
+has changed. In mail headers, such addresses are now properly
+quoted as "user@domain1"@domain2. As a side effect, this quoted
+form is now also expected on the left-hand side of virtual and
+canonical lookup tables, but only by some of the Postfix components.
+For now, it is better not to use user@domain1@domain2 address forms
+on the left-hand side of lookup tables.
+
+Regular expression and PCRE related changes
+===========================================
+
+[Feature 20021209] Regular expression maps are now allowed with
+local delivery agent alias tables and with all virtual delivery
+agent lookup tables. However, regular expression substitution of
+$1 etc. is still forbidden for security reasons.
+
+[Obsolete 20020917] In regexp lookup tables, the form /pattern1/!/pattern2/
+is going away. Use the cleaner and more flexible "if !/pattern2/..endif"
+form. The old form still exists but is no longer documented, and
+causes a warning (suggesting to use the new format) to be logged.
+
+[Incompat 20020610] Regexp/PCRE-based transport maps now see the
+entire recipient address instead of only the destination domain
+name.
+
+[Incompat 20020528] With PCRE pattern matching, the `.' metacharacter
+now matches all characters including newline characters. This makes
+PCRE pattern matching more convenient to use with multi-line message
+headers, and also makes PCRE more compatible with regexp pattern
+matching. The pcre_table(5) manual page has been greatly revised.
+
+New mail "HOLD" action and "hold" queue
+=======================================
+
+[Feature 20020819] New "hold" queue for mail that should not be
+delivered. "postsuper -h" puts mail on hold, and "postsuper -H"
+releases mail, moving mail that was "on hold" to the deferred queue.
+
+[Feature 20020821] HOLD and DISCARD actions in SMTPD access tables.
+As with the header/body version of the same, these actions apply
+to all recipients of the same queue file.
+
+[Feature 20020819] New header/body HOLD action that causes mail to
+be placed on the "hold" queue. Presently, all you can do with mail
+"on hold" is to examine it with postcat, to take it "off hold" with
+"postsuper -H", or to destroy it with "postsuper -d". See
+conf/sample-filter.cf.
+
+[Incompat 20020819] In mailq output, the queue ID is followed by
+the ! character when the message is in the "hold" queue (see below).
+This may break programs that process mailq output.
+
+Content filtering
+=================
+
+[Feature 20020823] Selective content filtering. In in SMTPD access
+tables, specify "FILTER transport:nexthop" for mail that needs
+filtering. More info about content filtering is in the Postfix
+FILTER_README file. This feature overrides the main.cf content_filter
+setting. Presently, this applies to all the recipients of a queue
+file.
+
+[Feature 20020527] Selective content filtering. In header/body_check
+patterns, specify "FILTER transport:nexthop" for mail that needs
+filtering. This requires different cleanup servers before and after
+the filter, with header/body checks turned off in the second cleanup
+server. More info about content filtering is in the Postfix
+FILTER_README file. This feature overrides the main.cf content_filter
+setting. Presently, this applies to all the recipients of a queue
+file.
+
+[Feature 20020527] Postfix now has real MIME support. This improves
+content filtering efficiency and accuracy, and improves inter-operability
+with mail systems that cannot receive 8-bit mail. See conf/sample-mime.cf
+for details.
+
+[Feature 20020527] Postfix header_checks now properly recognize
+MIME headers in attachments. This is much more efficient than
+previous versions that recognized MIME headers via body_checks.
+MIME headers are now processed one multi-line header at a time,
+instead of one body line at a time. To get the the old behavior,
+specify "disable_mime_input_processing = yes". More details in
+conf/sample-filter.cf.
+
+[Feature 20020527] Postfix now has three classes of header patterns:
+header_checks (for primary message headers except MIME headers),
+mime_header_checks (for MIME headers), and nested_header_checks
+(for headers of attached email messages except MIME headers). By
+default, all headers are matched with header_checks.
+
+[Feature 20021013] The body_checks_max_size parameter limits the
+amount of text per message body segment (or attachment, if you
+prefer to use that term) that is subjected to body_checks inspection.
+The default limit is 50 kbytes. This speeds up the processing of
+mail with large attachments.
+
+[Feature 20020917] Speedups of regexp table lookups by optimizing
+for the $number substitutions that are actually present in the
+right-hand side. Based on a suggestion by Liviu Daia.
+
+[Feature 20020917] Speedups of regexp and pcre tables, using
+IF..ENDIF support. Based on an idea by Bert Driehuis. To protect
+a block of patterns, use:
+
+ if /pattern1/
+ /pattern2/ result2
+ /pattern3/ result3
+ endif
+
+IF..ENDIF can nest. Don't specify blanks at the beginning of lines
+inside IF..ENDIF, because lines beginning with whitespace are
+appended to the previous line. More details about the syntax are
+given in the pcre_table(5) and regexp_table(5) manual pages.
+
+Postmap/postalias/newaliases changes
+====================================
+
+[Incompat 20020505] The postalias command now copies the source
+file read permissions to the result file when creating a table for
+the first time. Until now, the result file was created with default
+read permissions. This change makes postalias more similar to
+postmap.
+
+[Incompat 20020505] The postalias and postmap commands now drop
+super-user privileges when processing a non-root source file. The
+file is now processed as the source file owner, and the owner must
+therefore have permission to update the result file. Specify the
+"-o" flag to get the old behavior (process non-root files with root
+privileges).
+
+[Incompat 20020122] When the postmap command creates a non-existent
+result file, the new file inherits the group/other read permissions
+of the source file.
+
+Assorted changes
+================
+
+[Feature 20021028] The local(8) and virtual(8) delivery agents now record
+the original recipient address in the X-Original-To: message header.
+This header can also be emitted by the pipe(8) delivery agent.
+
+[Feature 20021024] New proxy_interfaces parameter, for sites behind a
+network address translation gateway or other type of proxy. You
+should specify all the proxy network addresses here, to avoid avoid
+mail delivery loops.
+
+[Feature 20021013] Updated MacOS X support by Gerben Wierda. See
+the auxiliary/MacOSX directory.
+
+[Incompat 20021013] Subtle change in ${name?result} macro expansions:
+the expansion no longer happens when $name is an empty string. This
+probably makes more sense than the old behavior.
+
+[Incompat 20020917] The relayhost setting now behaves as documented,
+i.e. you can no longer specify multiple destinations.
+
+[Incompatibility 20021219] The use of the XVERP extension in the
+SMTP MAIL FROM command is now restricted to SMTP clients that match
+the hostnames, domains or networks listed with the authorized_verp_clients
+parameter (default: $mynetworks).
+
+[Feature 20020819] When the Postfix local delivery agent detects
+a mail delivery loop (usually the result of mis-configured mail
+pickup software), the undeliverable mail is now sent to the mailing
+list owner instead of the envelope sender address (usually the
+original poster who has no guilt, and who cannot fix the problem).
+
+[Warning 20020819] The Postfix queue manager now warns when mail
+for some destination is piling up in the active queue, and suggests
+a variety of remedies to speed up delivery (increase per-destination
+concurrency limit, increase active queue size, use a separate
+delivery transport, increase per-transport process limit). The
+qmgr_clog_warn_time parameter controls the time between warnings.
+To disable these warnings, specify "qmgr_clog_warn_time = 0".
+
+[Warning 20020717] The Postfix SMTP client now logs a warning when
+the same domain is listed in main.cf:mydestination as well as a
+Postfix-style virtual map. Such a mis-configuration may cause mail
+for users to be rejected with "user unknown".
+
+[Feature 20020331] A new smtp_helo_name parameter that specifies
+the hostname to be used in HELO or EHLO commands; this can be more
+convenient than changing the myhostname parameter setting.
+
+[Feature 20020331] Choice between multiple instances of internal
+services: bounce, cleanup, defer, error, flush, pickup, queue,
+rewrite, showq. This allows you to use different cleanup server
+settings for different SMTP server instances. For example, specify
+in the master.cf file:
+
+ localhost:10025 ... smtpd -o cleanup_service_name=cleanup2 ...
+ cleanup2 ... cleanup -o header_checks= body_checks= ...
+
+Logfile format changes
+======================
+
+[Incompat 20021209] The Postfix SMTP client no longer expands CNAMEs
+in MAIL FROM addresses (as permitted by RFC 2821) before logging
+the recipient address.
+
+[Incompat 20021028] The Postfix SMTP server UCE reject etc. logging
+now includes the queue ID, the mail protocol (SMTP or ESMTP), and
+the hostname that was received with the HELO or EHLO command, if
+available.
+
+[Incompat 20021028] The Postfix header/body_checks logging now
+includes the mail protocol (SMTP, ESMTP, QMQP) and the hostname
+that was received with the SMTP HELO or EHLO command, if available.
+
+[Incompat 20021028] The Postfix status=sent/bounced/deferred logging
+now shows the original recipient address (as received before any
+address rewriting or aliasing). The original recipient address is
+logged only when it differs from the final recipient address.
+
+[Incompat 20020923] The default RBL "reject" server reply now
+includes an indication of *what* is being rejected: Client host,
+Helo command, Sender address, or Recipient address. This also
+changes the logfile format.
+
+LDAP related changes
+====================
+
+[Incompat 20020819] LDAP API version 1 is no longer supported. The
+memory allocation and deallocation strategy has changed too much
+to maintain both version 1 and 2 at the same time.
+
+[Feature 20020513] Updated LDAP client module with better handling
+of dead LDAP servers, and with configurable filtering of query
+results.
+
+SASL related changes
+====================
+
+[Incompat 20020819] The smtpd_sasl_local_domain setting now defaults
+to the null string, rather than $myhostname. This seems to work
+better with Cyrus SASL version 2. This change may cause incompatibility
+with the saslpasswd2 command.
+
+[Feature 20020331] Support for the Cyrus SASL version 2 library,
+contributed by Jason Hoos. This adds some new functionality that
+was not available in Cyrus SASL version 1, and provides bit-rot
+insurance for the time when Cyrus SASL version 1 eventually stops
+working.
+
+Berkeley DB related changes
+===========================
+
+[Feature 20020505] Finer control over Berkeley DB memory usage,
+The parameter "berkeley_db_create_buffer_size" (default: 16 MBytes)
+specifies the buffer size for the postmap and postalias commands.
+The parameter "berkeley_db_read_buffer_size" (default: 256 kBytes)
+speficies the buffer size for all other applications. Specify
+"berkeley_db_read_buffer_size = 1048576" to get the old read buffer
+size. For more information, see the last paragraphs of the DB_README
+file.
+
+[Incompat 20020201] In Postfix SMTPD access tables, Postfix now
+uses <> as the default lookup key for the null address, in order
+to work around bugs in some Berkeley DB implementations. This
+behavior is controlled with the smtpd_null_access_lookup_key
+configuration parameter.
+
+[Incompat 20020201] Postfix now detects if the run-time Berkeley
+DB library routines do not match the major version number of the
+compile-time include file that was used for compiling Postfix. The
+software issues a warning and aborts in case of a discrepancy. If
+it didn't, the software was certain to crash with a segmentation
+violation.
+
+Assorted workarounds
+====================
+
+[Incompat 20020201] On SCO 3.2 UNIX, the input rate flow control
+is now turned off by default, because of limitations in the SCO
+UNIX kernel.
#
# - You define $mydestination domain recipients in files other than
# /etc/passwd, /etc/aliases, or the $virtual_alias_maps files.
-# For example, you define $mydestination domain recipients in
+# For example, you define $mydestination domain recipients in
# the $virtual_mailbox_maps files.
#
# - You redefined the local delivery agent in master.cf.
rewrite unix - - n - - trivial-rewrite
bounce unix - - n - 0 bounce
defer unix - - n - 0 bounce
+trace unix - - n - 0 bounce
+verify unix - - n - 1 verify
flush unix n - n 1000? 0 flush
smtp unix - - n - - smtp
relay unix - - n - - smtp
EOF
}
+ # Add missing trace service to master.cf.
+
+ grep 'trace.*bounce' $config_directory/master.cf >/dev/null || {
+ echo Editing $config_directory/master.cf, adding missing entry for trace service
+ cat >>$config_directory/master.cf <<EOF || exit 1
+trace unix - - n - 0 bounce
+EOF
+ }
+
+ # Add missing verify service to master.cf.
+
+ grep '^verify.*verify' $config_directory/master.cf >/dev/null || {
+ echo Editing $config_directory/master.cf, adding missing entry for verify service
+ cat >>$config_directory/master.cf <<EOF || exit 1
+verify unix - - n - 1 verify
+EOF
+ }
+
+ # Fix verify service process limit.
+
+ grep '^verify.*[ ]0[ ]*verify' \
+ $config_directory/master.cf >/dev/null && {
+ echo Editing $config_directory/master.cf, setting verify process limit to 1
+ ed $config_directory/master.cf <<EOF || exit 1
+/^verify.*[ ]0[ ]*verify/
+s/\([ ]\)0\([ ]\)/\11\2/
+p
+w
+q
+EOF
+ }
+
# Change privileged pickup service into unprivileged.
grep "^pickup[ ]*fifo[ ]*n[ ]*n" \
if [ -z "$has_lrm" -a -z "$has_lrjc" ]
then
echo SAFETY: editing main.cf, setting $unknown_local=450.
- echo See the RELEASE_NOTES and $config_directory/main.cf for details.
+ echo See the RELEASE_NOTES and LOCAL_RECIPIENT_README files for details.
$POSTCONF -e "$unknown_local = 450" || exit 1
fi
$queue_directory/maildrop:d:$mail_owner:$setgid_group:730:uc
$queue_directory/public:d:$mail_owner:$setgid_group:710:uc
$queue_directory/pid:d:root:-:755:uc
+$queue_directory/trace:d:$mail_owner:-:700:ucr
$daemon_directory/bounce:f:root:-:755
$daemon_directory/cleanup:f:root:-:755
$daemon_directory/error:f:root:-:755
$daemon_directory/smtpd:f:root:-:755
$daemon_directory/spawn:f:root:-:755
$daemon_directory/trivial-rewrite:f:root:-:755
+$daemon_directory/verify:f:root:-:755
$daemon_directory/virtual:f:root:-:755
$command_directory/postalias:f:root:-:755
$command_directory/postcat:f:root:-:755
$manpage_directory/man8/smtp.8:f:root:-:644
$manpage_directory/man8/smtpd.8:f:root:-:644
$manpage_directory/man8/spawn.8:f:root:-:644
+$manpage_directory/man8/trace.8:f:root:-:644
$manpage_directory/man8/trivial-rewrite.8:f:root:-:644
+$manpage_directory/man8/verify.8:f:root:-:644
$manpage_directory/man8/virtual.8:f:root:-:644
$sample_directory/sample-aliases.cf:f:root:-:644
$sample_directory/sample-auth.cf:f:root:-:644
$sample_directory/sample-smtp.cf:f:root:-:644
$sample_directory/sample-smtpd.cf:f:root:-:644
$sample_directory/sample-transport.cf:f:root:-:644
+$sample_directory/sample-verify.cf:f:root:-:644
$sample_directory/sample-virtual.cf:f:root:-:644
$readme_directory/ADDRESS_CLASS_README:f:root:-:644
$readme_directory/DB_README:f:root:-:644
}
find `ls -d $queue_directory/* | \
- egrep '/(incoming|active|defer|deferred|bounce|hold|corrupt|public|private|flush)$'` \
+ egrep '/(incoming|active|defer|deferred|bounce|hold|trace|corrupt|public|private|flush)$'` \
! \( -type p -o -type s \) ! -user $mail_owner \
-exec $WARN not owned by $mail_owner: {} \;
#
# *permit_mynetworks: permit if the client address matches $mynetworks.
# reject_unknown_sender_domain: reject sender domain without A or MX record.
+# reject_unverified_sender: reject undeliverable sender address.
+# reject_unverified_recipient: reject undeliverable recipient address.
+# reject_multi_recipient_bounce: reject mail from <> with multiple recipients.
# reject_rhsbl_recipient domain.tld: reject recipient domain name if it is
# listed in an A record under domain.tld.
# permit_auth_destination: permit mail
#
maps_rbl_reject_code = 550
+# The multi_recipient_bounce_reject_code parameter specifies the SMTP
+# server response when an SMTP client request is blocked by the
+# reject_multi_recipient_bounce restriction.
+#
+# Do not change this unless you have a complete understanding of RFC 821.
+#
+multi_recipient_bounce_reject_code = 550
+
# The rbl_reply_maps parameter specifies tables with RBL response
# templates, indexed by RBL domain name. By default, Postfix uses
# the default template as specified with the default_rbl_reply
#
unknown_address_reject_code = 450
+# The unverified_sender_reject_code parameter specifies the SMTP
+# server response when a client violates the reject_unverified_sender
+# restriction.
+#
+# Unlike elsewhere in Postfix, you can specify 250 in order to
+# accept the address anyway.
+#
+# Do not change this unless you have a complete understanding of RFC 821.
+#
+unverified_sender_reject_code = 450
+
+# The unverified_recipient_reject_code parameter specifies the SMTP
+# server response when a client violates the reject_unverified_recipient
+# restriction.
+#
+# Unlike elsewhere in Postfix, you can specify 250 in order to
+# accept the address anyway.
+#
+# Do not change this unless you have a complete understanding of RFC 821.
+#
+unverified_recipient_reject_code = 450
+
# The unknown_client_reject_code parameter specifies the SMTP server
# response when a client without address to name mapping violates
# the reject_unknown_client restriction.
--- /dev/null
+# DO NOT EDIT THIS FILE. EDIT THE MAIN.CF FILE INSTEAD. THE STUFF
+# HERE JUST SERVES AS AN EXAMPLE.
+#
+# This file contains example settings of Postfix configuration
+# parameters that control the SMTP client program.
+
+#
+# ADDRESS VERIFICATION (see also: verify(8) and SENDER_VERIFICATION_README)
+#
+
+# The address_verify_map configuration parameter specifies an optional
+# table for persistent recipient status storage. The file is opened
+# before the process enters a chroot jail and before it drops root
+# privileges.
+#
+# By default, the information is kept in volatile memory, and is lost
+# after postfix reload or postfix stop.
+#
+# Specify a pathname in a file system that will not fill up. If the
+# database becomes corrupted, the world comes to an end. To recover
+# you have to delete the file and do "postfix reload".
+#
+#address_verify_map = hash:/etc/postfix/verify
+#address_verify_map = btree:/etc/postfix/verify
+address_verify_map =
+
+# The address_verify_sender configuration parameter specifies the
+# sender address that Postfix will use in address verification probe
+# messages.
+#
+# By default, the probe sender address is postmaster@$myorigin.
+#
+# Specify an empty value (address_verify_sender =) or <> if you want
+# to use the null sender address. Beware, some sites reject mail from
+# <>, even though RFCs require that such addresses to be accepted.
+#
+#address_verify_sender = <>
+#address_verify_sender = postmaster@my.domain
+address_verify_sender = postmaster
+
+# The address_verify_positive_expire_time configuration parameter
+# specifies the amount of time after which a known to be good address
+# expires.
+#
+# Time units: s (seconds), m (minutes), h (hours), d (days), w (weeks).
+#
+address_verify_positive_expire_time = 31d
+
+# The address_verify_positive_refresh_time configuration parameter
+# specifies the minimal amount of time after which a proactive probe
+# is sent to verify that a known to be good address is still good.
+# The address status is not updated when the probe fails (optimistic
+# caching).
+#
+# Time units: s (seconds), m (minutes), h (hours), d (days), w (weeks).
+#
+address_verify_positive_refresh_time = 7d
+
+# The address_verify_negative_cache configuration parameter specifies
+# whether negative probe results are stored in the address verification
+# cache. When enabled, the cache may pollute quickly with garbage.
+# When disabled, Postfix will generate an address probe for every
+# lookup.
+#
+address_verify_negative_cache = yes
+
+# The address_verify_negative_expire_time configuration parameter
+# specifies the amount of time after which a rejected address expires
+# from the address verification cache.
+#
+# Time units: s (seconds), m (minutes), h (hours), d (days), w (weeks).
+#
+address_verify_negative_expire_time = 3d
+
+# The address_verify_negative_refresh_time configuration parameter
+# speficies the minimal amount of time after which a proactive probe
+# is sent to verify that a known to be bad address is still bad.
+#
+# Time units: s (seconds), m (minutes), h (hours), d (days), w (weeks).
+#
+address_verify_negative_refresh_time = 2h
DAEMONS = bounce.8.html cleanup.8.html defer.8.html error.8.html local.8.html \
lmtp.8.html master.8.html pickup.8.html pipe.8.html qmgr.8.html \
showq.8.html smtp.8.html smtpd.8.html trivial-rewrite.8.html \
- nqmgr.8.html spawn.8.html flush.8.html virtual.8.html qmqpd.8.html
+ nqmgr.8.html spawn.8.html flush.8.html virtual.8.html qmqpd.8.html \
+ trace.8.html verify.8.html
COMMANDS= mailq.1.html newaliases.1.html postalias.1.html postcat.1.html \
postconf.1.html postfix.1.html postkick.1.html postlock.1.html \
postlog.1.html postdrop.1.html postmap.1.html sendmail.1.html \
PATH=../mantools:$$PATH; \
srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@
+trace.8.html: bounce.8.html
+ rm -f $@
+ ln -s $? $@
+
trivial-rewrite.8.html: ../src/trivial-rewrite/trivial-rewrite.c
PATH=../mantools:$$PATH; \
srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@
+verify.8.html: ../src/verify/verify.c
+ PATH=../mantools:$$PATH; \
+ srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@
+
postalias.1.html: ../src/postalias/postalias.c
PATH=../mantools:$$PATH; \
srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@
<p>
-<li>The <a href="bounce.8.html">bounce or defer</a> daemon is called
-upon left and right by other daemon processes, in order to maintain
-per-message log files with non-delivery status information.
+<li>The <a href="bounce.8.html">bounce, defer, or trace</a> daemon
+is called upon left and right by other daemon processes, in order
+to maintain per-message log files with delivery status information.
<p>
<p>
+<li>The <a href="verify.8.html">verify</a> daemon maintains the
+address verification cache that is used by the
+\fBreject_unverified_sender\fR and \fBreject_unverified_recipient\fR
+UCE restrictions.
+
+<p>
+
<li>The <a href="spawn.8.html">spawn</a> daemon listens on a TCP
port, UNIX-domain socket or FIFO, and runs non-Postfix commands on
request, with the socket or FIFO connected to the standard input,
non-delivery status information. Each log file is named
after the queue file that it corresponds to, and is kept
in a queue subdirectory named after the service name in
- the <b>master.cf</b> file (either <b>bounce</b> or <b>defer</b>). This program
- expects to be run from the <a href="master.8.html"><b>master</b>(8)</a> process manager.
+ the <b>master.cf</b> file (either <b>bounce</b>, <b>defer</b> or <b>trace</b>). This
+ program expects to be run from the <a href="master.8.html"><b>master</b>(8)</a> process man-
+ ager.
The <b>bounce</b> daemon processes two types of service requests:
- <b>o</b> Append a recipient status record to a per-message
+ <b>o</b> Append a recipient status record to a per-message
log file.
- <b>o</b> Post a bounce message, with a copy of a log file
- and of the corresponding message. When the bounce
+ <b>o</b> Post a bounce message, with a copy of a log file
+ and of the corresponding message. When the bounce
is posted successfully, the log file is deleted.
- The software does a best effort to notify the sender that
- there was a problem. A notification is sent even when the
+ The software does a best effort to notify the sender that
+ there was a problem. A notification is sent even when the
log file or original message cannot be read.
- Optionally, a client can request that the per-message log
- file be deleted when the requested operation fails. This
+ Optionally, a client can request that the per-message log
+ file be deleted when the requested operation fails. This
is used by clients that cannot retry transactions by them-
- selves, and that depend on retry logic in their own
+ selves, and that depend on retry logic in their own
client.
<b>STANDARDS</b>
Problems and transactions are logged to <b>syslogd</b>(8).
<b>BUGS</b>
- The log files use an ad-hoc, unstructured format. This
- will have to change in order to easily support standard
+ The log files use an ad-hoc, unstructured format. This
+ will have to change in order to easily support standard
delivery status notifications.
<b>CONFIGURATION</b> <b>PARAMETERS</b>
- The following <b>main.cf</b> parameters are especially relevant
- to this program. See the Postfix <b>main.cf</b> file for syntax
- details and for default values. Use the <b>postfix</b> <b>reload</b>
+ The following <b>main.cf</b> parameters are especially relevant
+ to this program. See the Postfix <b>main.cf</b> file for syntax
+ details and for default values. Use the <b>postfix</b> <b>reload</b>
command after a configuration change.
<b>bounce</b><i>_</i><b>notice</b><i>_</i><b>recipient</b>
- The recipient of single bounce postmaster notices.
+ The recipient of single bounce postmaster notices.
<b>2bounce</b><i>_</i><b>notice</b><i>_</i><b>recipient</b>
- The recipient of double bounce postmaster notices.
+ The recipient of double bounce postmaster notices.
<b>delay</b><i>_</i><b>notice</b><i>_</i><b>recipient</b>
The recipient of "delayed mail" postmaster notices.
<b>bounce</b><i>_</i><b>size</b><i>_</i><b>limit</b>
- Limit the amount of original message context that
+ Limit the amount of original message context that
is sent in a non-delivery notification.
+ <b>backwards</b><i>_</i><b>bounce</b><i>_</i><b>logfile</b><i>_</i><b>compatibility</b>
+ Controls whether the logfile will be readable by
+ old Postfix versions that used the ad-hoc logfile
+ format of <i>&</i>lt;<i>address&</i>gt;<i>:</i> <i>text</i>.
+
<b>mail</b><i>_</i><b>name</b>
- Use this mail system name in the introductory text
+ Use this mail system name in the introductory text
at the start of a bounce message.
<b>notify</b><i>_</i><b>classes</b>
- Notify the postmaster of bounced mail when this
- parameter includes the <b>bounce</b> class. For privacy
+ Notify the postmaster of bounced mail when this
+ parameter includes the <b>bounce</b> class. For privacy
reasons, the message body is not included.
<b>SEE</b> <b>ALSO</b>
syslogd(8) system logging
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>
By default, <b>postsuper</b> performs the operations requested
with the <b>-s</b> and <b>-p</b> command-line options on all Postfix
queue directories - this includes the <b>incoming</b>, <b>active</b> and
- <b>deferred</b> directories with mail files and the <b>bounce</b>, <b>defer</b>
- and <b>flush</b> directories with log files.
+ <b>deferred</b> directories with mail files and the <b>bounce</b>,
+ <b>defer</b>, <b>trace</b> and <b>flush</b> directories with log files.
Options:
This mode of operation is implemented by running
the <a href="smtpd.8.html"><b>smtpd</b>(8)</a> daemon.
+ <b>-bv</b> Send an email report after verifying each recipient
+ address. Verification always happens in the back-
+ ground. This is useful for testing address rewrit-
+ ing and routing configurations.
+
<b>-f</b> <i>sender</i>
Set the envelope sender address. This is the
address where delivery problems are sent to, unless
- the message contains an <b>Errors-To:</b> message header.
+ the message contains an <b>Errors-To:</b> message header.
<b>-h</b> <i>hop_count</i> (ignored)
- Hop count limit. Use the <b>hopcount</b><i>_</i><b>limit</b> configura-
+ Hop count limit. Use the <b>hopcount</b><i>_</i><b>limit</b> configura-
tion parameter instead.
- <b>-i</b> When reading a message from standard input, don't
- treat a line with only a <b>.</b> character as the end of
+ <b>-i</b> When reading a message from standard input, don't
+ treat a line with only a <b>.</b> character as the end of
input.
<b>-m</b> (ignored)
Backwards compatibility.
<b>-oA</b><i>alias_database</i>
- Non-default alias database. Specify <i>pathname</i> or
+ Non-default alias database. Specify <i>pathname</i> or
<i>type</i>:<i>pathname</i>. See <a href="postalias.1.html"><b>postalias</b>(1)</a> for details.
<b>-o7</b> (ignored)
<b>-o8</b> (ignored)
To send 8-bit or binary content, use an appropriate
- MIME encapsulation and specify the appropriate <b>-B</b>
+ MIME encapsulation and specify the appropriate <b>-B</b>
command-line option.
- <b>-oi</b> When reading a message from standard input, don't
- treat a line with only a <b>.</b> character as the end of
+ <b>-oi</b> When reading a message from standard input, don't
+ treat a line with only a <b>.</b> character as the end of
input.
<b>-om</b> (ignored)
- The sender is never eliminated from alias etc.
+ The sender is never eliminated from alias etc.
expansions.
<b>-o</b> <i>x</i> <i>value</i> (ignored)
- Set option <i>x</i> to <i>value</i>. Use the equivalent configu-
+ Set option <i>x</i> to <i>value</i>. Use the equivalent configu-
ration parameter in <b>main.cf</b> instead.
<b>-r</b> <i>sender</i>
Set the envelope sender address. This is the
address where delivery problems are sent to, unless
- the message contains an <b>Errors-To:</b> message header.
+ the message contains an <b>Errors-To:</b> message header.
- <b>-q</b> Attempt to deliver all queued mail. This is imple-
+ <b>-q</b> Attempt to deliver all queued mail. This is imple-
mented by executing the <a href="postqueue.1.html"><b>postqueue</b>(1)</a> command.
<b>-q</b><i>interval</i> (ignored)
- The interval between queue runs. Use the
+ The interval between queue runs. Use the
<b>queue</b><i>_</i><b>run</b><i>_</i><b>delay</b> configuration parameter instead.
<b>-qR</b><i>site</i>
- Schedule immediate delivery of all mail that is
+ Schedule immediate delivery of all mail that is
queued for the named <i>site</i>. This option accepts only
- <i>site</i> names that are eligible for the "fast flush"
- service, and is implemented by executing the
+ <i>site</i> names that are eligible for the "fast flush"
+ service, and is implemented by executing the
<a href="postqueue.1.html"><b>postqueue</b>(1)</a> command. See <a href="flushd.8.html"><b>flush</b>(8)</a> for more infor-
mation about the "fast flush" service.
<b>-qS</b><i>site</i>
- This command is not implemented. Use the slower
+ This command is not implemented. Use the slower
<b>sendmail</b> <b>-q</b> command instead.
- <b>-t</b> Extract recipients from message headers. This
- requires that no recipients be specified on the
+ <b>-t</b> Extract recipients from message headers. This
+ requires that no recipients be specified on the
command line.
- <b>-v</b> Enable verbose logging for debugging purposes. Mul-
- tiple <b>-v</b> options make the software increasingly
- verbose. For compatibility with mailx and other
- mail submission software, a single <b>-v</b> option pro-
- duces no output.
+ <b>-v</b> Send an email report of all delivery attempts (mail
+ delivery always happens in the background). When
+ multiple <b>-v</b> options are given, enable verbose log-
+ ging for debugging purposes.
<b>SECURITY</b>
By design, this program is not set-user (or group) id.
received, a warning is logged that the mail may be
delivered multiple times.
+ <b>smtp</b><i>_</i><b>rset</b><i>_</i><b>timeout</b>
+ Timeout for sending the <b>RSET</b> command.
+
<b>smtp</b><i>_</i><b>quit</b><i>_</i><b>timeout</b>
Timeout for sending the <b>QUIT</b> command, and for
receiving the server response.
<b>maps</b><i>_</i><b>rbl</b><i>_</i><b>reject</b><i>_</i><b>code</b>
Response code when a request is RBL blacklisted.
+ <b>multi</b><i>_</i><b>recipient</b><i>_</i><b>bounce</b><i>_</i><b>reject</b><i>_</i><b>code</b>
+ Response code when a multi-recipient bounce is
+ blocked.
+
<b>rbl</b><i>_</i><b>reply</b><i>_</i><b>maps</b>
- Table with template responses for RBL blacklisted
- requests, indexed by RBL domain name. These tem-
+ Table with template responses for RBL blacklisted
+ requests, indexed by RBL domain name. These tem-
plates are used by the <b>reject</b><i>_</i><b>rbl</b><i>_</i><b>*</b> and
- <b>reject</b><i>_</i><b>rhsbl</b><i>_</i><b>*</b> restrictions. See also:
+ <b>reject</b><i>_</i><b>rhsbl</b><i>_</i><b>*</b> restrictions. See also:
<b>default</b><i>_</i><b>rbl</b><i>_</i><b>reply</b> and <b>smtpd</b><i>_</i><b>expansion</b><i>_</i><b>filter</b>.
<b>reject</b><i>_</i><b>code</b>
- Response code when the client matches a <b>reject</b>
+ Response code when the client matches a <b>reject</b>
restriction.
<b>relay</b><i>_</i><b>domains</b><i>_</i><b>reject</b><i>_</i><b>code</b>
mail relay policy.
<b>unknown</b><i>_</i><b>address</b><i>_</i><b>reject</b><i>_</i><b>code</b>
- Response code when a client violates the
+ Response code when a client violates the
<b>reject</b><i>_</i><b>unknown</b><i>_</i><b>address</b> restriction.
<b>unknown</b><i>_</i><b>client</b><i>_</i><b>reject</b><i>_</i><b>code</b>
tion.
<b>unknown</b><i>_</i><b>hostname</b><i>_</i><b>reject</b><i>_</i><b>code</b>
- Response code when a client violates the
+ Response code when a client violates the
<b>reject</b><i>_</i><b>unknown</b><i>_</i><b>hostname</b> restriction.
+ <b>unverified</b><i>_</i><b>sender</b><i>_</i><b>reject</b><i>_</i><b>code</b>
+ Response code when a sender address is known to be
+ undeliverable.
+
+ <b>unverified</b><i>_</i><b>recipient</b><i>_</i><b>reject</b><i>_</i><b>code</b>
+ Response code when a recipient address is known to
+ be undeliverable.
+
<b>SEE</b> <b>ALSO</b>
<a href="trivial-rewrite.8.html">trivial-rewrite(8)</a> address resolver
<a href="cleanup.8.html">cleanup(8)</a> message canonicalization
syslogd(8) system logging
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>
--- /dev/null
+bounce.8.html
\ No newline at end of file
<p>
+<a name="reject_unverified_sender">
+
+<dt> <b>reject_unverified_sender</b> <dd> Reject the request when
+mail to the sender address is known to bounce, or when the sender
+address destination is not reachable. Address verification
+information is managed by the <a href="verify.8.html"> verify</a>(8)
+server. The <b>unverified_sender_reject_code </b> parameter
+specifies the response when an address is known to bounce (default:
+450, change into 550 when you are confident that it is safe to do
+so). Postfix replies with 450 when an address probe failed due to
+a temporary problem.
+
+<p>
+
<a name="reject_rhsbl_sender">
<dt> <b>reject_rhsbl_sender</b> <i>domain.tld</i> <dd> Reject the
<p>
+<a name="reject_multi_recipient_bounce">
+
+<dt> <b>reject_multi_recipient_bounce</b> <dd> Reject the request
+when the envelope sender is the null address, and the message has
+multiple envelope recipients. The <b>multi_recipient_bounce_reject_code
+</b> parameter specifies the response code for rejected requests
+(default: <b>550</b>).
+
+<p>
+
<a name="reject_unknown_recipient_domain">
<dt> <b>reject_unknown_recipient_domain</b> <dd> Reject the request
<p>
+<a name="reject_unverified_recipient">
+
+<dt> <b>reject_unverified_recipient</b> <dd> Reject the request when
+mail to the recipient address is known to bounce, or when the recipient
+address destination is not reachable. Address verification
+information is managed by the <a href="verify.8.html"> verify</a>(8)
+server. The <b>unverified_recipient_reject_code </b> parameter
+specifies the response when an address is known to bounce (default:
+450, change into 550 when you are confident that it is safe to do
+so). Postfix replies with 450 when an address probe failed due to
+a temporary problem.
+
+<p>
+
<a name="reject_rhsbl_recipient">
<dt> <b>reject_rhsbl_recipient</b> <i>domain.tld</i> <dd> Reject the
--- /dev/null
+<html> <head> </head> <body> <pre>
+VERIFY(8) VERIFY(8)
+
+<b>NAME</b>
+ verify - Postfix address verification server
+
+<b>SYNOPSIS</b>
+ <b>verify</b> [generic Postfix daemon options]
+
+<b>DESCRIPTION</b>
+ The Postfix address verification server maintains a record
+ of what recipient addresses are known to be deliverable or
+ undeliverable.
+
+ Addresses are verified by submitting probe messages to the
+ Postfix queue. Probe messages are run through all the
+ routing and rewriting machinery except for final delivery,
+ and are discarded rather than being deferred or bounced.
+
+ Address verification relies on the answer from the nearest
+ MTA for the specified address, and will therefore not
+ detect all undeliverable addresses.
+
+ This server is designed to run under control by the Post-
+ fix master server. It maintains an optional persistent
+ database. To avoid being interrupted by "postfix stop" in
+ the middle of a database update, the process runs in a
+ separate process group.
+
+ This server implements the following requests:
+
+ <b>VRFY</b><i>_</i><b>ADDR</b><i>_</i><b>UPDATE</b> <i>address</i> <i>status</i> <i>text</i>
+ Update the status of the specified address.
+
+ <b>VRFY</b><i>_</i><b>ADDR</b><i>_</i><b>QUERY</b> <i>address</i>
+ Look up the <i>status</i> and <i>text</i> of the specified
+ address. If the status is unknown, a probe is sent
+ and a default status is returned.
+
+ The server reply status is one of:
+
+ <b>VRFYSTAT</b><i>_</i><b>OK</b>
+ The request completed normally.
+
+ <b>VRFYSTAT</b><i>_</i><b>BAD</b>
+ The server rejected the request (bad request name,
+ bad request parameter value).
+
+ <b>VRFYSTAT</b><i>_</i><b>FAIL</b>
+ The request failed.
+
+ The recipient status is one of:
+
+ <b>DEL</b><i>_</i><b>RCPT</b><i>_</i><b>STAT</b><i>_</i><b>OK</b>
+ The address is deliverable.
+
+ <b>DEL</b><i>_</i><b>RCPT</b><i>_</i><b>STAT</b><i>_</i><b>DEFER</b>
+ The address is undeliverable due to a temporary
+ problem.
+
+ <b>DEL</b><i>_</i><b>RCPT</b><i>_</i><b>STAT</b><i>_</i><b>BOUNCE</b>
+ The address is undeliverable due to a permanent
+ problem.
+
+ <b>DEL</b><i>_</i><b>RCPT</b><i>_</i><b>STAT</b><i>_</i><b>TODO</b>
+ The address status is being determined.
+
+<b>SECURITY</b>
+ The address verification server is not security-sensitive.
+ It does not talk to the network, and it does not talk to
+ local users. The verify server can run chrooted at fixed
+ low privilege.
+
+ The address verification server can be coerced to store
+ unlimited amounts of garbage. Limiting the cache size
+ trades one problem (disk space exhaustion) for another one
+ (poor response time to client requests).
+
+<b>DIAGNOSTICS</b>
+ Problems and transactions are logged to <b>syslogd</b>(8).
+
+<b>BUGS</b>
+ This prototype server uses synchronous submission for
+ sending a probe message, which can be slow on a busy
+ machine.
+
+ If the persistent database ever gets corrupted then the
+ world comes to an end and human intervention is needed.
+ This violates a basic Postfix principle.
+
+<b>CONFIGURATION</b> <b>PARAMETERS</b>
+ See the Postfix <b>main.cf</b> file for syntax details and for
+ default values. Use the <b>postfix</b> <b>reload</b> command after a
+ configuration change.
+
+ <b>address</b><i>_</i><b>verify</b><i>_</i><b>map</b>
+ Optional table for persistent recipient status
+ storage. The file is opened before the process
+ enters a chroot jail and before it drops root priv-
+ ileges. By default, the information is kept in
+ volatile memory, and is lost after <b>postfix</b> <b>reload</b>
+ or <b>postfix</b> <b>stop</b>.
+
+ To recover from a corrupted address verification
+ database, delete the file and do <b>postfix</b> <b>reload</b>.
+
+ <b>address</b><i>_</i><b>verify</b><i>_</i><b>sender</b>
+ The sender address to use for probe messages. Spec-
+ ify an empty value (<b>address</b><i>_</i><b>verify</b><i>_</i><b>sender</b> <b>=</b>) or <>
+ if you want to use the null sender address.
+
+ <b>address</b><i>_</i><b>verify</b><i>_</i><b>positive</b><i>_</i><b>expire</b><i>_</i><b>time</b>
+ The amount of time after which a known to be good
+ address expires.
+
+ <b>address</b><i>_</i><b>verify</b><i>_</i><b>positive</b><i>_</i><b>refresh</b><i>_</i><b>time</b>
+ The minimal amount of time after which a proactive
+ probe is sent to verify that a known to be good
+ address is still good. The address status is not
+ updated when the probe fails (optimistic caching).
+
+ <b>address</b><i>_</i><b>verify</b><i>_</i><b>negative</b><i>_</i><b>cache</b>
+ A boolean parameter that controls whether negative
+ probe results are stored in the address verifica-
+ tion cache. When enabled, the cache may pollute
+ quickly with garbage. When disabled, Postfix will
+ generate an address probe for every lookup.
+
+ <b>address</b><i>_</i><b>verify</b><i>_</i><b>negative</b><i>_</i><b>expire</b><i>_</i><b>time</b>
+ The amount of time after which a rejected address
+ expires.
+
+ <b>address</b><i>_</i><b>verify</b><i>_</i><b>negative</b><i>_</i><b>refresh</b><i>_</i><b>time</b>
+ The minimal amount of time after which a proactive
+ probe is sent to verify that a known to be bad
+ address is still bad.
+
+<b>SEE</b> <b>ALSO</b>
+ verify_clnt(3) address verification client
+
+<b>LICENSE</b>
+ The Secure Mailer license must be distributed with this
+ software.
+
+<b>AUTHOR(S)</b>
+ Wietse Venema
+ IBM T.J. Watson Research
+ P.O. Box 704
+ Yorktown Heights, NY 10598, USA
+
+ VERIFY(8)
+</pre> </body> </html>
DAEMONS = man8/bounce.8 man8/defer.8 man8/cleanup.8 man8/error.8 man8/local.8 \
man8/lmtp.8 man8/master.8 man8/pickup.8 man8/pipe.8 man8/qmgr.8 \
man8/showq.8 man8/smtp.8 man8/smtpd.8 man8/trivial-rewrite.8 \
- man8/nqmgr.8 man8/spawn.8 man8/flush.8 man8/virtual.8 man8/qmqpd.8
+ man8/nqmgr.8 man8/spawn.8 man8/flush.8 man8/virtual.8 man8/qmqpd.8 \
+ man8/verify.8 man8/trace.8
COMMANDS= man1/postalias.1 man1/postcat.1 man1/postconf.1 man1/postfix.1 \
man1/postkick.1 man1/postlock.1 man1/postlog.1 man1/postdrop.1 \
man1/postmap.1 man1/sendmail.1 man1/mailq.1 man1/newaliases.1 \
man8/virtual.8: ../src/virtual/virtual.c
../mantools/srctoman $? >$@
+man8/verify.8: ../src/verify/verify.c
+ ../mantools/srctoman $? >$@
+
+man8/trace.8:
+ echo .so man8/bounce.8 >$@
+
man8/trivial-rewrite.8: ../src/trivial-rewrite/trivial-rewrite.c
../mantools/srctoman $? >$@
\fB-s\fR and \fB-p\fR command-line options on all Postfix queue
directories - this includes the \fBincoming\fR, \fBactive\fR and
\fBdeferred\fR directories with mail files and the \fBbounce\fR,
-\fBdefer\fR and \fBflush\fR directories with log files.
+\fBdefer\fR, \fBtrace\fR and \fBflush\fR directories with log files.
Options:
.IP "\fB-c \fIconfig_dir\fR"
.sp
This mode of operation is implemented by running the
\fBsmtpd\fR(8) daemon.
+.IP \fB-bv\fR
+Send an email report after verifying each recipient address.
+Verification always happens in the background. This is useful
+for testing address rewriting and routing configurations.
.IP "\fB-f \fIsender\fR"
Set the envelope sender address. This is the address where
delivery problems are sent to, unless the message contains an
Extract recipients from message headers. This requires that no
recipients be specified on the command line.
.IP \fB-v\fR
-Enable verbose logging for debugging purposes. Multiple \fB-v\fR
-options make the software increasingly verbose. For compatibility
-with mailx and other mail submission software, a single \fB-v\fR
-option produces no output.
+Send an email report of all delivery attempts (mail delivery
+always happens in the background). When multiple \fB-v\fR
+options are given, enable verbose logging for debugging purposes.
.SH SECURITY
.na
.nf
non-delivery status information. Each log file is named after the
queue file that it corresponds to, and is kept in a queue subdirectory
named after the service name in the \fBmaster.cf\fR file (either
-\fBbounce\fR or \fBdefer\fR).
+\fBbounce\fR, \fBdefer\fR or \fBtrace\fR).
This program expects to be run from the \fBmaster\fR(8) process
manager.
.IP \fBbounce_size_limit\fR
Limit the amount of original message context that is sent in
a non-delivery notification.
+.IP \fBbackwards_bounce_logfile_compatibility\fR
+Controls whether the logfile will be readable by old Postfix versions
+that used the ad-hoc logfile format of \fI<address>: text\fR.
.IP \fBmail_name\fR
Use this mail system name in the introductory text at the
start of a bounce message.
Timeout for sending the "\fB.\fR" command, and for
receiving the server response. When no response is received, a
warning is logged that the mail may be delivered multiple times.
+.IP \fBsmtp_rset_timeout\fR
+Timeout for sending the \fBRSET\fR command.
.IP \fBsmtp_quit_timeout\fR
Timeout for sending the \fBQUIT\fR command, and for
receiving the server response.
restriction.
.IP \fBmaps_rbl_reject_code\fR
Response code when a request is RBL blacklisted.
+.IP \fBmulti_recipient_bounce_reject_code\fR
+Response code when a multi-recipient bounce is blocked.
.IP \fBrbl_reply_maps\fR
Table with template responses for RBL blacklisted requests, indexed by
RBL domain name. These templates are used by the \fBreject_rbl_*\fR
.IP \fBunknown_hostname_reject_code\fR
Response code when a client violates the \fBreject_unknown_hostname\fR
restriction.
+.IP \fBunverified_sender_reject_code\fR
+Response code when a sender address is known to be undeliverable.
+.IP \fBunverified_recipient_reject_code\fR
+Response code when a recipient address is known to be undeliverable.
.SH SEE ALSO
.na
.nf
--- /dev/null
+.so man8/bounce.8
--- /dev/null
+.TH VERIFY 8
+.ad
+.fi
+.SH NAME
+verify
+\-
+Postfix address verification server
+.SH SYNOPSIS
+.na
+.nf
+\fBverify\fR [generic Postfix daemon options]
+.SH DESCRIPTION
+.ad
+.fi
+The Postfix address verification server maintains a record
+of what recipient addresses are known to be deliverable or
+undeliverable.
+
+Addresses are verified by submitting probe messages to the
+Postfix queue. Probe messages are run through all the routing
+and rewriting machinery except for final delivery, and are
+discarded rather than being deferred or bounced.
+
+Address verification relies on the answer from the nearest
+MTA for the specified address, and will therefore not detect
+all undeliverable addresses.
+
+This server is designed to run under control by the Postfix
+master server. It maintains an optional persistent database.
+To avoid being interrupted by "postfix stop" in the middle
+of a database update, the process runs in a separate process
+group.
+
+This server implements the following requests:
+.IP "\fBVRFY_ADDR_UPDATE\fI address status text\fR"
+Update the status of the specified address.
+.IP "\fBVRFY_ADDR_QUERY\fI address\fR"
+Look up the \fIstatus\fR and \fItext\fR of the specified address.
+If the status is unknown, a probe is sent and a default status is
+returned.
+.PP
+The server reply status is one of:
+.IP \fBVRFYSTAT_OK\fR
+The request completed normally.
+.IP \fBVRFYSTAT_BAD\fR
+The server rejected the request (bad request name, bad
+request parameter value).
+.IP \fBVRFYSTAT_FAIL\fR
+The request failed.
+.PP
+The recipient status is one of:
+.IP \fBDEL_RCPT_STAT_OK\fR
+The address is deliverable.
+.IP \fBDEL_RCPT_STAT_DEFER\fR
+The address is undeliverable due to a temporary problem.
+.IP \fBDEL_RCPT_STAT_BOUNCE\fR
+The address is undeliverable due to a permanent problem.
+.IP \fBDEL_RCPT_STAT_TODO\fR
+The address status is being determined.
+.SH SECURITY
+.na
+.nf
+.ad
+.fi
+The address verification server is not security-sensitive. It does
+not talk to the network, and it does not talk to local users.
+The verify server can run chrooted at fixed low privilege.
+
+The address verification server can be coerced to store
+unlimited amounts of garbage. Limiting the cache size
+trades one problem (disk space exhaustion) for another
+one (poor response time to client requests).
+.SH DIAGNOSTICS
+.ad
+.fi
+Problems and transactions are logged to \fBsyslogd\fR(8).
+.SH BUGS
+.ad
+.fi
+This prototype server uses synchronous submission for sending
+a probe message, which can be slow on a busy machine.
+
+If the persistent database ever gets corrupted then the world
+comes to an end and human intervention is needed. This violates
+a basic Postfix principle.
+.SH CONFIGURATION PARAMETERS
+.na
+.nf
+.ad
+.fi
+See the Postfix \fBmain.cf\fR file for syntax details and for
+default values. Use the \fBpostfix reload\fR command after a
+configuration change.
+.IP \fBaddress_verify_map\fR
+Optional table for persistent recipient status storage. The file
+is opened before the process enters a chroot jail and before
+it drops root privileges.
+By default, the information is kept in volatile memory,
+and is lost after \fBpostfix reload\fR or \fBpostfix stop\fR.
+.sp
+To recover from a corrupted address verification database,
+delete the file and do \fBpostfix reload\fR.
+.IP \fBaddress_verify_sender\fR
+The sender address to use for probe messages. Specify an empty
+value (\fBaddress_verify_sender =\fR) or \fB<>\fR if you want
+to use the null sender address.
+.IP \fBaddress_verify_positive_expire_time\fR
+The amount of time after which a known to be good address expires.
+.IP \fBaddress_verify_positive_refresh_time\fR
+The minimal amount of time after which a proactive probe is sent to
+verify that a known to be good address is still good. The address
+status is not updated when the probe fails (optimistic caching).
+.IP \fBaddress_verify_negative_cache\fR
+A boolean parameter that controls whether negative probe results
+are stored in the address verification cache. When enabled, the
+cache may pollute quickly with garbage. When disabled, Postfix
+will generate an address probe for every lookup.
+.IP \fBaddress_verify_negative_expire_time\fR
+The amount of time after which a rejected address expires.
+.IP \fBaddress_verify_negative_refresh_time\fR
+The minimal amount of time after which a proactive probe is sent to
+verify that a known to be bad address is still bad.
+.SH SEE ALSO
+.na
+.nf
+verify_clnt(3) address verification client
+.SH LICENSE
+.na
+.nf
+.ad
+.fi
+The Secure Mailer license must be distributed with this software.
+.SH AUTHOR(S)
+.na
+.nf
+Wietse Venema
+IBM T.J. Watson Research
+P.O. Box 704
+Yorktown Heights, NY 10598, USA
rm -f $(CONFIG)
../conf/access: access
- ../mantools/srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@
+ srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@
../conf/aliases: aliases0 aliases
- (cat aliases0; ../mantools/srctoman - aliases | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /') >$@
+ (cat aliases0; srctoman - aliases | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /') >$@
../conf/canonical: canonical
- ../mantools/srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@
+ srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@
../conf/pcre_table: pcre_table
- ../mantools/srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@
+ srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@
../conf/regexp_table: regexp_table
- ../mantools/srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@
+ srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@
../conf/relocated: relocated
- ../mantools/srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@
+ srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@
../conf/transport: transport
- ../mantools/srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@
+ srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@
../conf/virtual: virtual
- ../mantools/srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@
+ srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@
SHELL = /bin/sh
SRCS = bounce.c bounce_append_service.c bounce_notify_service.c \
bounce_cleanup.c bounce_notify_util.c bounce_notify_verp.c \
- bounce_one_service.c
+ bounce_one_service.c bounce_warn_service.c bounce_trace_service.c
OBJS = bounce.o bounce_append_service.o bounce_notify_service.o \
bounce_cleanup.o bounce_notify_util.o bounce_notify_verp.o \
- bounce_one_service.o
+ bounce_one_service.o bounce_warn_service.o bounce_trace_service.o
HDRS =
TESTSRC =
WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \
bounce.o: ../../include/mail_params.h
bounce.o: ../../include/mail_conf.h
bounce.o: ../../include/bounce.h
+bounce.o: ../../include/deliver_request.h
+bounce.o: ../../include/recipient_list.h
bounce.o: ../../include/mail_addr.h
bounce.o: ../../include/mail_server.h
bounce.o: bounce_service.h
bounce_append_service.o: ../../include/vbuf.h
bounce_append_service.o: ../../include/vstream.h
bounce_append_service.o: ../../include/stringops.h
+bounce_append_service.o: ../../include/mail_params.h
bounce_append_service.o: ../../include/mail_queue.h
bounce_append_service.o: ../../include/quote_822_local.h
bounce_append_service.o: ../../include/quote_flags.h
bounce_append_service.o: ../../include/deliver_flock.h
bounce_append_service.o: ../../include/myflock.h
+bounce_append_service.o: ../../include/mail_proto.h
+bounce_append_service.o: ../../include/iostuff.h
+bounce_append_service.o: ../../include/attr.h
bounce_append_service.o: bounce_service.h
bounce_append_service.o: ../../include/bounce_log.h
bounce_cleanup.o: bounce_cleanup.c
bounce_one_service.o: bounce_service.h
bounce_one_service.o: ../../include/vstring.h
bounce_one_service.o: ../../include/bounce_log.h
+bounce_trace_service.o: bounce_trace_service.c
+bounce_trace_service.o: ../../include/sys_defs.h
+bounce_trace_service.o: ../../include/msg.h
+bounce_trace_service.o: ../../include/vstream.h
+bounce_trace_service.o: ../../include/vbuf.h
+bounce_trace_service.o: ../../include/mail_params.h
+bounce_trace_service.o: ../../include/mail_queue.h
+bounce_trace_service.o: ../../include/vstring.h
+bounce_trace_service.o: ../../include/post_mail.h
+bounce_trace_service.o: ../../include/cleanup_user.h
+bounce_trace_service.o: ../../include/mail_addr.h
+bounce_trace_service.o: ../../include/mail_error.h
+bounce_trace_service.o: ../../include/name_mask.h
+bounce_trace_service.o: bounce_service.h
+bounce_trace_service.o: ../../include/bounce_log.h
+bounce_warn_service.o: bounce_warn_service.c
+bounce_warn_service.o: ../../include/sys_defs.h
+bounce_warn_service.o: ../../include/msg.h
+bounce_warn_service.o: ../../include/vstream.h
+bounce_warn_service.o: ../../include/vbuf.h
+bounce_warn_service.o: ../../include/name_mask.h
+bounce_warn_service.o: ../../include/mail_params.h
+bounce_warn_service.o: ../../include/mail_queue.h
+bounce_warn_service.o: ../../include/vstring.h
+bounce_warn_service.o: ../../include/post_mail.h
+bounce_warn_service.o: ../../include/cleanup_user.h
+bounce_warn_service.o: ../../include/mail_addr.h
+bounce_warn_service.o: ../../include/mail_error.h
+bounce_warn_service.o: bounce_service.h
+bounce_warn_service.o: ../../include/bounce_log.h
/* non-delivery status information. Each log file is named after the
/* queue file that it corresponds to, and is kept in a queue subdirectory
/* named after the service name in the \fBmaster.cf\fR file (either
-/* \fBbounce\fR or \fBdefer\fR).
+/* \fBbounce\fR, \fBdefer\fR or \fBtrace\fR).
/* This program expects to be run from the \fBmaster\fR(8) process
/* manager.
/*
/* .IP \fBbounce_size_limit\fR
/* Limit the amount of original message context that is sent in
/* a non-delivery notification.
+/* .IP \fBbackwards_bounce_logfile_compatibility\fR
+/* Controls whether the logfile will be readable by old Postfix versions
+/* that used the ad-hoc logfile format of \fI<address>: text\fR.
/* .IP \fBmail_name\fR
/* Use this mail system name in the introductory text at the
/* start of a bounce message.
static VSTRING *encoding;
static VSTRING *sender;
static VSTRING *verp_delims;
+static VSTRING *dsn_status;
+static VSTRING *dsn_action;
static VSTRING *why;
#define STR vstring_str
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
ATTR_TYPE_STR, MAIL_ATTR_ORCPT, orig_rcpt,
ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient,
+ ATTR_TYPE_STR, MAIL_ATTR_STATUS, dsn_status,
+ ATTR_TYPE_STR, MAIL_ATTR_ACTION, dsn_action,
ATTR_TYPE_STR, MAIL_ATTR_WHY, why,
- ATTR_TYPE_END) != 5) {
+ ATTR_TYPE_END) != 7) {
msg_warn("malformed request");
return (-1);
}
return (-1);
}
if (msg_verbose)
- msg_info("bounce_append_proto: service=%s id=%s to=%s why=%s",
- service_name, STR(queue_id), STR(recipient), STR(why));
+ msg_info("bounce_append_proto: service=%s id=%s org_to=%s to=%s stat=%s act=%s why=%s",
+ service_name, STR(queue_id), STR(orig_rcpt),
+ STR(recipient), STR(dsn_status),
+ STR(dsn_action), STR(why));
/*
* On request by the client, set up a trap to delete the log file in case
* Execute the request.
*/
return (bounce_append_service(service_name, STR(queue_id),
- STR(recipient), STR(why)));
+ STR(orig_rcpt), STR(recipient),
+ STR(dsn_status), STR(dsn_action),
+ STR(why)));
}
/* bounce_notify_proto - bounce_notify server protocol */
-static int bounce_notify_proto(char *service_name, VSTREAM *client, int flush)
+static int bounce_notify_proto(char *service_name, VSTREAM *client,
+ int (*service) (char *, char *, char *, char *, char *))
{
int flags;
/*
* Execute the request.
*/
- return (bounce_notify_service(service_name, STR(queue_name),
- STR(queue_id), STR(encoding),
- STR(sender), flush));
+ return (service(service_name, STR(queue_name),
+ STR(queue_id), STR(encoding),
+ STR(sender)));
}
/* bounce_verp_proto - bounce_notify server protocol, VERP style */
-static int bounce_verp_proto(char *service_name, VSTREAM *client, int flush)
+static int bounce_verp_proto(char *service_name, VSTREAM *client)
{
char *myname = "bounce_verp_proto";
int flags;
msg_warn("request to send VERP-style notification of bounced mail");
return (bounce_notify_service(service_name, STR(queue_name),
STR(queue_id), STR(encoding),
- STR(sender), flush));
+ STR(sender)));
} else
return (bounce_notify_verp(service_name, STR(queue_name),
STR(queue_id), STR(encoding),
- STR(sender), STR(verp_delims), flush));
+ STR(sender), STR(verp_delims)));
}
/* bounce_one_proto - bounce_one server protocol */
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
ATTR_TYPE_STR, MAIL_ATTR_ORCPT, orig_rcpt,
ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient,
+ ATTR_TYPE_STR, MAIL_ATTR_STATUS, dsn_status,
+ ATTR_TYPE_STR, MAIL_ATTR_ACTION, dsn_status,
ATTR_TYPE_STR, MAIL_ATTR_WHY, why,
- ATTR_TYPE_END) != 8) {
+ ATTR_TYPE_END) != 9) {
msg_warn("malformed request");
return (-1);
}
return (-1);
}
if (msg_verbose)
- msg_info("bounce_one_proto: queue=%s id=%s encoding=%s sender=%s recipient=%s why=%s",
+ msg_info("bounce_one_proto: queue=%s id=%s encoding=%s sender=%s orig_to=%s to=%s stat=%s act=%s why=%s",
STR(queue_name), STR(queue_id), STR(encoding),
- STR(sender), STR(recipient), STR(why));
+ STR(sender), STR(orig_rcpt), STR(recipient),
+ STR(dsn_status), STR(dsn_action), STR(why));
/*
* Execute the request.
*/
return (bounce_one_service(STR(queue_name), STR(queue_id), STR(encoding),
- STR(sender), STR(recipient), STR(why)));
+ STR(sender), STR(orig_rcpt), STR(recipient),
+ STR(dsn_status), STR(dsn_action), STR(why)));
}
/* bounce_service - parse bounce command type and delegate */
msg_warn("malformed request");
status = -1;
} else if (command == BOUNCE_CMD_VERP) {
- status = bounce_verp_proto(service_name, client, REALLY_BOUNCE);
+ status = bounce_verp_proto(service_name, client);
} else if (command == BOUNCE_CMD_FLUSH) {
- status = bounce_notify_proto(service_name, client, REALLY_BOUNCE);
+ status = bounce_notify_proto(service_name, client,
+ bounce_notify_service);
} else if (command == BOUNCE_CMD_WARN) {
- status = bounce_notify_proto(service_name, client, JUST_WARN);
+ status = bounce_notify_proto(service_name, client,
+ bounce_warn_service);
+ } else if (command == BOUNCE_CMD_TRACE) {
+ status = bounce_notify_proto(service_name, client,
+ bounce_trace_service);
} else if (command == BOUNCE_CMD_APPEND) {
status = bounce_append_proto(service_name, client);
} else if (command == BOUNCE_CMD_ONE) {
encoding = vstring_alloc(10);
sender = vstring_alloc(10);
verp_delims = vstring_alloc(10);
+ dsn_status = vstring_alloc(10);
+ dsn_action = vstring_alloc(10);
why = vstring_alloc(10);
}
/* SYNOPSIS
/* #include "bounce_service.h"
/*
-/* int bounce_append_service(queue_id, recipient, why)
+/* int bounce_append_service(queue_id, orig_rcpt, recipient,
+/* status, action, why)
/* char *queue_id;
+/* char *orig_rcpt;
/* char *recipient;
+/* char *status;
+/* char *action;
/* char *why;
/* DESCRIPTION
/* This module implements the server side of the bounce_append()
#include <ctype.h>
#include <string.h>
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
/* Utility library. */
#include <msg.h>
/* Global library. */
+#include <mail_params.h>
#include <mail_queue.h>
#include <quote_822_local.h>
#include <deliver_flock.h>
+#include <mail_proto.h>
/* Application-specific. */
/* bounce_append_service - append bounce log */
int bounce_append_service(char *service, char *queue_id,
- char *recipient, char *why)
+ char *orig_rcpt, char *recipient,
+ char *status, char *action,
+ char *why)
{
VSTRING *in_buf = vstring_alloc(100);
VSTRING *out_buf = vstring_alloc(100);
* may change once we replace the present ad-hoc bounce/defer logfile
* format by one that is transparent for control etc. characters. See
* also: showq/showq.c.
+ *
+ * While migrating from old format to new format, allow backwards
+ * compatibility by writing an old-style record before the new-style
+ * records.
*/
if ((orig_length = vstream_fseek(log, 0L, SEEK_END)) < 0)
msg_fatal("seek file %s %s: %m", service, queue_id);
- if (*recipient)
- vstream_fprintf(log, "<%s>: ",
- printable(vstring_str(quote_822_local(in_buf, recipient)), '?'));
- else
- vstream_fprintf(log, "<>: ");
- vstream_fputs(printable(why, '?'), log);
- vstream_fputs("\n\n", log);
+ vstream_fputs("\n", log);
+ if (var_oldlog_compat) {
+ vstream_fprintf(log, "<%s>: %s\n", *recipient == 0 ? "" :
+ printable(vstring_str(quote_822_local(in_buf, recipient)), '?'),
+ printable(why, '?'));
+ }
+ vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_RECIP, *recipient ?
+ printable(vstring_str(quote_822_local(in_buf, recipient)), '?') :
+ "<>");
+ if (strcasecmp(recipient, orig_rcpt) != 0)
+ vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_ORCPT, *orig_rcpt ?
+ printable(vstring_str(quote_822_local(in_buf, orig_rcpt)), '?') :
+ "<>");
+ vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_STATUS, printable(status, '?'));
+ vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_ACTION, printable(action, '?'));
+ vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_WHY, printable(why, '?'));
+ vstream_fputs("\n", log);
if (vstream_fflush(log) != 0 || fsync(vstream_fileno(log)) < 0) {
#ifndef NO_TRUNCATE
/* #include "bounce_service.h"
/*
/* int bounce_notify_service(queue_name, queue_id, encoding,
-/* sender, flush)
+/* sender)
/* char *queue_name;
/* char *queue_id;
/* char *encoding;
/* int flush;
/* DESCRIPTION
/* This module implements the server side of the bounce_notify()
-/* (send bounce message) request. If flush is zero, the logfile
-/* is not removed, and a warning is sent instead of a bounce.
+/* (send bounce message) request. The logfile is removed after a
+/* warning is posted.
/*
/* When a message bounces, a full copy is sent to the originator,
/* and an optional copy of the diagnostics with message headers is
int bounce_notify_service(char *service, char *queue_name,
char *queue_id, char *encoding,
- char *recipient, int flush)
+ char *recipient)
{
BOUNCE_INFO *bounce_info;
int bounce_status = 1;
* Initialize. Open queue file, bounce log, etc.
*/
bounce_info = bounce_mail_init(service, queue_name, queue_id,
- encoding, flush);
+ encoding, BOUNCE_MSG_FAIL);
#define NULL_SENDER MAIL_ADDR_EMPTY /* special address */
#define NULL_CLEANUP_FLAGS 0
+#define NULL_TRACE_FLAGS 0
#define BOUNCE_HEADERS 1
#define BOUNCE_ALL 0
* Single bounce failed. Optionally send a double bounce to postmaster.
*/
#define ANY_BOUNCE (MAIL_ERROR_2BOUNCE | MAIL_ERROR_BOUNCE)
-#define SKIP_IF_BOUNCE (flush == 1 && (notify_mask & ANY_BOUNCE) == 0)
-#define SKIP_IF_DELAY (flush == 0 && (notify_mask & MAIL_ERROR_DELAY) == 0)
+#define SKIP_IF_BOUNCE ((notify_mask & ANY_BOUNCE) == 0)
else if (*recipient == 0) {
- if (SKIP_IF_BOUNCE || SKIP_IF_DELAY) {
+ if (SKIP_IF_BOUNCE) {
bounce_status = 0;
} else {
- postmaster = flush ? var_2bounce_rcpt : var_delay_rcpt;
+ postmaster = var_2bounce_rcpt;
if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(),
postmaster,
- NULL_CLEANUP_FLAGS)) != 0) {
+ NULL_CLEANUP_FLAGS,
+ NULL_TRACE_FLAGS)) != 0) {
/*
* Double bounce to Postmaster. This is the last opportunity
&& bounce_diagnostic_log(bounce, bounce_info) == 0
&& bounce_header_dsn(bounce, bounce_info) == 0
&& bounce_diagnostic_dsn(bounce, bounce_info) == 0)
- bounce_original(bounce, bounce_info, flush ?
- BOUNCE_ALL : BOUNCE_HEADERS);
+ bounce_original(bounce, bounce_info, BOUNCE_ALL);
bounce_status = post_mail_fclose(bounce);
}
}
*/
else {
if ((bounce = post_mail_fopen_nowait(NULL_SENDER, recipient,
- NULL_CLEANUP_FLAGS)) != 0) {
+ NULL_CLEANUP_FLAGS,
+ NULL_TRACE_FLAGS)) != 0) {
/*
* Send the bounce message header, some boilerplate text that
&& bounce_diagnostic_log(bounce, bounce_info) == 0
&& bounce_header_dsn(bounce, bounce_info) == 0
&& bounce_diagnostic_dsn(bounce, bounce_info) == 0)
- bounce_original(bounce, bounce_info, flush ?
- BOUNCE_ALL : BOUNCE_HEADERS);
+ bounce_original(bounce, bounce_info, BOUNCE_ALL);
bounce_status = post_mail_fclose(bounce);
}
* This postmaster notice is not critical, so if it fails don't
* retransmit the bounce that we just generated, just log a warning.
*/
-#define WANT_IF_BOUNCE (flush == 1 && (notify_mask & MAIL_ERROR_BOUNCE))
-#define WANT_IF_DELAY (flush == 0 && (notify_mask & MAIL_ERROR_DELAY))
+#define WANT_IF_BOUNCE ((notify_mask & MAIL_ERROR_BOUNCE))
- if (bounce_status == 0 && (WANT_IF_BOUNCE || WANT_IF_DELAY)
+ if (bounce_status == 0 && (WANT_IF_BOUNCE)
&& strcasecmp(recipient, mail_addr_double_bounce()) != 0) {
/*
* don't retransmit the bounce that we just generated, just log a
* warning.
*/
- postmaster = flush ? var_bounce_rcpt : var_delay_rcpt;
+ postmaster = var_bounce_rcpt;
if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(),
postmaster,
- NULL_CLEANUP_FLAGS)) != 0) {
+ NULL_CLEANUP_FLAGS,
+ NULL_TRACE_FLAGS)) != 0) {
if (bounce_header(bounce, bounce_info, postmaster) == 0
&& bounce_diagnostic_log(bounce, bounce_info) == 0
&& bounce_header_dsn(bounce, bounce_info) == 0
* the bounce was posted successfully, and only if we are bouncing for
* real, not just warning.
*/
- if (flush != 0 && bounce_status == 0 && mail_queue_remove(service, queue_id)
+ if (bounce_status == 0 && mail_queue_remove(service, queue_id)
&& errno != ENOENT)
msg_fatal("remove %s %s: %m", service, queue_id);
/* int flush;
/*
/* BOUNCE_INFO *bounce_mail_one_init(queue_name, queue_id,
-/* encoding, orig_recipient, why)
+/* encoding, orig_recipient,
+/* recipient, status, why)
/* const char *queue_name;
/* const char *queue_id;
/* const char *encoding;
/* const char *orig_recipient;
+/* const char *recipient;
+/* const char *status;
/* const char *why;
/*
/* void bounce_mail_free(bounce_info)
/* bounce_mail_alloc - initialize */
static BOUNCE_INFO *bounce_mail_alloc(const char *service,
- const char *queue_name,
- const char *queue_id,
- const char *encoding,
- int flush,
- BOUNCE_LOG *log_handle)
+ const char *queue_name,
+ const char *queue_id,
+ const char *encoding,
+ int flush,
+ BOUNCE_LOG *log_handle)
{
BOUNCE_INFO *bounce_info;
int rec_type;
const char *queue_id,
const char *encoding,
const char *orig_recipient,
+ const char *recipient,
+ const char *dsn_status,
+ const char *dsn_action,
const char *why)
{
BOUNCE_INFO *bounce_info;
*/
#define REALLY_BOUNCE 1
- log_handle = bounce_log_forge(orig_recipient, "5.0.0", why);
+ log_handle = bounce_log_forge(orig_recipient, recipient, dsn_status,
+ dsn_action, why);
bounce_info = bounce_mail_alloc("none", queue_name, queue_id,
encoding, REALLY_BOUNCE, log_handle);
return (bounce_info);
/*
* Non-delivery subject line.
*/
- if (bounce_info->flush) {
+ if (bounce_info->flush == BOUNCE_MSG_FAIL) {
post_mail_fputs(bounce, dest == var_bounce_rcpt
|| dest == var_2bounce_rcpt || dest == var_delay_rcpt ?
"Subject: Postmaster Copy: Undelivered Mail" :
/*
* Delayed mail subject line.
*/
- else {
+ else if (bounce_info->flush == BOUNCE_MSG_WARN) {
post_mail_fputs(bounce, dest == var_bounce_rcpt
|| dest == var_2bounce_rcpt || dest == var_delay_rcpt ?
"Subject: Postmaster Warning: Delayed Mail" :
"Subject: Delayed Mail (still being retried)");
}
+
+ /*
+ * Address verification or delivery report.
+ */
+ else {
+ post_mail_fputs(bounce, "Subject: Mail Delivery Status Report");
+ }
+
post_mail_fprintf(bounce, "To: %s",
STR(quote_822_local(bounce_info->buf, dest)));
* word wrapping to make the text look nicer. No matter how hard we would
* try, receiving bounced mail will always suck.
*/
+#define UNDELIVERED(flush) \
+ ((flush) == BOUNCE_MSG_FAIL || (flush) == BOUNCE_MSG_WARN)
+
post_mail_fprintf(bounce, "This is the %s program at host %s.",
var_mail_name, var_myhostname);
post_mail_fputs(bounce, "");
- if (bounce_info->flush) {
+ if (bounce_info->flush == BOUNCE_MSG_FAIL) {
post_mail_fputs(bounce,
"I'm sorry to have to inform you that the message returned");
post_mail_fputs(bounce,
"below could not be delivered to one or more destinations.");
- } else {
+ } else if (bounce_info->flush == BOUNCE_MSG_WARN) {
post_mail_fputs(bounce,
"####################################################################");
post_mail_fputs(bounce,
post_mail_fprintf(bounce,
"It will be retried until it is %.1f days old.",
var_max_queue_time / 86400.0);
+ } else {
+ post_mail_fputs(bounce,
+ "Enclosed is the mail delivery report that you requested.");
}
-
- post_mail_fputs(bounce, "");
- post_mail_fprintf(bounce,
- "For further assistance, please send mail to <%s>",
- MAIL_ADDR_POSTMASTER);
- if (bounce_info->flush) {
+ if (UNDELIVERED(bounce_info->flush)) {
+ post_mail_fputs(bounce, "");
+ post_mail_fprintf(bounce,
+ "For further assistance, please send mail to <%s>",
+ MAIL_ADDR_POSTMASTER);
post_mail_fputs(bounce, "");
post_mail_fprintf(bounce,
"If you do so, please include this problem report. You can");
post_mail_fputs(bounce, "");
post_mail_fprintf(bounce, "--%s", bounce_info->mime_boundary);
post_mail_fprintf(bounce, "Content-Description: %s",
- "Delivery error report");
+ "Delivery report");
post_mail_fprintf(bounce, "Content-Type: %s", "message/delivery-status");
/*
int bounce_recipient_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
{
post_mail_fputs(bounce, "");
-#if 0
- post_mail_fprintf(bounce, "Original-Recipient: rfc822; %s", "whatever");
-#endif
post_mail_fprintf(bounce, "Final-Recipient: rfc822; %s",
bounce_info->log_handle->recipient);
- post_mail_fprintf(bounce, "Action: %s", bounce_info->flush ?
- "failed" : "delayed");
- post_mail_fprintf(bounce, "Status: %s", bounce_info->log_handle->status);
+ if (bounce_info->log_handle->orig_rcpt)
+ post_mail_fprintf(bounce, "Original-Recipient: rfc822; %s",
+ bounce_info->log_handle->orig_rcpt);
+ post_mail_fprintf(bounce, "Action: %s",
+ bounce_info->flush == BOUNCE_MSG_FAIL ?
+ "failed" : bounce_info->log_handle->dsn_action);
+ post_mail_fprintf(bounce, "Status: %s",
+ bounce_info->log_handle->dsn_status);
bounce_print_wrap(bounce, bounce_info, "Diagnostic-Code: X-Postfix; %s",
bounce_info->log_handle->text);
#if 0
post_mail_fprintf(bounce, "Last-Attempt-Date: %s",
bounce_info->log_handle->log_time);
#endif
- if (bounce_info->flush == 0)
+ if (bounce_info->flush == BOUNCE_MSG_WARN)
post_mail_fprintf(bounce, "Will-Retry-Until: %s",
mail_date(bounce_info->arrival_time + var_max_queue_time));
return (vstream_ferror(bounce));
*/
post_mail_fputs(bounce, "");
post_mail_fprintf(bounce, "--%s", bounce_info->mime_boundary);
- post_mail_fprintf(bounce, "Content-Description: %s", headers_only ?
- "Undelivered Message Headers" : "Undelivered Message");
+ post_mail_fprintf(bounce, "Content-Description: %s%s",
+ UNDELIVERED(bounce_info->flush) ? "Undelivered " : "",
+ headers_only ? "Message Headers" : "Message");
post_mail_fprintf(bounce, "Content-Type: %s", headers_only ?
"text/rfc822-headers" : "message/rfc822");
if (bounce_info->mime_encoding)
/* #include "bounce_service.h"
/*
/* int bounce_notify_verp(service, queue_name, queue_id, sender,
-/* verp_delims, flush)
+/* verp_delims)
/* char *queue_name;
/* char *queue_id;
/* char *sender;
/* int flush;
/* DESCRIPTION
/* This module implements the server side of the bounce_notify()
-/* (send bounce message) request. If flush is zero, the logfile
-/* is not removed, and a warning is sent instead of a bounce.
+/* (send bounce message) request. The logfile
+/* is removed after and a warning is posted.
/* The bounce recipient address is encoded in VERP format.
/* This routine must be used for single bounces only.
/*
int bounce_notify_verp(char *service, char *queue_name,
char *queue_id, char *encoding,
- char *recipient,
- char *verp_delims, int flush)
+ char *recipient,
+ char *verp_delims)
{
char *myname = "bounce_notify_verp";
BOUNCE_INFO *bounce_info;
* Initialize. Open queue file, bounce log, etc.
*/
bounce_info = bounce_mail_init(service, queue_name, queue_id,
- encoding, flush);
+ encoding, BOUNCE_MSG_FAIL);
#define NULL_SENDER MAIL_ADDR_EMPTY /* special address */
#define NULL_CLEANUP_FLAGS 0
+#define NULL_TRACE_FLAGS 0
#define BOUNCE_HEADERS 1
#define BOUNCE_ALL 0
verp_sender(verp_buf, verp_delims, recipient,
bounce_info->log_handle->recipient);
if ((bounce = post_mail_fopen_nowait(NULL_SENDER, STR(verp_buf),
- NULL_CLEANUP_FLAGS)) != 0) {
+ NULL_CLEANUP_FLAGS,
+ NULL_TRACE_FLAGS)) != 0) {
/*
* Send the bounce message header, some boilerplate text that
&& bounce_recipient_log(bounce, bounce_info) == 0
&& bounce_header_dsn(bounce, bounce_info) == 0
&& bounce_recipient_dsn(bounce, bounce_info) == 0)
- bounce_original(bounce, bounce_info, flush ?
- BOUNCE_ALL : BOUNCE_HEADERS);
+ bounce_original(bounce, bounce_info, BOUNCE_ALL);
bounce_status = post_mail_fclose(bounce);
} else
bounce_status = 1;
* This postmaster notice is not critical, so if it fails don't
* retransmit the bounce that we just generated, just log a warning.
*/
-#define WANT_IF_BOUNCE (flush == 1 && (notify_mask & MAIL_ERROR_BOUNCE))
-#define WANT_IF_DELAY (flush == 0 && (notify_mask & MAIL_ERROR_DELAY))
+#define WANT_IF_BOUNCE ((notify_mask & MAIL_ERROR_BOUNCE))
- if (WANT_IF_BOUNCE || WANT_IF_DELAY) {
+ if (WANT_IF_BOUNCE) {
/*
* Send the text with reason for the bounce, and the headers of
* don't retransmit the bounce that we just generated, just log a
* warning.
*/
- postmaster = flush ? var_bounce_rcpt : var_delay_rcpt;
+ postmaster = var_bounce_rcpt;
if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(),
postmaster,
- NULL_CLEANUP_FLAGS)) != 0) {
+ NULL_CLEANUP_FLAGS,
+ NULL_TRACE_FLAGS)) != 0) {
if (bounce_header(bounce, bounce_info, postmaster) == 0
&& bounce_recipient_log(bounce, bounce_info) == 0
&& bounce_header_dsn(bounce, bounce_info) == 0
* the bounce was posted successfully, and only if we are bouncing for
* real, not just warning.
*/
- if (flush != 0 && bounce_status == 0 && mail_queue_remove(service, queue_id)
+ if (bounce_status == 0 && mail_queue_remove(service, queue_id)
&& errno != ENOENT)
msg_fatal("remove %s %s: %m", service, queue_id);
/* #include "bounce_service.h"
/*
/* int bounce_one_service(queue_name, queue_id, encoding,
-/* orig_sender, orig_recipient, why)
+/* orig_sender, orig_recipient,
+/* status, why)
/* char *queue_name;
/* char *queue_id;
/* char *encoding;
/* char *orig_sender;
/* char *orig_recipient;
+/* char *status;
/* char *why;
/* DESCRIPTION
/* This module implements the server side of the bounce_one()
int bounce_one_service(char *queue_name, char *queue_id, char *encoding,
char *orig_sender, char *orig_recipient,
- char *why)
+ char *recipient, char *dsn_status,
+ char *dsn_action, char *why)
{
BOUNCE_INFO *bounce_info;
int bounce_status = 1;
* Initialize. Open queue file, bounce log, etc.
*/
bounce_info = bounce_mail_one_init(queue_name, queue_id,
- encoding, orig_recipient, why);
+ encoding, orig_recipient,
+ recipient, dsn_status,
+ dsn_action, why);
#define NULL_SENDER MAIL_ADDR_EMPTY /* special address */
#define NULL_CLEANUP_FLAGS 0
+#define NULL_TRACE_FLAGS 0
#define BOUNCE_HEADERS 1
#define BOUNCE_ALL 0
} else {
if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(),
var_2bounce_rcpt,
- NULL_CLEANUP_FLAGS)) != 0) {
+ NULL_CLEANUP_FLAGS,
+ NULL_TRACE_FLAGS)) != 0) {
/*
* Double bounce to Postmaster. This is the last opportunity
*/
else {
if ((bounce = post_mail_fopen_nowait(NULL_SENDER, orig_sender,
- NULL_CLEANUP_FLAGS)) != 0) {
+ NULL_CLEANUP_FLAGS,
+ NULL_TRACE_FLAGS)) != 0) {
/*
* Send the bounce message header, some boilerplate text that
*/
if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(),
var_bounce_rcpt,
- NULL_CLEANUP_FLAGS)) != 0) {
+ NULL_CLEANUP_FLAGS,
+ NULL_TRACE_FLAGS)) != 0) {
if (bounce_header(bounce, bounce_info, var_bounce_rcpt) == 0
&& bounce_recipient_log(bounce, bounce_info) == 0
&& bounce_header_dsn(bounce, bounce_info) == 0
/*
* bounce_append_service.c
*/
-extern int bounce_append_service(char *, char *, char *, char *);
+extern int bounce_append_service(char *, char *, char *, char *, char *, char *, char *);
/*
* bounce_notify_service.c
*/
-extern int bounce_notify_service(char *, char *, char *, char *, char *, int);
+extern int bounce_notify_service(char *, char *, char *, char *, char *);
+
+ /*
+ * bounce_warn_service.c
+ */
+extern int bounce_warn_service(char *, char *, char *, char *, char *);
+
+ /*
+ * bounce_trace_service.c
+ */
+extern int bounce_trace_service(char *, char *, char *, char *, char *);
/*
* bounce_notify_verp.c
*/
-extern int bounce_notify_verp(char *, char *, char *, char *, char *, char *, int);
+extern int bounce_notify_verp(char *, char *, char *, char *, char *, char *);
/*
* bounce_one_service.c
*/
-extern int bounce_one_service(char *, char *, char *, char *, char *, char *);
+extern int bounce_one_service(char *, char *, char *, char *, char *, char *, char *, char *, char *);
/*
* bounce_cleanup.c
} BOUNCE_INFO;
extern BOUNCE_INFO *bounce_mail_init(const char *, const char *, const char *, const char *, int);
-extern BOUNCE_INFO *bounce_mail_one_init(const char *, const char *, const char *, const char *, const char *);
+extern BOUNCE_INFO *bounce_mail_one_init(const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *);
extern void bounce_mail_free(BOUNCE_INFO *);
extern int bounce_header(VSTREAM *, BOUNCE_INFO *, const char *);
extern int bounce_boilerplate(VSTREAM *, BOUNCE_INFO *);
extern int bounce_diagnostic_dsn(VSTREAM *, BOUNCE_INFO *);
extern int bounce_original(VSTREAM *, BOUNCE_INFO *, int);
+#define BOUNCE_MSG_FAIL 0
+#define BOUNCE_MSG_WARN 1
+#define BOUNCE_MSG_STATUS 2
+
/* LICENSE
/* .ad
/* .fi
--- /dev/null
+/*++
+/* NAME
+/* bounce_trace_service 3
+/* SUMMARY
+/* send status report to sender, server side
+/* SYNOPSIS
+/* #include "bounce_service.h"
+/*
+/* int bounce_trace_service(queue_name, queue_id, encoding, sender)
+/* char *queue_name;
+/* char *queue_id;
+/* char *encoding;
+/* char *sender;
+/* DESCRIPTION
+/* This module implements the server side of the trace_flush()
+/* (send delivery notice) request. The logfile
+/* is removed after the notice is posted.
+/*
+/* A status report includes a prelude with human-readable text,
+/* a DSN-style report, and the email message that was subject of
+/* the status report.
+/*
+/* When a status report is sent, the sender address is the empty
+/* address.
+/* DIAGNOSTICS
+/* Fatal error: error opening existing file. Warnings: corrupt
+/* message file. A corrupt message is saved to the "corrupt"
+/* queue for further inspection.
+/* BUGS
+/* SEE ALSO
+/* bounce(3) basic bounce service client interface
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
+/* Utility library. */
+
+#include <msg.h>
+#include <vstream.h>
+
+/* Global library. */
+
+#include <mail_params.h>
+#include <mail_queue.h>
+#include <post_mail.h>
+#include <mail_addr.h>
+#include <mail_error.h>
+
+/* Application-specific. */
+
+#include "bounce_service.h"
+
+#define STR vstring_str
+
+/* bounce_trace_service - send a delivery status notice */
+
+int bounce_trace_service(char *service, char *queue_name,
+ char *queue_id, char *encoding,
+ char *recipient)
+{
+ BOUNCE_INFO *bounce_info;
+ int bounce_status = 1;
+ VSTREAM *bounce;
+
+ /*
+ * Initialize. Open queue file, bounce log, etc.
+ */
+ bounce_info = bounce_mail_init(service, queue_name, queue_id,
+ encoding, BOUNCE_MSG_STATUS);
+
+#define NULL_SENDER MAIL_ADDR_EMPTY /* special address */
+#define NULL_CLEANUP_FLAGS 0
+#define NULL_TRACE_FLAGS 0
+#define BOUNCE_ALL 0
+
+ /*
+ * Send a single bounce with a template message header, some boilerplate
+ * text that pretends that we are a polite mail system, the text with
+ * per-recipient status, and a copy of the original message.
+ */
+ if ((bounce = post_mail_fopen_nowait(NULL_SENDER, recipient,
+ NULL_CLEANUP_FLAGS,
+ NULL_TRACE_FLAGS)) != 0) {
+ if (bounce_header(bounce, bounce_info, recipient) == 0
+ && bounce_boilerplate(bounce, bounce_info) == 0
+ && bounce_diagnostic_log(bounce, bounce_info) == 0
+ && bounce_header_dsn(bounce, bounce_info) == 0
+ && bounce_diagnostic_dsn(bounce, bounce_info) == 0)
+ bounce_original(bounce, bounce_info, BOUNCE_ALL);
+ bounce_status = post_mail_fclose(bounce);
+ }
+
+ /*
+ * Examine the completion status. Delete the trace log file only when the
+ * status notice was posted successfully.
+ */
+ if (bounce_status == 0 && mail_queue_remove(service, queue_id)
+ && errno != ENOENT)
+ msg_fatal("remove %s %s: %m", service, queue_id);
+
+ /*
+ * Cleanup.
+ */
+ bounce_mail_free(bounce_info);
+
+ return (bounce_status);
+}
--- /dev/null
+/*++
+/* NAME
+/* bounce_warn_service 3
+/* SUMMARY
+/* send non-delivery report to sender, server side
+/* SYNOPSIS
+/* #include "bounce_service.h"
+/*
+/* int bounce_warn_service(queue_name, queue_id, encoding, sender)
+/* char *queue_name;
+/* char *queue_id;
+/* char *encoding;
+/* char *sender;
+/* DESCRIPTION
+/* This module implements the server side of the bounce_warn()
+/* (send delay notice) request. The logfile
+/* is not removed, and a warning is sent instead of a bounce.
+/*
+/* When a message bounces, a full copy is sent to the originator,
+/* and an optional copy of the diagnostics with message headers is
+/* sent to the postmaster. The result is non-zero when the operation
+/* should be tried again.
+/*
+/* When a bounce is sent, the sender address is the empty
+/* address. When a bounce bounces, an optional double bounce
+/* with the entire undeliverable mail is sent to the postmaster,
+/* with as sender address the double bounce address.
+/* DIAGNOSTICS
+/* Fatal error: error opening existing file. Warnings: corrupt
+/* message file. A corrupt message is saved to the "corrupt"
+/* queue for further inspection.
+/* BUGS
+/* SEE ALSO
+/* bounce(3) basic bounce service client interface
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
+/* Utility library. */
+
+#include <msg.h>
+#include <vstream.h>
+#include <name_mask.h>
+
+/* Global library. */
+
+#include <mail_params.h>
+#include <mail_queue.h>
+#include <post_mail.h>
+#include <mail_addr.h>
+#include <mail_error.h>
+
+/* Application-specific. */
+
+#include "bounce_service.h"
+
+#define STR vstring_str
+
+/* bounce_warn_service - send a delayed mail notice */
+
+int bounce_warn_service(char *service, char *queue_name,
+ char *queue_id, char *encoding,
+ char *recipient)
+{
+ BOUNCE_INFO *bounce_info;
+ int bounce_status = 1;
+ int postmaster_status = 1;
+ VSTREAM *bounce;
+ int notify_mask = name_mask(VAR_NOTIFY_CLASSES, mail_error_masks,
+ var_notify_classes);
+ char *postmaster;
+
+ /*
+ * Initialize. Open queue file, bounce log, etc.
+ */
+ bounce_info = bounce_mail_init(service, queue_name, queue_id,
+ encoding, BOUNCE_MSG_WARN);
+
+#define NULL_SENDER MAIL_ADDR_EMPTY /* special address */
+#define NULL_CLEANUP_FLAGS 0
+#define NULL_TRACE_FLAGS 0
+#define BOUNCE_HEADERS 1
+
+ /*
+ * The choice of sender address depends on the recipient address. For a
+ * single bounce (a non-delivery notification to the message originator),
+ * the sender address is the empty string. For a double bounce (typically
+ * a failed single bounce, or a postmaster notification that was produced
+ * by any of the mail processes) the sender address is defined by the
+ * var_double_bounce_sender configuration variable. When a double bounce
+ * cannot be delivered, the queue manager blackholes the resulting triple
+ * bounce message.
+ */
+
+ /*
+ * Double bounce failed. Never send a triple bounce.
+ *
+ * However, this does not prevent double bounces from bouncing on other
+ * systems. In order to cope with this, either the queue manager must
+ * recognize the double-bounce recipient address and discard mail, or
+ * every delivery agent must recognize the double-bounce sender address
+ * and substitute something else so mail does not come back at us.
+ */
+ if (strcasecmp(recipient, mail_addr_double_bounce()) == 0) {
+ msg_warn("%s: undeliverable postmaster notification discarded",
+ queue_id);
+ bounce_status = 0;
+ }
+
+ /*
+ * Single bounce failed. Optionally send a double bounce to postmaster.
+ */
+#define ANY_BOUNCE (MAIL_ERROR_2BOUNCE | MAIL_ERROR_BOUNCE)
+#define SKIP_IF_DELAY ((notify_mask & MAIL_ERROR_DELAY) == 0)
+
+ else if (*recipient == 0) {
+ if (SKIP_IF_DELAY) {
+ bounce_status = 0;
+ } else {
+ postmaster = var_delay_rcpt;
+ if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(),
+ postmaster,
+ NULL_CLEANUP_FLAGS,
+ NULL_TRACE_FLAGS)) != 0) {
+
+ /*
+ * Double bounce to Postmaster. This is the last opportunity
+ * for this message to be delivered. Send the text with
+ * reason for the bounce, and the headers of the original
+ * message. Don't bother sending the boiler-plate text.
+ */
+ if (!bounce_header(bounce, bounce_info, postmaster)
+ && bounce_diagnostic_log(bounce, bounce_info) == 0
+ && bounce_header_dsn(bounce, bounce_info) == 0
+ && bounce_diagnostic_dsn(bounce, bounce_info) == 0)
+ bounce_original(bounce, bounce_info, BOUNCE_HEADERS);
+ bounce_status = post_mail_fclose(bounce);
+ }
+ }
+ }
+
+ /*
+ * Non-bounce failed. Send a single bounce.
+ */
+ else {
+ if ((bounce = post_mail_fopen_nowait(NULL_SENDER, recipient,
+ NULL_CLEANUP_FLAGS,
+ NULL_TRACE_FLAGS)) != 0) {
+
+ /*
+ * Send the bounce message header, some boilerplate text that
+ * pretends that we are a polite mail system, the text with
+ * reason for the bounce, and a copy of the original message.
+ */
+ if (bounce_header(bounce, bounce_info, recipient) == 0
+ && bounce_boilerplate(bounce, bounce_info) == 0
+ && bounce_diagnostic_log(bounce, bounce_info) == 0
+ && bounce_header_dsn(bounce, bounce_info) == 0
+ && bounce_diagnostic_dsn(bounce, bounce_info) == 0)
+ bounce_original(bounce, bounce_info, BOUNCE_HEADERS);
+ bounce_status = post_mail_fclose(bounce);
+ }
+
+ /*
+ * Optionally, send a postmaster notice.
+ *
+ * This postmaster notice is not critical, so if it fails don't
+ * retransmit the bounce that we just generated, just log a warning.
+ */
+#define WANT_IF_DELAY ((notify_mask & MAIL_ERROR_DELAY))
+
+ if (bounce_status == 0 && WANT_IF_DELAY
+ && strcasecmp(recipient, mail_addr_double_bounce()) != 0) {
+
+ /*
+ * Send the text with reason for the bounce, and the headers of
+ * the original message. Don't bother sending the boiler-plate
+ * text. This postmaster notice is not critical, so if it fails
+ * don't retransmit the bounce that we just generated, just log a
+ * warning.
+ */
+ postmaster = var_delay_rcpt;
+ if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(),
+ postmaster,
+ NULL_CLEANUP_FLAGS,
+ NULL_TRACE_FLAGS)) != 0) {
+ if (bounce_header(bounce, bounce_info, postmaster) == 0
+ && bounce_diagnostic_log(bounce, bounce_info) == 0
+ && bounce_header_dsn(bounce, bounce_info) == 0
+ && bounce_diagnostic_dsn(bounce, bounce_info) == 0)
+ bounce_original(bounce, bounce_info, BOUNCE_HEADERS);
+ postmaster_status = post_mail_fclose(bounce);
+ }
+ if (postmaster_status)
+ msg_warn("postmaster notice failed while bouncing to %s",
+ recipient);
+ }
+ }
+
+ /*
+ * Cleanup.
+ */
+ bounce_mail_free(bounce_info);
+
+ return (bounce_status);
+}
cleanup_api.o: ../../include/iostuff.h
cleanup_api.o: ../../include/attr.h
cleanup_api.o: ../../include/bounce.h
+cleanup_api.o: ../../include/deliver_request.h
+cleanup_api.o: ../../include/recipient_list.h
cleanup_api.o: ../../include/mail_params.h
cleanup_api.o: ../../include/mail_stream.h
cleanup_api.o: ../../include/hold_message.h
/*
* Bounce all recipients.
*/
+#define BOUNCE_FLAGS(request) DEL_REQ_TRACE_FLAGS(request->flags)
+
for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
rcpt = request->rcpt_list.info + nrcpt;
if (rcpt->offset >= 0) {
- status = bounce_append(BOUNCE_FLAG_KEEP, request->queue_id,
+ status = bounce_append(BOUNCE_FLAGS(request), request->queue_id,
rcpt->orig_addr, rcpt->address, "none",
request->arrival_time,
"%s", request->nexthop);
tok822_resolve.c tok822_rewrite.c tok822_tree.c xtext.c bounce_log.c \
flush_clnt.c mail_conf_time.c mbox_conf.c mbox_open.c abounce.c \
verp_sender.c match_parent_style.c mime_state.c header_token.c \
- strip_addr.c virtual8_maps.c hold_message.c
+ strip_addr.c virtual8_maps.c hold_message.c verify_clnt.c \
+ trace.c log_adhoc.c verify.c
OBJS = been_here.o bounce.o canon_addr.o cleanup_strerror.o clnt_stream.o \
debug_peer.o debug_process.o defer.o deliver_completed.o \
deliver_flock.o deliver_pass.o deliver_request.o domain_list.o \
tok822_resolve.o tok822_rewrite.o tok822_tree.o xtext.o bounce_log.o \
flush_clnt.o mail_conf_time.o mbox_conf.o mbox_open.o abounce.o \
verp_sender.o match_parent_style.o mime_state.o header_token.o \
- strip_addr.o virtual8_maps.o hold_message.o
+ strip_addr.o virtual8_maps.o hold_message.o verify_clnt.o \
+ trace.o log_adhoc.o verify.o
HDRS = been_here.h bounce.h canon_addr.h cleanup_user.h clnt_stream.h \
config.h debug_peer.h debug_process.h defer.h deliver_completed.h \
deliver_flock.h deliver_pass.h deliver_request.h domain_list.h \
sys_exits.h timed_ipc.h tok822.h xtext.h bounce_log.h flush_clnt.h \
mbox_conf.h mbox_open.h abounce.h qmqp_proto.h verp_sender.h \
match_parent_style.h quote_flags.h mime_state.h header_token.h \
- lex_822.h strip_addr.h virtual8_maps.h hold_message.h
+ lex_822.h strip_addr.h virtual8_maps.h hold_message.h verify_clnt.h \
+ trace.h log_adhoc.h verify.h
TESTSRC = rec2stream.c stream2rec.c recdump.c
WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \
-Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \
off_cvt quote_822_local rec2stream recdump resolve_clnt \
resolve_local rewrite_clnt stream2rec string_list tok822_parse \
quote_821_local mail_conf_time mime_state strip_addr \
- virtual8_maps
+ virtual8_maps verify_clnt
LIBS = ../../lib/libutil.a
LIB_DIR = ../../lib
$(CC) -DTEST $(CFLAGS) -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
mv junk $@.o
+verify_clnt: $(LIB) $(LIBS)
+ mv $@.o junk
+ $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
+ mv junk $@.o
+
tests: tok822_test mime_test mime_nest mime_8bit mime_dom mime_trunc \
mime_cvt mime_cvt2 mime_cvt3 strip_addr_test tok822_limit_test \
virtual8_test
abounce.o: ../../include/attr.h
abounce.o: abounce.h
abounce.o: bounce.h
+abounce.o: deliver_request.h
+abounce.o: ../../include/vstring.h
+abounce.o: recipient_list.h
been_here.o: been_here.c
been_here.o: ../../include/sys_defs.h
been_here.o: ../../include/msg.h
bounce.o: ../../include/vstream.h
bounce.o: ../../include/iostuff.h
bounce.o: ../../include/attr.h
+bounce.o: log_adhoc.h
+bounce.o: verify.h
+bounce.o: deliver_request.h
+bounce.o: recipient_list.h
bounce.o: defer.h
bounce.o: bounce.h
+bounce.o: trace.h
bounce_log.o: bounce_log.c
bounce_log.o: ../../include/sys_defs.h
bounce_log.o: ../../include/msg.h
bounce_log.o: ../../include/vstring.h
bounce_log.o: ../../include/vstring_vstream.h
bounce_log.o: ../../include/stringops.h
+bounce_log.o: mail_params.h
+bounce_log.o: mail_proto.h
+bounce_log.o: ../../include/iostuff.h
+bounce_log.o: ../../include/attr.h
bounce_log.o: mail_queue.h
bounce_log.o: bounce_log.h
canon_addr.o: canon_addr.c
defer.o: ../../include/iostuff.h
defer.o: ../../include/attr.h
defer.o: flush_clnt.h
+defer.o: verify.h
+defer.o: deliver_request.h
+defer.o: recipient_list.h
+defer.o: log_adhoc.h
+defer.o: trace.h
defer.o: bounce.h
defer.o: defer.h
deliver_completed.o: deliver_completed.c
is_header.o: is_header.c
is_header.o: ../../include/sys_defs.h
is_header.o: is_header.h
+log_adhoc.o: log_adhoc.c
+log_adhoc.o: ../../include/sys_defs.h
+log_adhoc.o: ../../include/msg.h
+log_adhoc.o: ../../include/vstring.h
+log_adhoc.o: ../../include/vbuf.h
+log_adhoc.o: log_adhoc.h
mail_addr.o: mail_addr.c
mail_addr.o: ../../include/sys_defs.h
mail_addr.o: ../../include/stringops.h
post_mail.o: ../../include/vstream.h
post_mail.o: ../../include/vbuf.h
post_mail.o: ../../include/vstring.h
+post_mail.o: ../../include/mymalloc.h
+post_mail.o: ../../include/events.h
post_mail.o: mail_params.h
post_mail.o: record.h
post_mail.o: rec_type.h
sent.o: ../../include/msg.h
sent.o: ../../include/vstring.h
sent.o: ../../include/vbuf.h
+sent.o: mail_params.h
+sent.o: verify.h
+sent.o: deliver_request.h
+sent.o: ../../include/vstream.h
+sent.o: recipient_list.h
+sent.o: log_adhoc.h
+sent.o: trace.h
+sent.o: defer.h
+sent.o: bounce.h
sent.o: sent.h
smtp_stream.o: smtp_stream.c
smtp_stream.o: ../../include/sys_defs.h
tok822_tree.o: ../../include/vbuf.h
tok822_tree.o: tok822.h
tok822_tree.o: resolve_clnt.h
+trace.o: trace.c
+trace.o: ../../include/sys_defs.h
+trace.o: ../../include/msg.h
+trace.o: ../../include/vstring.h
+trace.o: ../../include/vbuf.h
+trace.o: mail_params.h
+trace.o: mail_proto.h
+trace.o: ../../include/vstream.h
+trace.o: ../../include/iostuff.h
+trace.o: ../../include/attr.h
+trace.o: verify_clnt.h
+trace.o: deliver_request.h
+trace.o: recipient_list.h
+trace.o: log_adhoc.h
+trace.o: bounce.h
+trace.o: trace.h
+verify.o: verify.c
+verify.o: ../../include/sys_defs.h
+verify.o: ../../include/msg.h
+verify.o: ../../include/vstring.h
+verify.o: ../../include/vbuf.h
+verify.o: mail_params.h
+verify.o: mail_proto.h
+verify.o: ../../include/vstream.h
+verify.o: ../../include/iostuff.h
+verify.o: ../../include/attr.h
+verify.o: verify_clnt.h
+verify.o: deliver_request.h
+verify.o: recipient_list.h
+verify.o: log_adhoc.h
+verify.o: verify.h
+verify_clnt.o: verify_clnt.c
+verify_clnt.o: ../../include/sys_defs.h
+verify_clnt.o: ../../include/msg.h
+verify_clnt.o: ../../include/vstream.h
+verify_clnt.o: ../../include/vbuf.h
+verify_clnt.o: ../../include/vstring.h
+verify_clnt.o: ../../include/attr.h
+verify_clnt.o: mail_params.h
+verify_clnt.o: mail_proto.h
+verify_clnt.o: ../../include/iostuff.h
+verify_clnt.o: clnt_stream.h
+verify_clnt.o: verify_clnt.h
+verify_clnt.o: deliver_request.h
+verify_clnt.o: recipient_list.h
verp_sender.o: verp_sender.c
verp_sender.o: ../../include/sys_defs.h
verp_sender.o: ../../include/vstring.h
/* records with recipients that were bounced, and the reason why.
/*
/* bounce_append() appends a reason for non-delivery to the
-/* bounce log for the named recipient.
+/* bounce log for the named recipient, updates the address
+/* verification service, or updates a message delivery record
+/* on request by the sender. The flags argument determines
+/* the action.
/*
/* vbounce_append() implements an alternative interface.
/*
/* .IP BOUNCE_FLAG_CLEAN
/* Delete the bounce log in case of an error (as in: pretend
/* that we never even tried to bounce this message).
+/* .IP DEL_REQ_FLAG_VERIFY
+/* The message is an address verification probe. Update the
+/* address verification database instead of bouncing mail.
+/* .IP DEL_REQ_FLAG_EXPAND
+/* The message is an address expansion probe. Update the
+/* message delivery record instead of bouncing mail.
+/* .IP DEL_REQ_FLAG_RECORD
+/* This is a normal message with logged delivery. Update the
+/* message delivery record and bounce the mail.
/* .RE
/* .IP queue
/* The message queue name of the original message file.
#include <sys_defs.h>
#include <stdlib.h> /* 44BSD stdarg.h uses abort() */
-#include <time.h>
#include <stdarg.h>
#include <string.h>
/* Global library. */
-#include "mail_params.h"
-#include "mail_proto.h"
-#include "defer.h"
-#include "bounce.h"
+#include <mail_params.h>
+#include <mail_proto.h>
+#include <log_adhoc.h>
+#include <verify.h>
+#include <defer.h>
+#include <trace.h>
+#include <bounce.h>
/* bounce_append - append reason to per-message bounce log */
const char *recipient, const char *relay,
time_t entry, const char *fmt, va_list ap)
{
- VSTRING *why;
int status;
- int delay;
/*
- * When we're pretending that we can't bounce, don't create a defer log
- * file when we wouldn't keep the bounce log file. That's a lot of
- * negatives in one sentence.
+ * MTA-requested address verification information is stored in the verify
+ * service database.
*/
- if (var_soft_bounce && (flags & BOUNCE_FLAG_CLEAN))
+ if (flags & DEL_REQ_FLAG_VERIFY) {
+ status = vverify_append(id, orig_rcpt, recipient, relay, entry,
+ "undeliverable", DEL_RCPT_STAT_BOUNCE, fmt, ap);
+ return (status);
+ }
+
+ /*
+ * User-requested address verification information is logged and mailed
+ * to the requesting user.
+ */
+ if (flags & DEL_REQ_FLAG_EXPAND) {
+ status = vtrace_append(flags, id, orig_rcpt, recipient, relay,
+ entry, "5.0.0", "undeliverable", fmt, ap);
+ return (status);
+ }
+
+ /*
+ * Normal (well almost) delivery. When we're pretending that we can't
+ * bounce, don't create a defer log file when we wouldn't keep the bounce
+ * log file. That's a lot of negatives in one sentence.
+ */
+ else if (var_soft_bounce && (flags & BOUNCE_FLAG_CLEAN)) {
return (-1);
+ }
- why = vstring_alloc(100);
- delay = time((time_t *) 0) - entry;
- vstring_vsprintf(why, fmt, ap);
- if (orig_rcpt == 0)
- orig_rcpt = "";
- if (mail_command_client(MAIL_CLASS_PRIVATE, var_soft_bounce ?
- var_defer_service : var_bounce_service,
- ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_APPEND,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
- ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
- ATTR_TYPE_STR, MAIL_ATTR_ORCPT, orig_rcpt,
- ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient,
- ATTR_TYPE_STR, MAIL_ATTR_WHY, vstring_str(why),
- ATTR_TYPE_END) == 0) {
- if (*orig_rcpt && strcasecmp(recipient, orig_rcpt) != 0)
- msg_info("%s: to=<%s>, orig_to=<%s>, relay=%s, delay=%d, status=%s (%s%s)",
- id, recipient, orig_rcpt, relay, delay,
- var_soft_bounce ? "deferred" : "bounced",
- var_soft_bounce ? "SOFT BOUNCE - " : "",
- vstring_str(why));
- else
- msg_info("%s: to=<%s>, relay=%s, delay=%d, status=%s (%s%s)",
- id, recipient, relay, delay,
- var_soft_bounce ? "deferred" : "bounced",
- var_soft_bounce ? "SOFT BOUNCE - " : "",
- vstring_str(why));
- status = (var_soft_bounce ? -1 : 0);
- } else if ((flags & BOUNCE_FLAG_CLEAN) == 0) {
- status = defer_append(flags, id, orig_rcpt, recipient, "bounce", entry,
- "bounce failed");
- } else {
- status = -1;
+ /*
+ * Normal mail delivery. May also send a delivery record to the user.
+ */
+ else {
+ VSTRING *why = vstring_alloc(100);
+ char *dsn_code = var_soft_bounce ? "4.0.0" : "5.0.0";
+ char *dsn_action = var_soft_bounce ? "delayed" : "failed";
+ char *log_status = var_soft_bounce ? "SOFTBOUNCE" : "bounced";
+
+ vstring_vsprintf(why, fmt, ap);
+ if (orig_rcpt == 0)
+ orig_rcpt = "";
+ if (mail_command_client(MAIL_CLASS_PRIVATE, var_soft_bounce ?
+ var_defer_service : var_bounce_service,
+ ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_APPEND,
+ ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+ ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
+ ATTR_TYPE_STR, MAIL_ATTR_ORCPT, orig_rcpt,
+ ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient,
+ ATTR_TYPE_STR, MAIL_ATTR_STATUS, dsn_code,
+ ATTR_TYPE_STR, MAIL_ATTR_ACTION, dsn_action,
+ ATTR_TYPE_STR, MAIL_ATTR_WHY, vstring_str(why),
+ ATTR_TYPE_END) == 0
+ && ((flags & DEL_REQ_FLAG_RECORD) == 0
+ || vtrace_append(flags, id, orig_rcpt, recipient, relay,
+ entry, dsn_code, dsn_action, fmt, ap) == 0)) {
+ vlog_adhoc(id, orig_rcpt, recipient, relay,
+ entry, log_status, fmt, ap);
+ status = (var_soft_bounce ? -1 : 0);
+ } else if ((flags & BOUNCE_FLAG_CLEAN) == 0) {
+ status = defer_append(flags, id, orig_rcpt, recipient, relay,
+ entry, "%s or %s service failure",
+ var_bounce_service, var_trace_service);
+ } else {
+ status = -1;
+ }
+ vstring_free(why);
+ return (status);
}
- vstring_free(why);
- return (status);
}
/* bounce_flush - flush the bounce log and deliver to the sender */
const char *relay, time_t entry,
const char *fmt, va_list ap)
{
- VSTRING *why;
int status;
- int delay;
/*
- * When we're not bouncing, then use the standard logfile based
- * procedure.
+ * MTA-requested address verification information is stored in the verify
+ * service database.
*/
- if (var_soft_bounce)
+ if (flags & DEL_REQ_FLAG_VERIFY) {
+ status = vverify_append(id, orig_rcpt, recipient, relay, entry,
+ "undeliverable", DEL_RCPT_STAT_BOUNCE, fmt, ap);
+ return (status);
+ }
+
+ /*
+ * User-requested address verification information is logged and mailed
+ * to the requesting user.
+ */
+ if (flags & DEL_REQ_FLAG_EXPAND) {
+ status = vtrace_append(flags, id, orig_rcpt, recipient, relay,
+ entry, "5.0.0", "undeliverable", fmt, ap);
+ return (status);
+ }
+
+ /*
+ * When we're not bouncing, then use the standard multi-recipient logfile
+ * based procedure.
+ */
+ else if (var_soft_bounce) {
return (vbounce_append(flags, id, orig_rcpt, recipient,
relay, entry, fmt, ap));
+ }
- why = vstring_alloc(100);
- delay = time((time_t *) 0) - entry;
- vstring_vsprintf(why, fmt, ap);
- if (orig_rcpt == 0)
- orig_rcpt = "";
- if (mail_command_client(MAIL_CLASS_PRIVATE, var_bounce_service,
- ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_ONE,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
- ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue,
- ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
- ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
- ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
- ATTR_TYPE_STR, MAIL_ATTR_ORCPT, orig_rcpt,
- ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient,
- ATTR_TYPE_STR, MAIL_ATTR_WHY, vstring_str(why),
- ATTR_TYPE_END) == 0) {
- if (*orig_rcpt && strcasecmp(recipient, orig_rcpt) != 0)
- msg_info("%s: to=<%s>, orig_to=<%s>, relay=%s, delay=%d, status=bounced (%s)",
- id, recipient, orig_rcpt, relay, delay, vstring_str(why));
- else
- msg_info("%s: to=<%s>, relay=%s, delay=%d, status=bounced (%s)",
- id, recipient, relay, delay, vstring_str(why));
- status = 0;
- } else if ((flags & BOUNCE_FLAG_CLEAN) == 0) {
- status = defer_append(flags, id, orig_rcpt, recipient, "bounce", entry,
- "bounce failed");
- } else {
- status = -1;
+ /*
+ * Normal mail delivery. May also send a delivery record to the user.
+ */
+ else {
+ VSTRING *why = vstring_alloc(100);
+
+ vstring_vsprintf(why, fmt, ap);
+ if (orig_rcpt == 0)
+ orig_rcpt = "";
+ if (mail_command_client(MAIL_CLASS_PRIVATE, var_bounce_service,
+ ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_ONE,
+ ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+ ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue,
+ ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
+ ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
+ ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
+ ATTR_TYPE_STR, MAIL_ATTR_ORCPT, orig_rcpt,
+ ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient,
+ ATTR_TYPE_STR, MAIL_ATTR_STATUS, "5.0.0",
+ ATTR_TYPE_STR, MAIL_ATTR_ACTION, "failed",
+ ATTR_TYPE_STR, MAIL_ATTR_WHY, vstring_str(why),
+ ATTR_TYPE_END) == 0
+ && ((flags & DEL_REQ_FLAG_RECORD) == 0
+ || vtrace_append(flags, id, orig_rcpt, recipient, relay,
+ entry, "5.0.0", "failed", fmt, ap) == 0)) {
+ vlog_adhoc(id, orig_rcpt, recipient, relay,
+ entry, "bounced", fmt, ap);
+ status = 0;
+ } else if ((flags & BOUNCE_FLAG_CLEAN) == 0) {
+ status = defer_append(flags, id, orig_rcpt, recipient, relay,
+ entry, "%s or %s service failure",
+ var_bounce_service, var_trace_service);
+ } else {
+ status = -1;
+ }
+ vstring_free(why);
+ return (status);
}
- vstring_free(why);
- return (status);
}
#include <time.h>
#include <stdarg.h>
+ /*
+ * Global library.
+ */
+#include <deliver_request.h>
+
/*
* Client interface.
*/
const char *, time_t, const char *, va_list);
extern int bounce_flush(int, const char *, const char *, const char *, const char *);
extern int PRINTFLIKE(10, 11) bounce_one(int, const char *, const char *,
- const char *, const char *,
- const char *, const char *,
- const char *, time_t,
- const char *,...);
+ const char *, const char *,
+ const char *, const char *,
+ const char *, time_t,
+ const char *,...);
extern int vbounce_one(int, const char *, const char *, const char *,
const char *, const char *, const char *,
const char *, time_t, const char *, va_list);
#define BOUNCE_CMD_WARN 2 /* send warning, don't delete log */
#define BOUNCE_CMD_VERP 3 /* send log, verp style */
#define BOUNCE_CMD_ONE 4 /* send one recipient notice */
+#define BOUNCE_CMD_TRACE 5 /* send delivery record */
/*
* Flags.
/* .in +4
/* /* public members... */
/* const char *recipient;
-/* const char *status;
+/* const char *orig_rcpt;
+/* const char *dsn_status;
+/* const char *dsn_action;
/* const char *text;
/* .in -4
/* } BOUNCE_LOG;
/* void bounce_log_rewind(bp)
/* BOUNCE_LOG *bp;
/*
-/* BOUNCE_LOG *bounce_log_forge(recipient, dsn, why)
+/* BOUNCE_LOG *bounce_log_forge(orig_rcpt, recipient, dsn_status,
+/* dsn_action, why)
+/* const char *orig_rcpt;
/* const char *recipient;
-/* const char *status;
+/* const char *dsn_status;
+/* const char *dsn_action;
/* const char *why;
/*
/* void bounce_log_close(bp)
/* of problems.
/*
/* bounce_log_forge() forges one recipient status record
-/* without actually accessing a logfile.
+/* without actually accessing a logfile.
/* The result cannot be used for any logfile access operation
/* and must be disposed of by passing it to bounce_log_close().
/*
/* The final recipient address.
/* .IP text
/* The text that explains why the recipient was undeliverable.
-/* .IP status
+/* .IP dsn_status
/* String with DSN compatible status code (digit.digit.digit).
+/* .IP dsn_action
+/* "delivered", "failed", "delayed" and so on.
/* .PP
/* Other fields will be added as the code evolves.
/* LICENSE
/* Global library. */
+#include <mail_params.h>
+#include <mail_proto.h>
#include <mail_queue.h>
#include <bounce_log.h>
/* Application-specific. */
-#define STR(x) vstring_str(x)
+#define STR(x) vstring_str(x)
/* bounce_log_init - initialize structure */
static BOUNCE_LOG *bounce_log_init(VSTREAM *fp,
VSTRING *buf,
- const char *recipient,
- const char *status,
- const char *text,
+ VSTRING *orcp_buf,
+ VSTRING *rcpt_buf,
+ VSTRING *status_buf,
+ const char *compat_status,
+ VSTRING *action_buf,
+ const char *compat_action,
+ VSTRING *text_buf,
long offset)
{
BOUNCE_LOG *bp;
+#define SET_BUFFER(bp, buf, str) { \
+ bp->buf = buf; \
+ bp->str = (buf && STR(buf)[0] ? STR(buf) : 0); \
+ }
+
bp = (BOUNCE_LOG *) mymalloc(sizeof(*bp));
bp->fp = fp;
bp->buf = buf;
- bp->recipient = recipient;
- bp->status = status;
- bp->text = text;
+ SET_BUFFER(bp, orcp_buf, orig_rcpt);
+ SET_BUFFER(bp, rcpt_buf, recipient);
+ SET_BUFFER(bp, status_buf, dsn_status);
+ bp->compat_status = compat_status;
+ SET_BUFFER(bp, action_buf, dsn_action);
+ bp->compat_action = compat_action;
+ SET_BUFFER(bp, text_buf, text);
bp->offset = offset;
return (bp);
}
VSTREAM *fp;
#define STREQ(x,y) (strcmp((x),(y)) == 0)
+#define SAVE_TO_VSTRING(s) vstring_strcpy(vstring_alloc(10), (s))
/*
* TODO: peek at the first byte to see if this is an old-style log
* (<recipient>: text) or a new-style extensible log with multiple
- * attributes per recipient.
+ * attributes per recipient. That would not help during a transition from
+ * old to new style, where one can expect to find mixed format files.
+ *
+ * Kluge up default DSN status and action for old-style logfiles.
*/
if ((fp = mail_queue_open(queue_name, queue_id, flags, mode)) == 0) {
return (0);
} else {
return (bounce_log_init(fp, /* stream */
vstring_alloc(100), /* buffer */
- (const char *) 0, /* recipient */
+ vstring_alloc(10), /* orig_rcpt */
+ vstring_alloc(10), /* recipient */
+ vstring_alloc(10), /* dsn_status */
STREQ(queue_name, MAIL_QUEUE_DEFER) ?
- "4.0.0" : "5.0.0", /* status */
- (const char *) 0, /* text */
+ "4.0.0" : "5.0.0", /* compatibility */
+ vstring_alloc(10), /* dsn_action */
+ STREQ(queue_name, MAIL_QUEUE_DEFER) ?
+ "delayed" : "failed", /* compatibility */
+ vstring_alloc(10), /* text */
0)); /* offset */
}
}
char *recipient;
char *text;
char *cp;
+ int state;
+ long offset;
+
+ /*
+ * Our trivial logfile parser state machine.
+ */
+#define START 0 /* still searching */
+#define FOUND 1 /* in logfile entry */
+#define SKIP 2 /* in deleted entry */
- while ((bp->offset = vstream_ftell(bp->fp)),
+ /*
+ * Initialize.
+ */
+ state = START;
+ bp->recipient = "(unavailable)";
+ bp->orig_rcpt = 0;
+ bp->dsn_status = "(unavailable)";
+ bp->dsn_action = "(unavailable)";
+ bp->text = "(unavailable)";
+
+ /*
+ * Support mixed logfile formats to make transitions easier. The same
+ * file can start with old-style records and end with new-style records.
+ * With backwards compatibility, we even have old format followed by new
+ * format within the same logfile entry!
+ */
+ while ((offset = vstream_ftell(bp->fp)),
(vstring_get_nonl(bp->buf, bp->fp) != VSTREAM_EOF)) {
- if (STR(bp->buf)[0] == 0)
+ /*
+ * Logfile entries are separated by blank lines. Even the old ad-hoc
+ * logfile format has a blank line after the last record. This means
+ * we can safely use blank lines to detect the start and end of
+ * logfile entries.
+ */
+ if (STR(bp->buf)[0] == 0) {
+ if (state == FOUND)
+ return (bp);
+ state = START;
+ continue;
+ }
+
+ /*
+ * Skip over deleted logfile entries.
+ */
+ if (state == SKIP)
continue;
/*
- * Sanitize.
+ * Sanitize. XXX This needs to be done more carefully with new-style
+ * logfile entries.
*/
cp = printable(STR(bp->buf), '?');
/*
* Skip over deleted recipients.
*/
- if (*cp == BOUNCE_LOG_STAT_DELETED)
+ if (*cp == BOUNCE_LOG_STAT_DELETED) {
+ state = SKIP;
continue;
+ }
+
+ /*
+ * Save the first record offset of this logfile entry so that it can
+ * be marked as deleted.
+ */
+ if (state == START) {
+ state = FOUND;
+ bp->offset = offset;
+ }
/*
- * Find the recipient address.
+ * New style logfile entries are in "name = value" format.
+ */
+ if (ISALNUM(*cp)) {
+ const char *err;
+ char *name;
+ char *value;
+
+ /*
+ * Split into name and value.
+ */
+ if ((err = split_nameval(cp, &name, &value)) != 0) {
+ msg_warn("%s: malformed record: %s", VSTREAM_PATH(bp->fp), err);
+ continue;
+ }
+
+ /*
+ * Save attribute value.
+ */
+ if (STREQ(name, MAIL_ATTR_RECIP)) {
+ bp->recipient = STR(vstring_strcpy(bp->rcpt_buf, *value ?
+ value : "(MAILER-DAEMON)"));
+ } else if (STREQ(name, MAIL_ATTR_ORCPT)) {
+ bp->orig_rcpt = STR(vstring_strcpy(bp->orcp_buf, *value ?
+ value : "(MAILER-DAEMON)"));
+ } else if (STREQ(name, MAIL_ATTR_STATUS)) {
+ bp->dsn_status = STR(vstring_strcpy(bp->status_buf, value));
+ } else if (STREQ(name, MAIL_ATTR_ACTION)) {
+ bp->dsn_action = STR(vstring_strcpy(bp->action_buf, value));
+ } else if (STREQ(name, MAIL_ATTR_WHY)) {
+ bp->text = STR(vstring_strcpy(bp->text_buf, value));
+ } else {
+ msg_warn("%s: unknown attribute name: %s, ignored",
+ VSTREAM_PATH(bp->fp), name);
+ }
+ continue;
+ }
+
+ /*
+ * Old-style logfile record. Find the recipient address.
*/
if (*cp != '<') {
msg_warn("%s: malformed record: %.30s...",
continue;
}
*cp = 0;
- bp->recipient = *recipient ? recipient : "(MAILER-DAEMON)";
+ vstring_strcpy(bp->rcpt_buf, *recipient ?
+ recipient : "(MAILER-DAEMON)");
+ bp->recipient = STR(bp->rcpt_buf);
/*
* Find the text that explains why mail was not deliverable.
text = cp + 2;
while (*text && ISSPACE(*text))
text++;
- bp->text = text;
+ vstring_strcpy(bp->text_buf, text);
+ bp->text = STR(bp->text_buf);
- return (bp);
+ /*
+ * Add compatibility status and action info, to make up for data that
+ * was not stored in old-style bounce logfiles.
+ */
+ bp->dsn_status = bp->compat_status;
+ bp->dsn_action = bp->compat_action;
}
return (0);
}
/* bounce_log_forge - forge one recipient status record */
-BOUNCE_LOG *bounce_log_forge(const char *recipient, const char *status,
+BOUNCE_LOG *bounce_log_forge(const char *orig_rcpt, const char *recipient,
+ const char *dsn_status, const char *dsn_action,
const char *text)
{
- return (bounce_log_init((VSTREAM *) 0, (VSTRING *) 0,
- recipient, status, text, 0));
+ return (bounce_log_init((VSTREAM *) 0,
+ (VSTRING *) 0,
+ SAVE_TO_VSTRING(orig_rcpt),
+ SAVE_TO_VSTRING(recipient),
+ SAVE_TO_VSTRING(dsn_status),
+ "(unavailable)",
+ SAVE_TO_VSTRING(dsn_action),
+ "(unavailable)",
+ SAVE_TO_VSTRING(text),
+ 0));
}
/* bounce_log_close - close bounce reader stream */
ret = 0;
if (bp->buf)
vstring_free(bp->buf);
+ if (bp->rcpt_buf)
+ vstring_free(bp->rcpt_buf);
+ if (bp->orcp_buf)
+ vstring_free(bp->orcp_buf);
+ if (bp->status_buf)
+ vstring_free(bp->status_buf);
+ if (bp->action_buf)
+ vstring_free(bp->action_buf);
+ if (bp->text_buf)
+ vstring_free(bp->text_buf);
myfree((char *) bp);
return (ret);
}
/* Private. */
VSTREAM *fp; /* open file */
VSTRING *buf; /* I/O buffer */
+ VSTRING *rcpt_buf; /* final recipient */
+ VSTRING *orcp_buf; /* original recipient */
+ VSTRING *status_buf; /* dsn code */
+ const char *compat_status; /* old logfile compatibility */
+ VSTRING *action_buf; /* dsn action */
+ const char *compat_action; /* old logfile compatibility */
+ VSTRING *text_buf; /* descriptive text */
/* Public. */
const char *recipient; /* final recipient */
- const char *status; /* recipient status */
- const char *text; /* why undeliverable */
+ const char *orig_rcpt; /* original recipient */
+ const char *dsn_status; /* dsn code */
+ const char *dsn_action; /* dsn action */
+ const char *text; /* descriptive text */
long offset; /* start of current record */
} BOUNCE_LOG;
extern BOUNCE_LOG *bounce_log_open(const char *, const char *, int, int);
extern BOUNCE_LOG *bounce_log_read(BOUNCE_LOG *);
extern BOUNCE_LOG *bounce_log_delrcpt(BOUNCE_LOG *);
-extern BOUNCE_LOG *bounce_log_forge(const char *, const char *, const char *);
+extern BOUNCE_LOG *bounce_log_forge(const char *, const char *, const char *, const char *, const char *);
extern int bounce_log_close(BOUNCE_LOG *);
#define bounce_log_rewind(bp) vstream_fseek((bp)->fp, 0L, SEEK_SET)
/* each recipient whose delivery is deferred, and the reason why.
/*
/* defer_append() appends a record to the per-message defer log,
-/* with the reason for delayed delivery to the named recipient.
+/* with the reason for delayed delivery to the named recipient,
+/* updates the address verification service, or updates a message
+/* delivery record on request by the sender. The flags argument
+/* determines the action.
/* The result is a convenient non-zero value.
/* When the fast flush cache is enabled, the fast flush server is
/* notified of deferred mail.
/* .IP BOUNCE_FLAG_CLEAN
/* Delete the defer log in case of an error (as in: pretend
/* that we never even tried to defer this message).
+/* .IP DEL_REQ_FLAG_VERIFY
+/* The message is an address verification probe. Update the
+/* address verification database instead of deferring mail.
+/* .IP DEL_REQ_FLAG_EXPAND
+/* The message is an address expansion probe. Update the
+/* the message delivery record instead of deferring mail.
+/* .IP DEL_REQ_FLAG_RECORD
+/* This is a normal message with logged delivery. Update the
+/* message delivery record and defer mail delivery.
/* .RE
/* .IP queue
/* The message queue name of the original message file.
/* Global library. */
-#include "mail_params.h"
-#include "mail_queue.h"
-#include "mail_proto.h"
-#include "flush_clnt.h"
-#include "bounce.h"
-#include "defer.h"
+#include <mail_params.h>
+#include <mail_queue.h>
+#include <mail_proto.h>
+#include <flush_clnt.h>
+#include <verify.h>
+#include <log_adhoc.h>
+#include <trace.h>
+#include <bounce.h>
+#include <defer.h>
#define STR(x) vstring_str(x)
const char *recipient, const char *relay,
time_t entry, const char *fmt, va_list ap)
{
- VSTRING *why = vstring_alloc(100);
- int delay = time((time_t *) 0) - entry;
const char *rcpt_domain;
+ int status;
- vstring_vsprintf(why, fmt, ap);
- if (orig_rcpt == 0)
- orig_rcpt = "";
- if (mail_command_client(MAIL_CLASS_PRIVATE, var_defer_service,
+ /*
+ * MTA-requested address verification information is stored in the verify
+ * service database.
+ */
+ if (flags & DEL_REQ_FLAG_VERIFY) {
+ status = vverify_append(id, orig_rcpt, recipient, relay, entry,
+ "undeliverable", DEL_RCPT_STAT_DEFER, fmt, ap);
+ return (status);
+ }
+
+ /*
+ * User-requested address verification information is logged and mailed
+ * to the requesting user.
+ */
+ if (flags & DEL_REQ_FLAG_EXPAND) {
+ status = vtrace_append(flags, id, orig_rcpt, recipient, relay,
+ entry, "4.0.0", "undeliverable", fmt, ap);
+ return (status);
+ }
+
+ /*
+ * Normal mail delivery. May also send a delivery record to the user.
+ */
+ else {
+ VSTRING *why = vstring_alloc(100);
+
+ vstring_vsprintf(why, fmt, ap);
+
+ if (orig_rcpt == 0)
+ orig_rcpt = "";
+ if (mail_command_client(MAIL_CLASS_PRIVATE, var_defer_service,
ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_APPEND,
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
ATTR_TYPE_STR, MAIL_ATTR_ORCPT, orig_rcpt,
ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient,
+ ATTR_TYPE_STR, MAIL_ATTR_STATUS, "4.0.0",
+ ATTR_TYPE_STR, MAIL_ATTR_ACTION, "delayed",
ATTR_TYPE_STR, MAIL_ATTR_WHY, vstring_str(why),
ATTR_TYPE_END) != 0)
- msg_warn("%s: defer service failure", id);
- if (*orig_rcpt && strcasecmp(recipient, orig_rcpt) != 0)
- msg_info("%s: to=<%s>, orig_to=<%s>, relay=%s, delay=%d, status=deferred (%s)",
- id, recipient, orig_rcpt, relay, delay, vstring_str(why));
- else
- msg_info("%s: to=<%s>, relay=%s, delay=%d, status=deferred (%s)",
- id, recipient, relay, delay, vstring_str(why));
- vstring_free(why);
+ msg_warn("%s: %s service failure", id, var_defer_service);
+ vlog_adhoc(id, orig_rcpt, recipient, relay, entry, "deferred", fmt, ap);
- /*
- * Notify the fast flush service. XXX Should not this belong in the
- * bounce/defer daemon? Well, doing it here is more robust.
- */
- if ((rcpt_domain = strrchr(recipient, '@')) != 0 && *++rcpt_domain != 0)
- switch (flush_add(rcpt_domain, id)) {
- case FLUSH_STAT_OK:
- case FLUSH_STAT_DENY:
- break;
- default:
- msg_warn("unable to talk to fast flush service");
- break;
- }
-
- return (-1);
+ /*
+ * Traced delivery.
+ */
+ if (flags & DEL_REQ_FLAG_RECORD)
+ if (vtrace_append(flags, id, orig_rcpt, recipient, relay,
+ entry, "4.0.0", "deferred", fmt, ap) != 0)
+ msg_warn("%s: %s service failure", id, var_trace_service);
+
+ /*
+ * Notify the fast flush service. XXX Should not this belong in the
+ * bounce/defer daemon? Well, doing it here is more robust.
+ */
+ if ((rcpt_domain = strrchr(recipient, '@')) != 0 && *++rcpt_domain != 0)
+ switch (flush_add(rcpt_domain, id)) {
+ case FLUSH_STAT_OK:
+ case FLUSH_STAT_DENY:
+ break;
+ default:
+ msg_warn("%s: %s service failure", id, var_flush_service);
+ break;
+ }
+ vstring_free(why);
+ return (-1);
+ }
}
/* defer_flush - flush the defer log and deliver to the sender */
* Global library.
*/
#include <bounce.h>
+#include <deliver_request.h>
/*
* External interface.
#define DEL_REQ_FLAG_SUCCESS (1<<0) /* delete successful recipients */
#define DEL_REQ_FLAG_BOUNCE (1<<1) /* unimplemented */
+#define DEL_REQ_FLAG_VERIFY (1<<8) /* verify recipient, don't deliver */
+#define DEL_REQ_FLAG_EXPAND (1<<9) /* verify expansion, don't deliver */
+#define DEL_REQ_FLAG_RECORD (1<<10) /* record and deliver */
+
+#define DEL_REQ_TRACE_FLAGS_MASK \
+ (DEL_REQ_FLAG_VERIFY | DEL_REQ_FLAG_EXPAND | DEL_REQ_FLAG_RECORD)
+#define DEL_REQ_TRACE_FLAGS(f) ((f) & DEL_REQ_TRACE_FLAGS_MASK)
+
+#define DEL_REQ_TRACE_ONLY_MASK \
+ (DEL_REQ_FLAG_VERIFY | DEL_REQ_FLAG_EXPAND)
+#define DEL_REQ_TRACE_ONLY(f) ((f) & DEL_REQ_TRACE_ONLY_MASK)
+
+ /*
+ * Per-recipient delivery status. Not to be confused with per-delivery
+ * request status.
+ */
+#define DEL_RCPT_STAT_OK 0
+#define DEL_RCPT_STAT_DEFER 1
+#define DEL_RCPT_STAT_BOUNCE 2
+#define DEL_RCPT_STAT_TODO 3
+
/*
- * Delivery status. Note that there are only FINAL and DEFER. This is
- * because delivery status information can be lost when a delivery agent or
- * queue manager process terminates prematurely. The only distinctions we
- * can rely on are "final delivery completed" and "everything else". In the
- * absence of a definitive statement the queue manager will always have to
- * be prepared for all possibilities.
+ * Delivery request status. Note that there are only FINAL and DEFER. This
+ * is because delivery status information can be lost when a delivery agent
+ * or queue manager process terminates prematurely. The only distinctions we
+ * can rely on are "final delivery completed" (positive confirmation that
+ * all recipients are marked as done) and "everything else". In the absence
+ * of a definitive statement the queue manager will always have to be
+ * prepared for all possibilities.
*/
-#define DEL_STAT_FINAL 0 /* delivered or bounced */
-#define DEL_STAT_DEFER (-1) /* not delivered or bounced */
+#define DEL_STAT_FINAL 0 /* delivered or bounced */
+#define DEL_STAT_DEFER (-1) /* not delivered or bounced */
typedef struct VSTREAM _deliver_vstream_;
extern DELIVER_REQUEST *deliver_request_read(_deliver_vstream_ *);
--- /dev/null
+/*++
+/* NAME
+/* log_adhoc 3
+/* SUMMARY
+/* ad-hoc delivery event logging
+/* SYNOPSIS
+/* #include <log_adhoc.h>
+/*
+/* void log_adhoc(id, orig_rcpt, recipient, relay,
+/* entry, status, format, ...)
+/* const char *id;
+/* const char *orig_rcpt;
+/* const char *recipient;
+/* const char *relay;
+/* time_t entry;
+/* const char *status;
+/* const char *format;
+/*
+/* void vlog_adhoc(id, orig_rcpt, recipient, relay,
+/* entry, status, format, ap)
+/* const char *id;
+/* const char *orig_rcpt;
+/* const char *recipient;
+/* const char *relay;
+/* time_t entry;
+/* const char *status;
+/* const char *format;
+/* va_list ap;
+/* DESCRIPTION
+/* This module logs delivery events in an ad-hoc manner.
+/*
+/* log_adhoc() appends a record to the mail logfile
+/*
+/* vlog_adhoc() implements an alternative client interface.
+/*
+/* Arguments:
+/* .IP queue
+/* The message queue name of the original message file.
+/* .IP id
+/* The queue id of the original message file.
+/* .IP orig_rcpt
+/* The original envelope recipient address. If unavailable,
+/* specify a null string or null pointer.
+/* .IP recipient
+/* A recipient address that is being deferred. The domain part
+/* of the address is marked dead (for a limited amount of time).
+/* .IP sender
+/* The sender envelope address.
+/* .IP relay
+/* Host we could (not) talk to.
+/* .IP status
+/* bounced, deferred, sent, and so on.
+/* .IP entry
+/* Message arrival time.
+/* .IP format
+/* Descriptive text.
+/* .IP ap
+/* Variable-length argument list.
+/* BUGS
+/* Should be replaced by routines with an attribute-value based
+/* interface instead of an interface that uses a rigid argument list.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <stdlib.h> /* 44BSD stdarg.h uses abort() */
+#include <stdarg.h>
+#include <string.h>
+
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
+/* Utility library. */
+
+#include <msg.h>
+#include <vstring.h>
+
+/* Global library. */
+
+#include <log_adhoc.h>
+
+/* log_adhoc - defer message delivery */
+
+void log_adhoc(const char *id, const char *orig_rcpt,
+ const char *recipient, const char *relay,
+ time_t entry, const char *status,
+ const char *fmt,...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vlog_adhoc(id, orig_rcpt, recipient, relay, entry, status, fmt, ap);
+ va_end(ap);
+}
+
+/* vlog_adhoc - defer delivery of queue file */
+
+void vlog_adhoc(const char *id, const char *orig_rcpt,
+ const char *recipient, const char *relay,
+ time_t entry, const char *status,
+ const char *fmt, va_list ap)
+{
+ VSTRING *why = vstring_alloc(100);
+ int delay = time((time_t *) 0) - entry;
+
+ vstring_vsprintf(why, fmt, ap);
+ if (orig_rcpt == 0)
+ orig_rcpt = "";
+ if (strcasecmp(recipient, orig_rcpt) != 0)
+ msg_info("%s: to=<%s>, orig_to=<%s>, relay=%s, delay=%d, status=%s (%s)",
+ id, recipient, orig_rcpt, relay, delay, status, vstring_str(why));
+ else
+ msg_info("%s: to=<%s>, relay=%s, delay=%d, status=%s (%s)",
+ id, recipient, relay, delay, status, vstring_str(why));
+ vstring_free(why);
+}
--- /dev/null
+#ifndef _LOG_ADHOC_H_INCLUDED_
+#define _LOG_ADHOC_H_INCLUDED_
+
+/*++
+/* NAME
+/* log_adhoc 3h
+/* SUMMARY
+/* ad-hoc delivery event logging
+/* SYNOPSIS
+/* #include <log_adhoc.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * System library.
+ */
+#include <stdarg.h>
+#include <time.h>
+
+ /*
+ * Client interface.
+ */
+extern void PRINTFLIKE(7, 8) log_adhoc(const char *, const char *,
+ const char *, const char *,
+ time_t, const char *,
+ const char *,...);
+extern void vlog_adhoc(const char *, const char *,
+ const char *, const char *,
+ time_t, const char *,
+ const char *, va_list);
+
+/* 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
/* char *var_showq_service;
/* char *var_error_service;
/* char *var_flush_service;
+/* char *var_verify_service;
+/* char *var_trace_service;
/* int var_db_create_buf;
/* int var_db_read_buf;
/* int var_mime_maxdepth;
/* int var_strict_7bit_hdrs;
/* int var_strict_8bit_body;
/* int var_strict_encoding;
+/* int var_verify_neg_cache;
+/* int var_oldlog_compat;
/*
/* void mail_params_init()
/* DESCRIPTION
char *var_showq_service;
char *var_error_service;
char *var_flush_service;
+char *var_verify_service;
+char *var_trace_service;
int var_db_create_buf;
int var_db_read_buf;
int var_mime_maxdepth;
int var_strict_7bit_hdrs;
int var_strict_8bit_body;
int var_strict_encoding;
+int var_verify_neg_cache;
+int var_oldlog_compat;
/* check_myhostname - lookup hostname and validate */
VAR_SHOWQ_SERVICE, DEF_SHOWQ_SERVICE, &var_showq_service, 1, 0,
VAR_ERROR_SERVICE, DEF_ERROR_SERVICE, &var_error_service, 1, 0,
VAR_FLUSH_SERVICE, DEF_FLUSH_SERVICE, &var_flush_service, 1, 0,
+ VAR_VERIFY_SERVICE, DEF_VERIFY_SERVICE, &var_verify_service, 1, 0,
+ VAR_TRACE_SERVICE, DEF_TRACE_SERVICE, &var_trace_service, 1, 0,
0,
};
static CONFIG_STR_FN_TABLE function_str_defaults_2[] = {
VAR_STRICT_ENCODING, DEF_STRICT_ENCODING, &var_strict_encoding,
VAR_DISABLE_MIME_INPUT, DEF_DISABLE_MIME_INPUT, &var_disable_mime_input,
VAR_DISABLE_MIME_OCONV, DEF_DISABLE_MIME_OCONV, &var_disable_mime_oconv,
+ VAR_VERIFY_NEG_CACHE, DEF_VERIFY_NEG_CACHE, &var_verify_neg_cache,
+ VAR_OLDLOG_COMPAT, DEF_OLDLOG_COMPAT, &var_oldlog_compat,
VAR_HELPFUL_WARNINGS, DEF_HELPFUL_WARNINGS, &var_helpful_warnings,
0,
};
* subdirectories, and how deep the forest is.
*/
#define VAR_HASH_QUEUE_NAMES "hash_queue_names"
-#define DEF_HASH_QUEUE_NAMES "incoming,active,deferred,bounce,defer,flush,hold"
+#define DEF_HASH_QUEUE_NAMES "incoming,active,deferred,bounce,defer,flush,hold,trace"
extern char *var_hash_queue_names;
#define VAR_HASH_QUEUE_DEPTH "hash_queue_depth"
#define DEF_SMTP_DATA2_TMOUT "600s"
extern int var_smtp_data2_tmout;
+#define VAR_SMTP_RSET_TMOUT "smtp_rset_timeout"
+#define DEF_SMTP_RSET_TMOUT "120s"
+extern int var_smtp_rset_tmout;
+
#define VAR_SMTP_QUIT_TMOUT "smtp_quit_timeout"
#define DEF_SMTP_QUIT_TMOUT "300s"
extern int var_smtp_quit_tmout;
extern int var_lmtp_conn_tmout;
#define VAR_LMTP_RSET_TMOUT "lmtp_rset_timeout"
-#define DEF_LMTP_RSET_TMOUT "300s"
+#define DEF_LMTP_RSET_TMOUT "120s"
extern int var_lmtp_rset_tmout;
#define VAR_LMTP_LHLO_TMOUT "lmtp_lhlo_timeout"
#define DEF_UNK_ADDR_CODE 450
extern int var_unk_addr_code;
+#define REJECT_UNVERIFIED_RECIP "reject_unverified_recipient"
+#define VAR_UNV_RCPT_CODE "unverified_recipient_reject_code"
+#define DEF_UNV_RCPT_CODE 450
+extern int var_unv_rcpt_code;
+
+#define REJECT_UNVERIFIED_SENDER "reject_unverified_sender"
+#define VAR_UNV_FROM_CODE "unverified_sender_reject_code"
+#define DEF_UNV_FROM_CODE 450
+extern int var_unv_from_code;
+
+#define REJECT_MUL_RCPT_BOUNCE "reject_multi_recipient_bounce"
+#define VAR_MUL_RCPT_CODE "multi_recipient_bounce_reject_code"
+#define DEF_MUL_RCPT_CODE 550
+extern int var_mul_rcpt_code;
+
#define PERMIT_AUTH_DEST "permit_auth_destination"
#define REJECT_UNAUTH_DEST "reject_unauth_destination"
#define CHECK_RELAY_DOMAINS "check_relay_domains"
#define DEF_FLUSH_SERVICE MAIL_SERVICE_FLUSH
extern char *var_flush_service;
+ /*
+ * Address verification service.
+ */
+#define VAR_VERIFY_SERVICE "address_verify_service_name"
+#define DEF_VERIFY_SERVICE MAIL_SERVICE_VERIFY
+extern char *var_verify_service;
+
+#define VAR_VERIFY_MAP "address_verify_map"
+#define DEF_VERIFY_MAP ""
+extern char *var_verify_map;
+
+#define VAR_VERIFY_POS_EXP "address_verify_positive_expire_time"
+#define DEF_VERIFY_POS_EXP "31d"
+extern int var_verify_pos_exp;
+
+#define VAR_VERIFY_POS_TRY "address_verify_positive_refresh_time"
+#define DEF_VERIFY_POS_TRY "7d"
+extern int var_verify_pos_try;
+
+#define VAR_VERIFY_NEG_EXP "address_verify_negative_expire_time"
+#define DEF_VERIFY_NEG_EXP "3d"
+extern int var_verify_neg_exp;
+
+#define VAR_VERIFY_NEG_TRY "address_verify_negative_refresh_time"
+#define DEF_VERIFY_NEG_TRY "2h"
+extern int var_verify_neg_try;
+
+#define VAR_VERIFY_NEG_CACHE "address_verify_negative_cache"
+#define DEF_VERIFY_NEG_CACHE 1
+extern bool var_verify_neg_cache;
+
+#define VAR_VERIFY_SENDER "address_verify_sender"
+#define DEF_VERIFY_SENDER "postmaster"
+extern char *var_verify_sender;
+
+ /*
+ * Message delivery trace service.
+ */
+#define VAR_TRACE_SERVICE "trace_service_name"
+#define DEF_TRACE_SERVICE MAIL_SERVICE_TRACE
+extern char *var_trace_service;
+
/*
* Mailbox/maildir delivery errors that cause delivery to be tried again.
*/
#define DEF_XPORT_NULL_KEY "<>"
extern char *var_xport_null_key;
+ /*
+ * Bounce service controls.
+ */
+#define VAR_OLDLOG_COMPAT "backwards_bounce_logfile_compatibility"
+#define DEF_OLDLOG_COMPAT 1
+extern bool var_oldlog_compat;
+
/* LICENSE
/* .ad
/* .fi
#define MAIL_SERVICE_SHOWQ "showq"
#define MAIL_SERVICE_ERROR "error"
#define MAIL_SERVICE_FLUSH "flush"
+#define MAIL_SERVICE_VERIFY "verify"
+#define MAIL_SERVICE_TRACE "trace"
#define MAIL_SERVICE_RELAY "relay"
/*
#define MAIL_ATTR_ADDR "address"
#define MAIL_ATTR_TRANSPORT "transport"
#define MAIL_ATTR_NEXTHOP "nexthop"
+#define MAIL_ATTR_TRACE_FLAGS "trace_flags"
+#define MAIL_ATTR_ADDR_STATUS "recipient_status"
+#define MAIL_ATTR_ACTION "action"
/*
* Suffixes for sender_name, sender_domain etc.
#define MAIL_QUEUE_INCOMING "incoming"
#define MAIL_QUEUE_ACTIVE "active"
#define MAIL_QUEUE_DEFERRED "deferred"
+#define MAIL_QUEUE_TRACE "trace"
#define MAIL_QUEUE_DEFER "defer"
#define MAIL_QUEUE_BOUNCE "bounce"
#define MAIL_QUEUE_CORRUPT "corrupt"
* Patches change the patchlevel and the release date. Snapshots change the
* release date only, unless they include the same bugfix as a patch release.
*/
-#define MAIL_RELEASE_DATE "20021221"
+#define MAIL_RELEASE_DATE "20021222"
#define VAR_MAIL_VERSION "mail_version"
-#define DEF_MAIL_VERSION "1.1.12-" MAIL_RELEASE_DATE
+#define DEF_MAIL_VERSION "2.0.0-" MAIL_RELEASE_DATE
extern char *var_mail_version;
/*
/* SYNOPSIS
/* #include <post_mail.h>
/*
-/* VSTREAM *post_mail_fopen(sender, recipient, flags)
+/* VSTREAM *post_mail_fopen(sender, recipient, cleanup_flags, trace_flags)
/* const char *sender;
/* const char *recipient;
-/* int flags;
+/* int cleanup_flags;
+/* int trace_flags;
/*
-/* VSTREAM *post_mail_fopen_nowait(sender, recipient, flags)
+/* VSTREAM *post_mail_fopen_nowait(sender, recipient,
+/* cleanup_flags, trace_flags)
/* const char *sender;
/* const char *recipient;
-/* int flags;
+/* int cleanup_flags;
+/* int trace_flags;
+/*
+/* VSTREAM *post_mail_fopen_async(sender, recipient,
+/* cleanup_flags, trace_flags,
+/* notify, context)
+/* const char *sender;
+/* const char *recipient;
+/* int cleanup_flags;
+/* int trace_flags;
+/* void (*notify)(char *context);
+/* char *context;
/*
/* int post_mail_fprintf(stream, format, ...)
/* VSTREAM *stream;
/* only once, and does not wait until the cleanup service is
/* available. Otherwise it is identical to post_mail_fopen().
/*
+/* post_mail_fopen_async() contacts the cleanup service and
+/* invokes the caller-specified notify routine, with the
+/* caller-specified context, when the service responds.
+/* IMPORTANT NOTE: closing the stream will not cancel any
+/* pending I/O or timeout call-back notification.
+/*
/* post_mail_fprintf() formats message content (header or body)
/* and sends it to the cleanup service.
/*
/* .IP recipient
/* The recipient envelope address. It is up to the application
/* to produce To: headers.
-/* .IP flags
+/* .IP cleanup_flags
/* The binary OR of zero or more of the options defined in
-/* \fI<cleanup_user.h>\fR.
+/* \fB<cleanup_user.h>\fR.
+/* .IP trace_flags
+/* Message tracing flags as specified in \fB<deliver_request.h>\fR.
/* .IP via
/* The name of the service responsible for posting this message.
/* .IP stream
/* A stream opened by mail_post_fopen().
+/* .IP notify
+/* Application call-back routine.
+/* .IP context
+/* Application call-back context.
/* DIAGNOSTICS
/* post_mail_fopen_nowait() returns a null pointer when the
/* cleanup service is not available immediately.
/*
+/* post_mail_fopen_async() returns a null pointer when the
+/* attempt to contact the cleanup service fails immediately.
+/*
/* post_mail_fprintf(), post_mail_fputs() post_mail_fclose(),
/* and post_mail_buffer() return the binary OR of the error
/* status codes defined in \fI<cleanup_user.h>\fR.
#include <msg.h>
#include <vstream.h>
#include <vstring.h>
+#include <mymalloc.h>
+#include <events.h>
/* Global library. */
#include <post_mail.h>
#include <mail_date.h>
+ /*
+ * Call-back state for asynchronous connection requests.
+ */
+typedef struct {
+ char *sender;
+ char *recipient;
+ int cleanup_flags;
+ int trace_flags;
+ POST_MAIL_NOTIFY notify;
+ void *context;
+ VSTREAM *stream;
+} POST_MAIL_STATE;
+
/* post_mail_init - initial negotiations */
static void post_mail_init(VSTREAM *stream, const char *sender,
- const char *recipient, int flags)
+ const char *recipient,
+ int cleanup_flags, int trace_flags)
{
VSTRING *id = vstring_alloc(100);
long now = time((time_t *) 0);
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
ATTR_TYPE_END) != 1
|| attr_print(stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+ ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, cleanup_flags,
ATTR_TYPE_END) != 0)
msg_fatal("unable to contact the %s service", var_cleanup_service);
rec_fprintf(stream, REC_TYPE_TIME, "%ld", (long) now);
rec_fprintf(stream, REC_TYPE_ATTR, "%s=%s",
MAIL_ATTR_ORIGIN, MAIL_ATTR_ORG_LOCAL);
+ rec_fprintf(stream, REC_TYPE_ATTR, "%s=%d",
+ MAIL_ATTR_TRACE_FLAGS, trace_flags);
rec_fputs(stream, REC_TYPE_FROM, sender);
rec_fputs(stream, REC_TYPE_RCPT, recipient);
rec_fputs(stream, REC_TYPE_MESG, "");
/* post_mail_fopen - prepare for posting a message */
-VSTREAM *post_mail_fopen(const char *sender, const char *recipient, int flags)
+VSTREAM *post_mail_fopen(const char *sender, const char *recipient,
+ int cleanup_flags, int trace_flags)
{
VSTREAM *stream;
stream = mail_connect_wait(MAIL_CLASS_PUBLIC, var_cleanup_service);
- post_mail_init(stream, sender, recipient, flags);
+ post_mail_init(stream, sender, recipient, cleanup_flags, trace_flags);
return (stream);
}
/* post_mail_fopen_nowait - prepare for posting a message */
VSTREAM *post_mail_fopen_nowait(const char *sender, const char *recipient,
- int flags)
+ int cleanup_flags, int trace_flags)
{
VSTREAM *stream;
if ((stream = mail_connect(MAIL_CLASS_PUBLIC, var_cleanup_service,
BLOCKING)) != 0)
- post_mail_init(stream, sender, recipient, flags);
+ post_mail_init(stream, sender, recipient, cleanup_flags, trace_flags);
+ return (stream);
+}
+
+/* post_mail_open_event - handle asynchronous connection events */
+
+static void post_mail_open_event(int event, char *context)
+{
+ POST_MAIL_STATE *state = (POST_MAIL_STATE *) context;
+ char *myname = "post_mail_open_event";
+
+ switch (event) {
+
+ /*
+ * Connection established. Request notification when the server sends
+ * the initial response. This intermediate case is necessary for some
+ * versions of LINUX and perhaps Solaris, where UNIX-domain
+ * connect(2) blocks until the server performs an accept(2).
+ */
+ case EVENT_WRITE:
+ if (msg_verbose)
+ msg_info("%s: write event", myname);
+ event_disable_readwrite(vstream_fileno(state->stream));
+ non_blocking(vstream_fileno(state->stream), BLOCKING);
+ event_enable_read(vstream_fileno(state->stream),
+ post_mail_open_event, (char *) state);
+ return;
+
+ /*
+ * Initial server reply. Stop the watchdog timer, disable further
+ * read events that end up calling this function, and notify the
+ * requestor.
+ */
+ case EVENT_READ:
+ if (msg_verbose)
+ msg_info("%s: read event", myname);
+ event_cancel_timer(post_mail_open_event, context);
+ event_disable_readwrite(vstream_fileno(state->stream));
+ post_mail_init(state->stream, state->sender,
+ state->recipient, state->cleanup_flags,
+ state->trace_flags);
+ state->notify(state->context);
+ myfree(state->sender);
+ myfree(state->recipient);
+ myfree((char *) state);
+ return;
+
+ /*
+ * No connection or no initial reply within a conservative time
+ * limit. The system is broken and we give up.
+ */
+ case EVENT_TIME:
+ msg_fatal("timeout connecting to service: %s", var_cleanup_service);
+
+ /*
+ * Broken software or hardware.
+ */
+ default:
+ msg_panic("%s: unknown event type %d", myname, event);
+ }
+}
+
+/* post_mail_fopen_async - prepare for posting a message */
+
+VSTREAM *post_mail_fopen_async(const char *sender, const char *recipient,
+ int cleanup_flags, int trace_flags,
+ void (*notify) (void *), void *context)
+{
+ VSTREAM *stream;
+ POST_MAIL_STATE *state;
+
+ stream = mail_connect(MAIL_CLASS_PUBLIC, var_cleanup_service, NON_BLOCKING);
+ if (stream != 0) {
+ state = (POST_MAIL_STATE *) mymalloc(sizeof(*state));
+ state->sender = mystrdup(sender);
+ state->recipient = mystrdup(recipient);
+ state->cleanup_flags = cleanup_flags;
+ state->trace_flags = trace_flags;
+ state->notify = notify;
+ state->context = context;
+ state->stream = stream;
+ event_enable_write(vstream_fileno(stream), post_mail_open_event,
+ (void *) state);
+ event_request_timer(post_mail_open_event, (void *) state,
+ var_daemon_timeout);
+ }
return (stream);
}
/*
* External interface.
*/
-extern VSTREAM *post_mail_fopen(const char *, const char *, int);
-extern VSTREAM *post_mail_fopen_nowait(const char *, const char *, int);
+typedef void (*POST_MAIL_NOTIFY)(void *);
+extern VSTREAM *post_mail_fopen(const char *, const char *, int, int);
+extern VSTREAM *post_mail_fopen_nowait(const char *, const char *, int, int);
+extern VSTREAM *post_mail_fopen_async(const char *, const char *, int, int, POST_MAIL_NOTIFY, void *);
extern int PRINTFLIKE(2, 3) post_mail_fprintf(VSTREAM *, const char *,...);
extern int post_mail_fputs(VSTREAM *, const char *);
extern int post_mail_buffer(VSTREAM *, const char *, int);
/* SYNOPSIS
/* #include <sent.h>
/*
-/* int sent(queue_id, orig_rcpt, recipient, relay, entry, format, ...)
+/* int sent(flags, queue_id, orig_rcpt, recipient, relay,
+/* entry, format, ...)
+/* int flags;
/* const char *queue_id;
/* const char *orig_rcpt;
/* const char *recipient;
/* time_t entry;
/* const char *format;
/*
-/* int vsent(queue_id, orig_rcpt, recipient, relay, entry, format, ap)
+/* int vsent(flags, queue_id, orig_rcpt, recipient, relay,
+/* entry, format, ap)
+/* int flags;
/* const char *queue_id;
/* const char *orig_rcpt;
/* const char *recipient;
/* const char *format;
/* va_list ap;
/* DESCRIPTION
-/* sent() logs that a message was successfully delivered.
+/* sent() logs that a message was successfully delivered,
+/* updates the address verification service, or updates a
+/* message delivery record on request by the sender. The
+/* flags argument determines the action.
/*
/* vsent() implements an alternative interface.
/*
/* Arguments:
+/* .IP flags
+/* Zero or more of the following:
+/* .RS
+/* .IP SENT_FLAG_NONE
+/* The message is a normal delivery request.
+/* .IP DEL_REQ_FLAG_VERIFY
+/* The message is an address verification probe. Update the
+/* address verification database.
+/* .IP DEL_REQ_FLAG_EXPAND
+/* The message is an address expansion probe. Update the
+/* message delivery record.
+/* .IP DEL_REQ_FLAG_RECORD
+/* This is a normal message with logged delivery. Update the
+/* the message delivery record.
+/* .RE
/* .IP queue_id
/* The message queue id.
/* .IP orig_rcpt
/* Message arrival time.
/* .IP format
/* Optional additional information.
-/* .PP
-/* For convenience, sent() always returns a zero result.
/* DIAGNOSTICS
+/* A non-zero result means the operation failed.
+/*
/* Fatal: out of memory.
/* BUGS
/* Should be replaced by routines with an attribute-value based
/* Global library. */
-#include "sent.h"
+#include <mail_params.h>
+#include <verify.h>
+#include <log_adhoc.h>
+#include <trace.h>
+#include <defer.h>
+#include <sent.h>
+
+/* Application-specific. */
/* sent - log that a message was sent */
-int sent(const char *queue_id, const char *orig_rcpt,
+int sent(int flags, const char *id, const char *orig_rcpt,
const char *recipient, const char *relay,
time_t entry, const char *fmt,...)
{
va_list ap;
+ int status;
va_start(ap, fmt);
- vsent(queue_id, orig_rcpt, recipient, relay, entry, fmt, ap);
+ status = vsent(flags, id, orig_rcpt, recipient, relay, entry, fmt, ap);
va_end(ap);
- return (0);
+ return (status);
}
/* vsent - log that a message was sent */
-int vsent(const char *queue_id, const char *orig_rcpt,
+int vsent(int flags, const char *id, const char *orig_rcpt,
const char *recipient, const char *relay,
time_t entry, const char *fmt, va_list ap)
{
-#define TEXT (vstring_str(text))
- VSTRING *text = vstring_alloc(100);
- int delay = time((time_t *) 0) - entry;
-
- vstring_vsprintf(text, fmt, ap);
- if (orig_rcpt && *orig_rcpt && strcasecmp(recipient, orig_rcpt) != 0)
- msg_info("%s: to=<%s>, orig_to=<%s>, relay=%s, delay=%d, status=sent%s%s%s",
- queue_id, recipient, orig_rcpt, relay, delay,
- *TEXT ? " (" : "", TEXT, *TEXT ? ")" : "");
- else
- msg_info("%s: to=<%s>, relay=%s, delay=%d, status=sent%s%s%s",
- queue_id, recipient, relay, delay,
- *TEXT ? " (" : "", TEXT, *TEXT ? ")" : "");
- vstring_free(text);
- return (0);
+ int status;
+
+ /*
+ * MTA-requested address verification information is stored in the verify
+ * service database.
+ */
+ if (flags & DEL_REQ_FLAG_VERIFY) {
+ status = vverify_append(id, orig_rcpt, recipient, relay, entry,
+ "deliverable", DEL_RCPT_STAT_OK, fmt, ap);
+ return (status);
+ }
+
+ /*
+ * User-requested address verification information is logged and mailed
+ * to the requesting user.
+ */
+ if (flags & DEL_REQ_FLAG_EXPAND) {
+ status = vtrace_append(flags, id, orig_rcpt, recipient, relay,
+ entry, "2.0.0", "deliverable", fmt, ap);
+ return (status);
+ }
+
+ /*
+ * Normal mail delivery. May also send a delivery record to the user.
+ */
+ else {
+ if ((flags & DEL_REQ_FLAG_RECORD) == 0
+ || vtrace_append(flags, id, orig_rcpt, recipient, relay,
+ entry, "2.0.0", "delivered", fmt, ap) == 0) {
+ vlog_adhoc(id, orig_rcpt, recipient, relay,
+ entry, "sent", fmt, ap);
+ status = 0;
+ } else {
+ status = defer_append(flags, id, orig_rcpt, recipient,
+ relay, entry, "%s: %s service failed",
+ id, var_trace_service);
+ }
+ return (status);
+ }
}
#include <time.h>
#include <stdarg.h>
+ /*
+ * Global library.
+ */
+#include <deliver_request.h>
+
/*
* External interface.
*/
-extern int PRINTFLIKE(6, 7) sent(const char *, const char *, const char *,
+#define SENT_FLAG_NONE (0)
+
+extern int PRINTFLIKE(7, 8) sent(int, const char *, const char *, const char *,
const char *, time_t, const char *,...);
-extern int vsent(const char *, const char *, const char *, const char *,
+extern int vsent(int, const char *, const char *, const char *, const char *,
time_t, const char *, va_list);
/* LICENSE
--- /dev/null
+/*++
+/* NAME
+/* trace 3
+/* SUMMARY
+/* user requested delivery tracing
+/* SYNOPSIS
+/* #include <trace.h>
+/*
+/* int trace_append(flags, queue_id, orig_rcpt, recipient, relay,
+/* entry, dsn_code, dsn_action, format, ...)
+/* int flags;
+/* const char *queue_id;
+/* const char *orig_rcpt;
+/* const char *recipient;
+/* const char *relay;
+/* time_t entry;
+/* const char *dsn_code;
+/* const char *dsn_action;
+/* const char *format;
+/*
+/* int vtrace_append(flags, queue_id, orig_rcpt, recipient, relay,
+/* entry, dsn_code, dsn_action, format, ap)
+/* int flags;
+/* const char *queue_id;
+/* const char *orig_rcpt;
+/* const char *recipient;
+/* const char *relay;
+/* time_t entry;
+/* const char *dsn_code;
+/* const char *dsn_action;
+/* const char *format;
+/* va_list ap;
+/*
+/* int trace_flush(flags, queue, id, encoding, sender)
+/* int flags;
+/* const char *queue;
+/* const char *id;
+/* const char *encoding;
+/* const char *sender;
+/* DESCRIPTION
+/* trace_append() updates the message delivery record that is
+/* mailed back to the originator. In case of a trace-only
+/* message, the recipient status is also written to the
+/* mailer logfile.
+/*
+/* vtrace_append() implements an alternative interface.
+/*
+/* trace_flush() returns the specified message to the specified
+/* sender, including the message delivery record log that was built
+/* with vtrace_append().
+/*
+/* Arguments:
+/* .IP flags
+/* The bitwise OR of zero or more of the following (specify
+/* BOUNCE_FLAG_NONE to request no special processing):
+/* .RS
+/* .IP BOUNCE_FLAG_CLEAN
+/* Delete the logfile in case of an error (as in: pretend
+/* that we never even tried to deliver this message).
+/* .RE
+/* .IP queue_id
+/* The message queue id.
+/* .IP orig_rcpt
+/* The original envelope recipient address. If unavailable,
+/* specify a null string or a null pointer.
+/* .IP recipient
+/* The recipient address.
+/* .IP relay
+/* The host we sent the mail to.
+/* .IP entry
+/* Message arrival time.
+/* .IP dsn_code
+/* three-digit dot-separated code.
+/* .IP dsn_action
+/* "deliverable", "undeliverable", and so on.
+/* .IP format
+/* Optional additional information.
+/* DIAGNOSTICS
+/* A non-zero result means the operation failed.
+/*
+/* Fatal: out of memory.
+/* BUGS
+/* Should be replaced by routines with an attribute-value based
+/* interface instead of an interface that uses a rigid argument list.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <stdio.h>
+#include <stdlib.h> /* 44BSD stdarg.h uses abort() */
+#include <stdarg.h>
+#include <string.h>
+
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
+/* Utility library. */
+
+#include <msg.h>
+#include <vstring.h>
+
+/* Global library. */
+
+#include <mail_params.h>
+#include <mail_proto.h>
+#include <verify_clnt.h>
+#include <log_adhoc.h>
+#include <bounce.h>
+#include <trace.h>
+
+/* trace_append - append to message delivery record */
+
+int trace_append(int flags, const char *queue_id,
+ const char *orig_rcpt, const char *recipient,
+ const char *relay, time_t entry,
+ const char *dsn_code, const char *dsn_action,
+ const char *fmt,...)
+{
+ va_list ap;
+ int req_stat;
+
+ va_start(ap, fmt);
+ req_stat = vtrace_append(flags, queue_id, orig_rcpt, recipient,
+ relay, entry, dsn_code, dsn_action, fmt, ap);
+ va_end(ap);
+ return (req_stat);
+}
+
+/* vtrace_append - append to message delivery record */
+
+int vtrace_append(int flags, const char *queue_id,
+ const char *orig_rcpt, const char *recipient,
+ const char *relay, time_t entry,
+ const char *dsn_code, const char *dsn_action,
+ const char *fmt, va_list ap)
+{
+ VSTRING *why = vstring_alloc(100);
+ int req_stat;
+
+ /*
+ * User-requested address verification or verbose delivery. Mail the
+ * report to the requesting user.
+ */
+ vstring_sprintf(why, "delivery via %s: ", relay);
+ vstring_vsprintf_append(why, fmt, ap);
+
+ if (orig_rcpt == 0)
+ orig_rcpt = "";
+ if (mail_command_client(MAIL_CLASS_PRIVATE, var_trace_service,
+ ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_APPEND,
+ ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+ ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
+ ATTR_TYPE_STR, MAIL_ATTR_ORCPT, orig_rcpt,
+ ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient,
+ ATTR_TYPE_STR, MAIL_ATTR_STATUS, dsn_code,
+ ATTR_TYPE_STR, MAIL_ATTR_ACTION, dsn_action,
+ ATTR_TYPE_STR, MAIL_ATTR_WHY, vstring_str(why),
+ ATTR_TYPE_END) != 0) {
+ msg_warn("%s: %s service failure", queue_id, var_trace_service);
+ req_stat = -1;
+ } else {
+ if (flags & DEL_REQ_FLAG_EXPAND)
+ vlog_adhoc(queue_id, orig_rcpt, recipient, relay,
+ entry, dsn_action, fmt, ap);
+ req_stat = 0;
+ }
+ vstring_free(why);
+ return (req_stat);
+}
+
+/* trace_flush - deliver delivery record to the sender */
+
+int trace_flush(int flags, const char *queue, const char *id,
+ const char *encoding, const char *sender)
+{
+ if (mail_command_client(MAIL_CLASS_PRIVATE, var_trace_service,
+ ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_TRACE,
+ ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+ ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue,
+ ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
+ ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
+ ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
+ ATTR_TYPE_END) == 0) {
+ return (0);
+ } else {
+ return (-1);
+ }
+}
--- /dev/null
+#ifndef _TRACE_H_INCLUDED_
+#define _TRACE_H_INCLUDED_
+
+/*++
+/* NAME
+/* trace 3h
+/* SUMMARY
+/* update user message delivery record
+/* SYNOPSIS
+/* #include <trace.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * System library.
+ */
+#include <time.h>
+#include <stdarg.h>
+
+ /*
+ * Global library.
+ */
+#include <deliver_request.h>
+
+ /*
+ * External interface.
+ */
+extern int PRINTFLIKE(9, 10) trace_append(int, const char *,
+ const char *, const char *,
+ const char *, time_t,
+ const char *, const char *,
+ const char *,...);
+extern int vtrace_append(int, const char *,
+ const char *, const char *,
+ const char *, time_t,
+ const char *, const char *,
+ const char *, va_list);
+extern int trace_flush(int, const char *, const char *, const char *, const char *);
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+#endif
--- /dev/null
+/*++
+/* NAME
+/* verify 3
+/* SUMMARY
+/* update verify database
+/* SYNOPSIS
+/* #include <verify.h>
+/*
+/* int verify_append(queue_id, orig_rcpt, recipient,
+/* relay, entry, status,
+/* recipient_status, format, ...)
+/* const char *queue_id;
+/* const char *orig_rcpt;
+/* const char *recipient;
+/* const char *relay;
+/* time_t entry;
+/* const char *status;
+/* int recipient_status;
+/* const char *format;
+/*
+/* int vverify_append(queue_id, orig_rcpt, recipient,
+/* relay, entry, status,
+/* recipient_status, format, ap)
+/* int recipient_status;
+/* const char *queue_id;
+/* const char *orig_rcpt;
+/* const char *recipient;
+/* const char *relay;
+/* time_t entry;
+/* const char *status;
+/* int recipient_status;
+/* const char *format;
+/* va_list ap;
+/* DESCRIPTION
+/* This module implements an impedance adaptor between the
+/* verify_clnt interface and the interface expected by the
+/* bounce/defer/sent modules.
+/*
+/* verify_append() updates the address verification database
+/* and logs the action to the mailer logfile.
+/*
+/* vverify_append() implements an alternative interface.
+/*
+/* Arguments:
+/* .IP queue_id
+/* The message queue id.
+/* .IP orig_rcpt
+/* The original envelope recipient address. If unavailable,
+/* specify a null string or a null pointer.
+/* .IP recipient
+/* The recipient address.
+/* .IP relay
+/* Name of the host we're talking to.
+/* .IP entry
+/* Message arrival time.
+/* .IP status
+/* "deliverable", "undeliverable", and so on.
+/* .IP recipient_status
+/* One of the following recipient verification status codes:
+/* .RS
+/* .IP DEL_REQ_RCPT_STAT_OK
+/* Successful delivery.
+/* .IP DEL_REQ_RCPT_STAT_DEFER
+/* Temporary delivery error.
+/* .IP DEL_REQ_RCPT_STAT_BOUNCE
+/* Hard delivery error.
+/* .RE
+/* .IP format
+/* Optional additional information.
+/* DIAGNOSTICS
+/* A non-zero result means the operation failed.
+/*
+/* Fatal: out of memory.
+/* BUGS
+/* Should be replaced by routines with an attribute-value based
+/* interface instead of an interface that uses a rigid argument list.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <stdio.h>
+#include <stdlib.h> /* 44BSD stdarg.h uses abort() */
+#include <stdarg.h>
+#include <string.h>
+
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
+/* Utility library. */
+
+#include <msg.h>
+#include <vstring.h>
+
+/* Global library. */
+
+#include <mail_params.h>
+#include <mail_proto.h>
+#include <verify_clnt.h>
+#include <log_adhoc.h>
+#include <verify.h>
+
+/* verify_append - update address verification database */
+
+int verify_append(const char *queue_id, const char *orig_rcpt,
+ const char *recipient, const char *relay,
+ time_t entry, const char *status,
+ int rcpt_stat, const char *fmt,...)
+{
+ va_list ap;
+ int req_stat;
+
+ va_start(ap, fmt);
+ req_stat = vverify_append(queue_id, orig_rcpt, recipient, relay,
+ entry, status, rcpt_stat, fmt, ap);
+ va_end(ap);
+ return (req_stat);
+}
+
+/* vverify_append - update address verification database */
+
+int vverify_append(const char *queue_id, const char *orig_rcpt,
+ const char *recipient, const char *relay,
+ time_t entry, const char *status,
+ int rcpt_stat, const char *fmt, va_list ap)
+{
+ int req_stat;
+
+ /*
+ * Impedance adaptor between bounce/defer/sent and verify_clnt.
+ */
+ if (var_verify_neg_cache || rcpt_stat == DEL_RCPT_STAT_OK) {
+ req_stat = verify_clnt_vupdate(orig_rcpt, rcpt_stat, fmt, ap);
+ if (req_stat == VRFY_STAT_OK && strcasecmp(recipient, orig_rcpt) != 0)
+ req_stat = verify_clnt_vupdate(recipient, rcpt_stat, fmt, ap);
+ } else {
+ status = "undeliverable-but-not-cached";
+ req_stat = VRFY_STAT_OK;
+ }
+ if (req_stat == VRFY_STAT_OK) {
+ vlog_adhoc(queue_id, orig_rcpt, recipient, relay,
+ entry, status, fmt, ap);
+ req_stat = 0;
+ } else {
+ msg_warn("%s: %s service failure", queue_id, var_verify_service);
+ req_stat = -1;
+ }
+ return (req_stat);
+}
--- /dev/null
+#ifndef _VERIFY_H_INCLUDED_
+#define _VERIFY_H_INCLUDED_
+
+/*++
+/* NAME
+/* verify 3h
+/* SUMMARY
+/* update user message delivery record
+/* SYNOPSIS
+/* #include <verify.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * System library.
+ */
+#include <time.h>
+#include <stdarg.h>
+
+ /*
+ * Global library.
+ */
+#include <deliver_request.h>
+
+ /*
+ * External interface.
+ */
+extern int PRINTFLIKE(8, 9) verify_append(const char *, const char *,
+ const char *, const char *,
+ time_t, const char *,
+ int, const char *,...);
+extern int vverify_append(const char *, const char *,
+ const char *, const char *,
+ time_t, const char *,
+ int, const char *, va_list);
+
+/* 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
+/* verify_clnt 3
+/* SUMMARY
+/* address verification client interface
+/* SYNOPSIS
+/* #include <verify_clnt.h>
+/*
+/* int verify_clnt_query(addr, status, why)
+/* const char *addr;
+/* int *status;
+/* VSTRING *why;
+/*
+/* int verify_clnt_update(addr, status, format, ...)
+/* const char *addr;
+/* int status;
+/* const char *format;
+/*
+/* int verify_clnt_vupdate(addr, status, format, ap)
+/* const char *addr;
+/* int status;
+/* const char *format;
+/* va_list ap;
+/* DESCRIPTION
+/* verify_clnt_query() requests information about the given address.
+/* The result value is one of the valud status values (see
+/* status description below).
+/* In all cases the \fBwhy\fR argument provides additional
+/* information.
+/*
+/* verify_clnt_update() requests that the status of the specified
+/* address be updated. The result status is DEL_REQ_RCPT_STAT_OK upon
+/* success, DEL_REQ_RCPT_STAT_DEFER upon failure.
+/*
+/* verify_clnt_vupdate() presents the function of verify_clnt_update()
+/* with a different user interface.
+/*
+/* Arguments
+/* .IP addr
+/* The email address in question.
+/* .IP status
+/* One of the following status codes:
+/* .RS
+/* .IP DEL_REQ_RCPT_STAT_OK
+/* The mail system did not detect any problems.
+/* .IP DEL_REQ_RCPT_STAT_DEFER
+/* The status of the address is indeterminate.
+/* .IP DEL_REQ_RCPT_STAT_BOUNCE
+/* The address is permanently undeliverable.
+/* .RE
+/* .IP why
+/* textual description of the status.
+/* DIAGNOSTICS
+/* These functions return VRFY_STAT_OK in case of success,
+/* VRFY_STAT_BAD in case of a malformed request, and
+/* VRFY_STAT_FAIL when the operation failed.
+/* SEE ALSO
+/* verify(8) Postfix address verification server
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <unistd.h>
+#include <errno.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <vstream.h>
+#include <vstring.h>
+#include <attr.h>
+
+/* Global library. */
+
+#include <mail_params.h>
+#include <mail_proto.h>
+#include <clnt_stream.h>
+#include <verify_clnt.h>
+
+CLNT_STREAM *vrfy_clnt;
+
+/* verify_clnt_init - initialize */
+
+static void verify_clnt_init(void)
+{
+ if (vrfy_clnt != 0)
+ msg_panic("verify_clnt_init: multiple initialization");
+ vrfy_clnt = clnt_stream_create(MAIL_CLASS_PRIVATE, var_verify_service,
+ var_ipc_idle_limit);
+}
+
+/* verify_clnt_query - request address verification status */
+
+int verify_clnt_query(const char *addr, int *addr_status, VSTRING *why)
+{
+ VSTREAM *stream;
+ int request_status;
+
+ /*
+ * Do client-server plumbing.
+ */
+ if (vrfy_clnt == 0)
+ verify_clnt_init();
+
+ /*
+ * Request status for this address.
+ */
+ for (;;) {
+ stream = clnt_stream_access(vrfy_clnt);
+ if (attr_print(stream, ATTR_FLAG_NONE,
+ ATTR_TYPE_STR, MAIL_ATTR_REQ, VRFY_REQ_QUERY,
+ ATTR_TYPE_STR, MAIL_ATTR_ADDR, addr,
+ ATTR_TYPE_END) != 0
+ || vstream_fflush(stream)) {
+ if (msg_verbose || (errno != EPIPE && errno != ENOENT)) {
+ msg_warn("service %s: bad write: %m", var_verify_service);
+ sleep(10); /* XXX make configurable */
+ }
+ } else if (attr_scan(stream, ATTR_FLAG_MISSING,
+ ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &request_status,
+ ATTR_TYPE_NUM, MAIL_ATTR_ADDR_STATUS, addr_status,
+ ATTR_TYPE_STR, MAIL_ATTR_WHY, why,
+ ATTR_TYPE_END) != 3) {
+ if (msg_verbose || (errno != EPIPE && errno != ENOENT)) {
+ msg_warn("service %s: bad read: %m", var_verify_service);
+ sleep(10); /* XXX make configurable */
+ }
+ } else {
+ break;
+ }
+ sleep(1);
+ clnt_stream_recover(vrfy_clnt);
+ }
+ return (request_status);
+}
+
+/* verify_clnt_update - request address status update */
+
+int verify_clnt_update(const char *addr, int addr_status,
+ const char *format,...)
+{
+ va_list ap;
+ int status;
+
+ va_start(ap, format);
+ status = verify_clnt_vupdate(addr, addr_status, format, ap);
+ va_end(ap);
+ return (status);
+}
+
+/* verify_clnt_update - request address status update */
+
+int verify_clnt_vupdate(const char *addr, int addr_status,
+ const char *format, va_list ap)
+{
+ VSTRING *text;
+ VSTREAM *stream;
+ int request_status;
+
+ /*
+ * Do client-server plumbing.
+ */
+ if (vrfy_clnt == 0)
+ verify_clnt_init();
+
+ /*
+ * Send status for this address. Supply a default status if the address
+ * verification service is unavailable.
+ */
+ text = vstring_alloc(100);
+ vstring_vsprintf(text, format, ap);
+ for (;;) {
+ stream = clnt_stream_access(vrfy_clnt);
+ if (attr_print(stream, ATTR_FLAG_NONE,
+ ATTR_TYPE_STR, MAIL_ATTR_REQ, VRFY_REQ_UPDATE,
+ ATTR_TYPE_STR, MAIL_ATTR_ADDR, addr,
+ ATTR_TYPE_NUM, MAIL_ATTR_ADDR_STATUS, addr_status,
+ ATTR_TYPE_STR, MAIL_ATTR_WHY, vstring_str(text),
+ ATTR_TYPE_END) != 0
+ || vstream_fflush(stream)) {
+ if (msg_verbose || (errno != EPIPE && errno != ENOENT)) {
+ msg_warn("service %s: bad write: %m", var_verify_service);
+ msg_warn("service %s: bad write: %m", var_verify_service);
+ sleep(10); /* XXX make configurable */
+ }
+ } else if (attr_scan(stream, ATTR_FLAG_MISSING,
+ ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &request_status,
+ ATTR_TYPE_END) != 1) {
+ if (msg_verbose || (errno != EPIPE && errno != ENOENT)) {
+ msg_warn("service %s: bad read: %m", var_verify_service);
+ sleep(10); /* XXX make configurable */
+ }
+ } else {
+ break;
+ }
+ sleep(1);
+ clnt_stream_recover(vrfy_clnt);
+ }
+ vstring_free(text);
+ return (request_status);
+}
+
+ /*
+ * Proof-of-concept test client program.
+ */
+#ifdef TEST
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <msg_vstream.h>
+#include <stringops.h>
+#include <vstring_vstream.h>
+#include <mail_conf.h>
+
+#define STR(x) vstring_str(x)
+
+static NORETURN usage(char *myname)
+{
+ msg_fatal("usage: %s [-v]", myname);
+}
+
+static void query(char *query, VSTRING *buf)
+{
+ int status;
+
+ switch (verify_clnt_query(query, &status, buf)) {
+ case VRFY_STAT_OK:
+ vstream_printf("%-10s %d\n", "status", status);
+ vstream_printf("%-10s %s\n", "text", STR(buf));
+ vstream_fflush(VSTREAM_OUT);
+ break;
+ case VRFY_STAT_BAD:
+ msg_warn("bad request format");
+ break;
+ case VRFY_STAT_FAIL:
+ msg_warn("request failed");
+ break;
+ }
+}
+
+static void update(char *query)
+{
+ char *addr;
+ char *status_text;
+ char *cp = query;
+
+ if ((addr = mystrtok(&cp, " \t\r\n")) == 0
+ || (status_text = mystrtok(&cp, " \t\r\n")) == 0) {
+ msg_warn("bad request format");
+ return;
+ }
+ while (*cp && ISSPACE(*cp))
+ cp++;
+ if (*cp == 0) {
+ msg_warn("bad request format");
+ return;
+ }
+ switch (verify_clnt_update(query, atoi(status_text), cp)) {
+ case VRFY_STAT_OK:
+ vstream_printf("OK\n");
+ vstream_fflush(VSTREAM_OUT);
+ break;
+ case VRFY_STAT_BAD:
+ msg_warn("bad request format");
+ break;
+ case VRFY_STAT_FAIL:
+ msg_warn("request failed");
+ break;
+ }
+}
+
+int main(int argc, char **argv)
+{
+ VSTRING *buffer = vstring_alloc(1);
+ char *cp;
+ int ch;
+ char *command;
+
+ signal(SIGPIPE, SIG_IGN);
+
+ msg_vstream_init(argv[0], VSTREAM_ERR);
+
+ mail_conf_read();
+ msg_info("using config files in %s", var_config_dir);
+ if (chdir(var_queue_dir) < 0)
+ msg_fatal("chdir %s: %m", var_queue_dir);
+
+ while ((ch = GETOPT(argc, argv, "v")) > 0) {
+ switch (ch) {
+ case 'v':
+ msg_verbose++;
+ break;
+ default:
+ usage(argv[0]);
+ }
+ }
+ if (argc - optind > 1)
+ usage(argv[0]);
+
+ while (vstring_fgets_nonl(buffer, VSTREAM_IN)) {
+ cp = STR(buffer);
+ if ((command = mystrtok(&cp, " \t\r\n")) == 0)
+ continue;
+ if (strcmp(command, "query") == 0)
+ query(cp, buffer);
+ else if (strcmp(command, "update") == 0)
+ update(cp);
+ else
+ msg_warn("unrecognized command: %s", command);
+ }
+ vstring_free(buffer);
+}
+
+#endif
--- /dev/null
+#ifndef _VRFY_STAT_H_INCLUDED_
+#define _VRFY_STAT_H_INCLUDED_
+
+/*++
+/* NAME
+/* mail_proto 3h
+/* SUMMARY
+/* mail internal IPC support
+/* SYNOPSIS
+/* #include <mail_proto.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * System library.
+ */
+#include <stdarg.h>
+
+ /*
+ * Global library.
+ */
+#include <deliver_request.h>
+
+ /*
+ * Address verification requests.
+ */
+#define VRFY_REQ_QUERY "query"
+#define VRFY_REQ_UPDATE "update"
+
+ /*
+ * Request (NOT: address) status codes.
+ */
+#define VRFY_STAT_OK 0
+#define VRFY_STAT_FAIL (-1)
+#define VRFY_STAT_BAD (-2)
+
+ /*
+ * Functional interface.
+ */
+extern int verify_clnt_query(const char *, int *, VSTRING *);
+extern int PRINTFLIKE(3, 4) verify_clnt_update(const char *, int, const char *,...);
+extern int verify_clnt_vupdate(const char *, int, const char *, va_list);
+
+/* 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
* generate from untrusted data.
*/
#define NULL_CLEANUP_FLAGS 0
+#define NULL_TRACE_FLAGS 0
#define LENGTH 78
#define INDENT 4
notice = post_mail_fopen_nowait(mail_addr_double_bounce(),
var_error_rcpt,
- NULL_CLEANUP_FLAGS);
+ NULL_CLEANUP_FLAGS,
+ NULL_TRACE_FLAGS);
if (notice == 0) {
msg_warn("postmaster notify: %m");
return;
"RCPT TO command",
"DATA command",
"end of DATA command",
- "final RSET command",
+ "RSET command",
+ "RSET command",
"QUIT command",
};
vstring_sprintf(next_command, "RCPT TO:<%s>",
vstring_str(state->scratch));
if ((next_rcpt = send_rcpt + 1) == request->rcpt_list.len)
- next_state = LMTP_STATE_DATA;
+ next_state = DEL_REQ_TRACE_ONLY(request->flags) ?
+ LMTP_STATE_ABORT : LMTP_STATE_DATA;
break;
/*
msg_panic("%s: sender abort state", myname);
/*
- * Build the RSET command. This command does not really belong
- * here because it is always sent without pipelining, but having
- * it here means that we can reuse a lot of error handling code
- * that already exists.
+ * Build the RSET command. This is used between pipelined
+ * deliveries, and to abort a trace-only delivery request.
*/
case LMTP_STATE_RSET:
vstring_strcpy(next_command, "RSET");
mymalloc(request->rcpt_list.len
* sizeof(int));
survivors[nrcpt++] = recv_rcpt;
+ /* If trace-only, mark the recipient done. */
+ if (DEL_REQ_TRACE_ONLY(request->flags)
+ && sent(DEL_REQ_TRACE_FLAGS(request->flags),
+ request->queue_id, rcpt->orig_addr,
+ rcpt->address, session->namaddr,
+ request->arrival_time, "%s",
+ translit(resp->str, "\n", " ")) == 0) {
+ if (request->flags & DEL_REQ_FLAG_SUCCESS)
+ deliver_completed(state->src, rcpt->offset);
+ rcpt->offset = 0; /* in case deferred */
+ }
} else {
lmtp_rcpt_fail(state, resp->code, rcpt,
"host %s said: %s (in reply to %s)",
rcpt->offset = 0; /* in case deferred */
}
}
+ /* If trace-only, send RSET instead of DATA. */
if (++recv_rcpt == request->rcpt_list.len)
- recv_state = LMTP_STATE_DATA;
+ recv_state = DEL_REQ_TRACE_ONLY(request->flags) ?
+ LMTP_STATE_ABORT : LMTP_STATE_DATA;
break;
/*
rcpt = request->rcpt_list.info + survivors[recv_dot];
if (resp->code / 100 == 2) {
if (rcpt->offset) {
- sent(request->queue_id, rcpt->orig_addr,
- rcpt->address, session->namaddr,
- request->arrival_time, "%s", resp->str);
- if (request->flags & DEL_REQ_FLAG_SUCCESS)
- deliver_completed(state->src, rcpt->offset);
- rcpt->offset = 0;
+ if (sent(DEL_REQ_TRACE_FLAGS(request->flags),
+ request->queue_id, rcpt->orig_addr,
+ rcpt->address, session->namaddr,
+ request->arrival_time,
+ "%s", resp->str) == 0) {
+ if (request->flags & DEL_REQ_FLAG_SUCCESS)
+ deliver_completed(state->src, rcpt->offset);
+ rcpt->offset = 0;
+ }
}
} else {
lmtp_rcpt_fail(state, resp->code, rcpt,
#define LMTP_SOFT(code) (((code) / 100) == 4)
#define LMTP_HARD(code) (((code) / 100) == 5)
-#define KEEP BOUNCE_FLAG_KEEP
/* lmtp_check_code - check response code */
if (rcpt->offset == 0)
continue;
status = (soft_error ? defer_append : bounce_append)
- (KEEP, request->queue_id, rcpt->orig_addr, rcpt->address,
+ (DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
+ rcpt->orig_addr, rcpt->address,
session ? session->namaddr : "none",
request->arrival_time, "%s", vstring_str(why));
if (status == 0) {
if (rcpt->offset == 0)
continue;
status = (LMTP_SOFT(code) ? defer_append : bounce_append)
- (KEEP, request->queue_id, rcpt->orig_addr, rcpt->address,
+ (DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
+ rcpt->orig_addr, rcpt->address,
session->namaddr, request->arrival_time,
"%s", vstring_str(why));
if (status == 0) {
*/
va_start(ap, format);
status = (LMTP_SOFT(code) ? vdefer_append : vbounce_append)
- (KEEP, request->queue_id, rcpt->orig_addr, rcpt->address,
+ (DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
+ rcpt->orig_addr, rcpt->address,
session->namaddr, request->arrival_time, format, ap);
va_end(ap);
if (status == 0) {
rcpt = request->rcpt_list.info + nrcpt;
if (rcpt->offset == 0)
continue;
- state->status |= defer_append(KEEP, request->queue_id,
+ state->status |= defer_append(DEL_REQ_TRACE_FLAGS(request->flags),
+ request->queue_id,
rcpt->orig_addr, rcpt->address,
session->namaddr,
request->arrival_time,
alias.o: ../../include/mail_params.h
alias.o: ../../include/defer.h
alias.o: ../../include/bounce.h
+alias.o: ../../include/deliver_request.h
+alias.o: ../../include/recipient_list.h
alias.o: ../../include/maps.h
alias.o: ../../include/mypwd.h
alias.o: ../../include/canon_addr.h
+alias.o: ../../include/sent.h
alias.o: local.h
alias.o: ../../include/been_here.h
alias.o: ../../include/tok822.h
alias.o: ../../include/resolve_clnt.h
-alias.o: ../../include/deliver_request.h
-alias.o: ../../include/recipient_list.h
alias.o: ../../include/mbox_conf.h
biff_notify.o: biff_notify.c
biff_notify.o: ../../include/sys_defs.h
command.o: ../../include/argv.h
command.o: ../../include/defer.h
command.o: ../../include/bounce.h
+command.o: ../../include/deliver_request.h
+command.o: ../../include/recipient_list.h
command.o: ../../include/sent.h
command.o: ../../include/been_here.h
command.o: ../../include/mail_params.h
command.o: local.h
command.o: ../../include/tok822.h
command.o: ../../include/resolve_clnt.h
-command.o: ../../include/deliver_request.h
-command.o: ../../include/recipient_list.h
command.o: ../../include/mbox_conf.h
command.o: ../../include/maps.h
command.o: ../../include/dict.h
dotforward.o: ../../include/mac_parse.h
dotforward.o: ../../include/mypwd.h
dotforward.o: ../../include/bounce.h
+dotforward.o: ../../include/deliver_request.h
+dotforward.o: ../../include/recipient_list.h
dotforward.o: ../../include/been_here.h
dotforward.o: ../../include/mail_params.h
dotforward.o: ../../include/mail_conf.h
dotforward.o: ../../include/ext_prop.h
+dotforward.o: ../../include/sent.h
dotforward.o: local.h
dotforward.o: ../../include/tok822.h
dotforward.o: ../../include/resolve_clnt.h
-dotforward.o: ../../include/deliver_request.h
-dotforward.o: ../../include/recipient_list.h
dotforward.o: ../../include/mbox_conf.h
dotforward.o: ../../include/argv.h
dotforward.o: ../../include/maps.h
file.o: ../../include/set_eugid.h
file.o: ../../include/mail_copy.h
file.o: ../../include/bounce.h
+file.o: ../../include/deliver_request.h
+file.o: ../../include/recipient_list.h
file.o: ../../include/defer.h
file.o: ../../include/sent.h
file.o: ../../include/been_here.h
file.o: local.h
file.o: ../../include/tok822.h
file.o: ../../include/resolve_clnt.h
-file.o: ../../include/deliver_request.h
-file.o: ../../include/recipient_list.h
file.o: ../../include/maps.h
file.o: ../../include/dict.h
forward.o: forward.c
forward.o: ../../include/attr.h
forward.o: ../../include/cleanup_user.h
forward.o: ../../include/sent.h
+forward.o: ../../include/deliver_request.h
+forward.o: ../../include/recipient_list.h
forward.o: ../../include/record.h
forward.o: ../../include/rec_type.h
forward.o: ../../include/mark_corrupt.h
forward.o: ../../include/been_here.h
forward.o: ../../include/tok822.h
forward.o: ../../include/resolve_clnt.h
-forward.o: ../../include/deliver_request.h
-forward.o: ../../include/recipient_list.h
forward.o: ../../include/mbox_conf.h
forward.o: ../../include/maps.h
forward.o: ../../include/dict.h
include.o: ../../include/iostuff.h
include.o: ../../include/mypwd.h
include.o: ../../include/bounce.h
+include.o: ../../include/deliver_request.h
+include.o: ../../include/vstring.h
+include.o: ../../include/recipient_list.h
include.o: ../../include/defer.h
include.o: ../../include/been_here.h
include.o: ../../include/mail_params.h
include.o: ../../include/ext_prop.h
+include.o: ../../include/sent.h
include.o: local.h
-include.o: ../../include/vstring.h
include.o: ../../include/tok822.h
include.o: ../../include/resolve_clnt.h
-include.o: ../../include/deliver_request.h
-include.o: ../../include/recipient_list.h
include.o: ../../include/mbox_conf.h
include.o: ../../include/argv.h
include.o: ../../include/maps.h
indirect.o: ../../include/htable.h
indirect.o: ../../include/mail_params.h
indirect.o: ../../include/bounce.h
+indirect.o: ../../include/deliver_request.h
+indirect.o: ../../include/vstring.h
+indirect.o: ../../include/vbuf.h
+indirect.o: ../../include/vstream.h
+indirect.o: ../../include/recipient_list.h
indirect.o: ../../include/defer.h
indirect.o: ../../include/been_here.h
+indirect.o: ../../include/sent.h
indirect.o: local.h
-indirect.o: ../../include/vstream.h
-indirect.o: ../../include/vbuf.h
-indirect.o: ../../include/vstring.h
indirect.o: ../../include/tok822.h
indirect.o: ../../include/resolve_clnt.h
-indirect.o: ../../include/deliver_request.h
-indirect.o: ../../include/recipient_list.h
indirect.o: ../../include/mbox_conf.h
indirect.o: ../../include/argv.h
indirect.o: ../../include/maps.h
mailbox.o: ../../include/mail_copy.h
mailbox.o: ../../include/defer.h
mailbox.o: ../../include/bounce.h
+mailbox.o: ../../include/deliver_request.h
+mailbox.o: ../../include/recipient_list.h
mailbox.o: ../../include/sent.h
mailbox.o: ../../include/mypwd.h
mailbox.o: ../../include/been_here.h
mailbox.o: ../../include/mail_params.h
mailbox.o: ../../include/deliver_pass.h
-mailbox.o: ../../include/deliver_request.h
-mailbox.o: ../../include/recipient_list.h
mailbox.o: ../../include/mail_proto.h
mailbox.o: ../../include/iostuff.h
mailbox.o: ../../include/attr.h
maildir.o: ../../include/sane_fsops.h
maildir.o: ../../include/mail_copy.h
maildir.o: ../../include/bounce.h
+maildir.o: ../../include/deliver_request.h
+maildir.o: ../../include/recipient_list.h
maildir.o: ../../include/defer.h
maildir.o: ../../include/sent.h
maildir.o: ../../include/mail_params.h
maildir.o: ../../include/been_here.h
maildir.o: ../../include/tok822.h
maildir.o: ../../include/resolve_clnt.h
-maildir.o: ../../include/deliver_request.h
-maildir.o: ../../include/recipient_list.h
maildir.o: ../../include/mbox_conf.h
maildir.o: ../../include/argv.h
maildir.o: ../../include/maps.h
recipient.o: ../../include/argv.h
recipient.o: ../../include/stat_as.h
recipient.o: ../../include/bounce.h
+recipient.o: ../../include/deliver_request.h
+recipient.o: ../../include/recipient_list.h
recipient.o: ../../include/defer.h
recipient.o: ../../include/mail_params.h
recipient.o: ../../include/split_addr.h
recipient.o: ../../include/been_here.h
recipient.o: ../../include/tok822.h
recipient.o: ../../include/resolve_clnt.h
-recipient.o: ../../include/deliver_request.h
-recipient.o: ../../include/recipient_list.h
recipient.o: ../../include/mbox_conf.h
recipient.o: ../../include/maps.h
resolve.o: resolve.c
resolve.o: ../../include/mail_params.h
resolve.o: ../../include/defer.h
resolve.o: ../../include/bounce.h
-resolve.o: local.h
-resolve.o: ../../include/been_here.h
resolve.o: ../../include/deliver_request.h
resolve.o: ../../include/recipient_list.h
+resolve.o: local.h
+resolve.o: ../../include/been_here.h
resolve.o: ../../include/mbox_conf.h
resolve.o: ../../include/argv.h
resolve.o: ../../include/maps.h
token.o: ../../include/resolve_clnt.h
token.o: ../../include/mail_params.h
token.o: ../../include/bounce.h
-token.o: local.h
-token.o: ../../include/been_here.h
token.o: ../../include/deliver_request.h
token.o: ../../include/recipient_list.h
+token.o: local.h
+token.o: ../../include/been_here.h
token.o: ../../include/mbox_conf.h
token.o: ../../include/argv.h
token.o: ../../include/maps.h
unknown.o: ../../include/iostuff.h
unknown.o: ../../include/attr.h
unknown.o: ../../include/bounce.h
+unknown.o: ../../include/deliver_request.h
+unknown.o: ../../include/recipient_list.h
unknown.o: ../../include/mail_addr.h
unknown.o: ../../include/sent.h
unknown.o: local.h
unknown.o: ../../include/htable.h
unknown.o: ../../include/tok822.h
unknown.o: ../../include/resolve_clnt.h
-unknown.o: ../../include/deliver_request.h
-unknown.o: ../../include/recipient_list.h
unknown.o: ../../include/mbox_conf.h
unknown.o: ../../include/argv.h
unknown.o: ../../include/maps.h
#include <bounce.h>
#include <mypwd.h>
#include <canon_addr.h>
+#include <sent.h>
/* Application-specific. */
return (NO);
if (state.level > 100) {
msg_warn("possible alias database loop for %s", name);
- *statusp = bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+ *statusp = bounce_append(BOUNCE_FLAGS(state.request),
+ BOUNCE_ATTR(state.msg_attr),
"possible alias database loop for %s", name);
return (YES);
}
if (msg_verbose)
msg_info("%s: %s: %s = %s", myname, *cpp, name, alias_result);
+ /*
+ * Don't expand a verify-only request.
+ */
+ if (state.request->flags & DEL_REQ_FLAG_VERIFY) {
+ *statusp = sent(BOUNCE_FLAGS(state.request),
+ SENT_ATTR(state.msg_attr),
+ "aliased to %s", alias_result);
+ return (YES);
+ }
+
/*
* DELIVERY POLICY
*
} else {
if ((alias_pwd = mypwuid(alias_uid)) == 0) {
msg_warn("cannot find alias database owner for %s", *cpp);
- *statusp = defer_append(BOUNCE_FLAG_KEEP,
+ *statusp = defer_append(BOUNCE_FLAGS(state.request),
BOUNCE_ATTR(state.msg_attr),
"cannot find alias database owner");
return (YES);
expansion = mystrdup(alias_result);
if (OWNER_ASSIGN(owner) != 0
- && (owner_rhs = maps_find(alias_maps, owner, DICT_FLAG_NONE)) != 0) {
+ && (owner_rhs = maps_find(alias_maps, owner, DICT_FLAG_NONE)) != 0) {
canon_owner = canon_addr_internal(vstring_alloc(10),
var_exp_own_alias ? owner_rhs : owner);
SET_OWNER_ATTR(state.msg_attr, STR(canon_owner), state.level);
alias_count = 0;
*statusp =
(dict_errno ?
- defer_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+ defer_append(BOUNCE_FLAGS(state.request),
+ BOUNCE_ATTR(state.msg_attr),
"alias database unavailable") :
deliver_token_string(state, usr_attr, expansion, &alias_count));
#if 0
if (var_ownreq_special
- && strncmp("owner-", state.msg_attr.sender, 6) != 0
+ && strncmp("owner-", state.msg_attr.sender, 6) != 0
&& alias_count > 10)
msg_warn("mailing list \"%s\" needs an \"owner-%s\" alias",
name, name);
* further delivery for the current top-level recipient.
*/
if (dict_errno != 0) {
- *statusp = defer_append(BOUNCE_FLAG_KEEP,
+ *statusp = defer_append(BOUNCE_FLAGS(state.request),
BOUNCE_ATTR(state.msg_attr),
"alias database unavailable");
return (YES);
if (been_here(state.dup_filter, "command %ld %s", (long) usr_attr.uid, command))
return (0);
+ /*
+ * Don't deliver a trace-only request.
+ */
+ if (DEL_REQ_TRACE_ONLY(state.request->flags))
+ return (sent(BOUNCE_FLAGS(state.request), SENT_ATTR(state.msg_attr),
+ "delivers to command: %s", command));
+
/*
* DELIVERY RIGHTS
*
*/
switch (cmd_status) {
case PIPE_STAT_OK:
- deliver_status = sent(SENT_ATTR(state.msg_attr), "\"|%s\"", command);
+ deliver_status = sent(BOUNCE_FLAGS(state.request),
+ SENT_ATTR(state.msg_attr),
+ "delivered to command: %s", command);
break;
case PIPE_STAT_BOUNCE:
- deliver_status = bounce_append(BOUNCE_FLAG_KEEP,
+ deliver_status = bounce_append(BOUNCE_FLAGS(state.request),
BOUNCE_ATTR(state.msg_attr),
"%s", vstring_str(why));
break;
case PIPE_STAT_DEFER:
- deliver_status = defer_append(BOUNCE_FLAG_KEEP,
+ deliver_status = defer_append(BOUNCE_FLAGS(state.request),
BOUNCE_ATTR(state.msg_attr),
"%s", vstring_str(why));
break;
#include <mail_params.h>
#include <mail_conf.h>
#include <ext_prop.h>
+#include <sent.h>
/* Application-specific. */
* deliver to the user instead.
*/
if (lookup_status >= 0) {
- if (been_here(state.dup_filter, "forward %s", STR(path)) == 0) {
+
+ /*
+ * Don't expand a verify-only request.
+ */
+ if (state.request->flags & DEL_REQ_FLAG_VERIFY) {
+ *statusp = sent(BOUNCE_FLAGS(state.request),
+ SENT_ATTR(state.msg_attr),
+ "forward via file: %s", STR(path));
+ forward_found = YES;
+ } else if (been_here(state.dup_filter, "forward %s", STR(path)) == 0) {
state.msg_attr.exp_from = state.msg_attr.local;
if (S_ISREG(st.st_mode) == 0) {
msg_warn("file %s is not a regular file", STR(path));
* Do we allow delivery to files?
*/
if ((local_file_deliver_mask & state.msg_attr.exp_type) == 0)
- return (bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+ return (bounce_append(BOUNCE_FLAGS(state.request),
+ BOUNCE_ATTR(state.msg_attr),
"mail to file is restricted"));
+ /*
+ * Don't deliver trace-only requests.
+ */
+ if (DEL_REQ_TRACE_ONLY(state.request->flags))
+ return (sent(BOUNCE_FLAGS(state.request), SENT_ATTR(state.msg_attr),
+ "delivers to file: %s", path));
+
/*
* DELIVERY RIGHTS
*
} else if (mail_copy_status != 0) {
deliver_status = (errno == EAGAIN || errno == ENOSPC || errno == ESTALE ?
defer_append : bounce_append)
- (BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+ (BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr),
"cannot append message to destination file %s: %s",
path, STR(why));
} else {
- deliver_status = sent(SENT_ATTR(state.msg_attr), "%s", path);
+ deliver_status = sent(BOUNCE_FLAGS(state.request),
+ SENT_ATTR(state.msg_attr),
+ "delivered to file: %s", path);
}
/*
/* int forward_append(attr)
/* DELIVER_ATTR attr;
/*
-/* int forward_finish(attr, cancel)
+/* int forward_finish(request, attr, cancel)
+/* DELIVER_REQUEST *request;
/* DELIVER_ATTR attr;
/* int cancel;
/* DESCRIPTION
/* forward_send - send forwarded message */
-static int forward_send(FORWARD_INFO *info, DELIVER_ATTR attr, char *delivered)
+static int forward_send(FORWARD_INFO *info, DELIVER_REQUEST *request,
+ DELIVER_ATTR attr, char *delivered)
{
char *myname = "forward_send";
VSTRING *buffer = vstring_alloc(100);
* Log successful forwarding.
*/
if (status == 0)
- sent(SENT_ATTR(attr), "forwarded as %s", info->queue_id);
+ status = sent(BOUNCE_FLAGS(request), SENT_ATTR(attr),
+ "forwarded as %s", info->queue_id);
/*
* Cleanup.
/* forward_finish - complete message forwarding requests and clean up */
-int forward_finish(DELIVER_ATTR attr, int cancel)
+int forward_finish(DELIVER_REQUEST *request, DELIVER_ATTR attr, int cancel)
{
HTABLE_INFO **dt_list;
HTABLE_INFO **dt;
sender = sn[0]->key;
info = (FORWARD_INFO *) sn[0]->value;
if (status == 0)
- status |= forward_send(info, attr, delivered);
+ status |= forward_send(info, request, attr, delivered);
if (msg_verbose)
msg_info("forward_finish: delivered %s sender %s status %d",
delivered, sender, status);
#include <been_here.h>
#include <mail_params.h>
#include <ext_prop.h>
+#include <sent.h>
/* Application-specific. */
* enabled.
*/
if (*path != '/')
- return (bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+ return (bounce_append(BOUNCE_FLAGS(state.request),
+ BOUNCE_ATTR(state.msg_attr),
":include:%s uses a relative path", path));
if (stat_as(path, &st, usr_attr.uid, usr_attr.gid) < 0)
- return (bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
- "unable to lookup file %s: %m", path));
+ return (bounce_append(BOUNCE_FLAGS(state.request),
+ BOUNCE_ATTR(state.msg_attr),
+ "unable to lookup include file %s: %m", path));
if (S_ISREG(st.st_mode) == 0)
- return (bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+ return (bounce_append(BOUNCE_FLAGS(state.request),
+ BOUNCE_ATTR(state.msg_attr),
"not a regular include file: %s", path));
if (st.st_mode & S_IWOTH)
- return (bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+ return (bounce_append(BOUNCE_FLAGS(state.request),
+ BOUNCE_ATTR(state.msg_attr),
"world writable include file: %s", path));
/*
if (usr_attr.uid == 0) {
if ((file_pwd = mypwuid(st.st_uid)) == 0) {
msg_warn("cannot find username for uid %ld", (long) st.st_uid);
- return (defer_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+ return (defer_append(BOUNCE_FLAGS(state.request),
+ BOUNCE_ATTR(state.msg_attr),
"%s: cannot find :include: file owner", path));
}
if (file_pwd->pw_uid != 0)
vstream_fdopen(fd,O_RDONLY) : 0)
if ((fp = FOPEN_AS(path, usr_attr.uid, usr_attr.gid)) == 0) {
- status = bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+ status = bounce_append(BOUNCE_FLAGS(state.request),
+ BOUNCE_ATTR(state.msg_attr),
"cannot open include file %s: %m", path);
} else {
if ((local_ext_prop_mask & EXT_PROP_INCLUDE) == 0)
#include <bounce.h>
#include <defer.h>
#include <been_here.h>
+#include <sent.h>
/* Application-specific. */
if (msg_verbose)
msg_info("deliver_indirect: %s", state.msg_attr.recipient);
if (been_here(state.dup_filter, "indirect %s", state.msg_attr.recipient))
- return (0);
+ return (0);
+
+ /*
+ * Don't forward a trace-only request.
+ */
+ if (DEL_REQ_TRACE_ONLY(state.request->flags))
+ return (sent(BOUNCE_FLAGS(state.request),
+ SENT_ATTR(state.msg_attr),
+ "forwards to %s", state.msg_attr.recipient));
/*
* Send the address to the forwarding service. Inherit the delivered
* attribute from the alias or from the .forward file owner.
*/
if (forward_append(state.msg_attr))
- return (defer_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+ return (defer_append(BOUNCE_FLAGS(state.request),
+ BOUNCE_ATTR(state.msg_attr),
"unable to forward message"));
return (0);
}
state.msg_attr.orig_rcpt = rcpt->orig_addr;
state.msg_attr.recipient = rcpt->address;
rcpt_stat = deliver_recipient(state, usr_attr);
- rcpt_stat |= forward_finish(state.msg_attr, rcpt_stat);
+ rcpt_stat |= forward_finish(rqst, state.msg_attr, rcpt_stat);
if (rcpt_stat == 0 && (rqst->flags & DEL_REQ_FLAG_SUCCESS))
deliver_completed(state.msg_attr.fp, rcpt->offset);
been_here_free(state.dup_filter);
/*
* Bundle up some often-user attributes.
*/
+#define BOUNCE_FLAGS(request) DEL_REQ_TRACE_FLAGS((request)->flags)
+
#define BOUNCE_ATTR(attr) attr.queue_id, attr.orig_rcpt, attr.recipient, \
attr.relay, attr.arrival_time
#define BOUNCE_ONE_ATTR(attr) attr.queue_name, attr.queue_id, attr.encoding, \
*/
extern int forward_init(void);
extern int forward_append(DELIVER_ATTR);
-extern int forward_finish(DELIVER_ATTR, int);
+extern int forward_finish(DELIVER_REQUEST *, DELIVER_ATTR, int);
/*
* feature.c
if (msg_verbose)
MSG_LOG_STATE(myname, state);
+ /*
+ * Don't deliver trace-only requests.
+ */
+ if (DEL_REQ_TRACE_ONLY(state.request->flags))
+ return (sent(BOUNCE_FLAGS(state.request), SENT_ATTR(state.msg_attr),
+ "delivers to mailbox"));
+
/*
* Initialize. Assume the operation will fail. Set the delivered
* attribute to reflect the final recipient.
} else if (mail_copy_status != 0) {
deliver_status = (errno == EAGAIN || errno == ENOSPC || errno == ESTALE ?
defer_append : bounce_append)
- (BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+ (BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr),
"cannot access mailbox %s for user %s. %s",
mailbox, state.msg_attr.user, vstring_str(why));
} else {
- deliver_status = sent(SENT_ATTR(state.msg_attr), "mailbox");
+ deliver_status = sent(BOUNCE_FLAGS(state.request),
+ SENT_ATTR(state.msg_attr),
+ "delivered to mailbox");
if (var_biff) {
biff = vstring_alloc(100);
vstring_sprintf(biff, "%s@%ld", usr_attr.logname, (long) end);
if (msg_verbose)
MSG_LOG_STATE(myname, state);
+ /*
+ * Don't deliver trace-only requests.
+ */
+ if (DEL_REQ_TRACE_ONLY(state.request->flags))
+ return (sent(BOUNCE_FLAGS(state.request), SENT_ATTR(state.msg_attr),
+ "delivers to maildir"));
+
/*
* Initialize. Assume the operation will fail. Set the delivered
* attribute to reflect the final recipient.
} else if (mail_copy_status != 0) {
deliver_status = (errno == ENOSPC || errno == ESTALE ?
defer_append : bounce_append)
- (BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+ (BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr),
"maildir delivery failed: %s", vstring_str(why));
} else {
- deliver_status = sent(SENT_ATTR(state.msg_attr), "maildir");
+ deliver_status = sent(BOUNCE_FLAGS(state.request),
+ SENT_ATTR(state.msg_attr),
+ "delivered to maildir");
}
vstring_free(buf);
vstring_free(why);
if (var_stat_home_dir
&& (mypwd = mypwnam(state.msg_attr.user)) != 0
&& stat_as(mypwd->pw_dir, &st, mypwd->pw_uid, mypwd->pw_gid) < 0)
- return (defer_append(BOUNCE_FLAG_KEEP,
+ return (defer_append(BOUNCE_FLAGS(state.request),
BOUNCE_ATTR(state.msg_attr),
"cannot access home directory %s: %m",
mypwd->pw_dir));
myfree(owner_alias);
}
if (canon_owner) {
- rcpt_stat = bounce_one(BOUNCE_FLAG_KEEP,
+ rcpt_stat = bounce_one(BOUNCE_FLAGS(state.request),
BOUNCE_ONE_ATTR(state.msg_attr),
"mail forwarding loop for %s",
state.msg_attr.recipient);
vstring_free(canon_owner);
} else {
- rcpt_stat = bounce_append(BOUNCE_FLAG_KEEP,
+ rcpt_stat = bounce_append(BOUNCE_FLAGS(state.request),
BOUNCE_ATTR(state.msg_attr),
"mail forwarding loop for %s",
state.msg_attr.recipient);
* Do not allow null usernames.
*/
if (state.msg_attr.user[0] == 0)
- return (bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+ return (bounce_append(BOUNCE_FLAGS(state.request),
+ BOUNCE_ATTR(state.msg_attr),
"null username in %s", state.msg_attr.recipient));
/*
* First, a healthy portion of error handling.
*/
if (reply.flags & RESOLVE_FLAG_FAIL) {
- status = defer_append(BOUNCE_FLAG_KEEP, /* XXX */
+ status = defer_append(BOUNCE_FLAGS(state.request),
BOUNCE_ATTR(state.msg_attr),
"address resolver failure");
} else if (reply.flags & RESOLVE_FLAG_ERROR) {
- status = bounce_append(BOUNCE_FLAG_KEEP,/* XXX */
+ status = bounce_append(BOUNCE_FLAGS(state.request),
BOUNCE_ATTR(state.msg_attr),
"bad recipient address syntax: %s",
STR(reply.recipient));
int status;
if (addr[1] != '/') { /* disallow ~user */
- status = bounce_append(BOUNCE_FLAG_KEEP,
+ status = bounce_append(BOUNCE_FLAGS(state.request),
BOUNCE_ATTR(state.msg_attr),
"bad home directory syntax for: %s", addr);
} else if (usr_attr.home == 0) { /* require user context */
- status = bounce_append(BOUNCE_FLAG_KEEP,
+ status = bounce_append(BOUNCE_FLAGS(state.request),
BOUNCE_ATTR(state.msg_attr),
"unknown home directory for: %s", addr);
} else if (usr_attr.home[0] == '/' && usr_attr.home[1] == 0) {
status = deliver_token_home(state, usr_attr, STR(addr_buf));
} else if (*STR(addr_buf) == '|') {
if ((local_cmd_deliver_mask & state.msg_attr.exp_type) == 0)
- status = bounce_append(BOUNCE_FLAG_KEEP,
+ status = bounce_append(BOUNCE_FLAGS(state.request),
BOUNCE_ATTR(state.msg_attr),
"mail to command is restricted");
else
if (STREQ(state.msg_attr.local, MAIL_ADDR_MAIL_DAEMON)
|| STREQ(state.msg_attr.local, MAIL_ADDR_POSTMASTER)) {
msg_warn("required alias not found: %s", state.msg_attr.local);
- return (sent(SENT_ATTR(state.msg_attr), "discarded"));
+ return (sent(BOUNCE_FLAGS(state.request),
+ SENT_ATTR(state.msg_attr),
+ "discarded"));
}
/*
* Bounce the message when no luser relay is specified.
*/
- return (bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+ return (bounce_append(BOUNCE_FLAGS(state.request),
+ BOUNCE_ATTR(state.msg_attr),
"unknown user: \"%s\"", state.msg_attr.local));
}
qmgr_active.o: ../../include/vstring.h
qmgr_active.o: ../../include/recipient_list.h
qmgr_active.o: ../../include/bounce.h
+qmgr_active.o: ../../include/deliver_request.h
qmgr_active.o: ../../include/defer.h
+qmgr_active.o: ../../include/trace.h
qmgr_active.o: ../../include/abounce.h
qmgr_active.o: ../../include/rec_type.h
qmgr_active.o: qmgr.h
qmgr_bounce.o: qmgr_bounce.c
qmgr_bounce.o: ../../include/sys_defs.h
qmgr_bounce.o: ../../include/bounce.h
-qmgr_bounce.o: ../../include/deliver_completed.h
-qmgr_bounce.o: ../../include/vstream.h
+qmgr_bounce.o: ../../include/deliver_request.h
+qmgr_bounce.o: ../../include/vstring.h
qmgr_bounce.o: ../../include/vbuf.h
+qmgr_bounce.o: ../../include/vstream.h
+qmgr_bounce.o: ../../include/recipient_list.h
+qmgr_bounce.o: ../../include/deliver_completed.h
qmgr_bounce.o: qmgr.h
qmgr_bounce.o: ../../include/scan_dir.h
qmgr_defer.o: qmgr_defer.c
qmgr_defer.o: ../../include/vbuf.h
qmgr_defer.o: ../../include/defer.h
qmgr_defer.o: ../../include/bounce.h
+qmgr_defer.o: ../../include/deliver_request.h
+qmgr_defer.o: ../../include/vstring.h
+qmgr_defer.o: ../../include/recipient_list.h
qmgr_defer.o: qmgr.h
qmgr_defer.o: ../../include/scan_dir.h
qmgr_deliver.o: qmgr_deliver.c
qmgr_message.o: ../../include/record.h
qmgr_message.o: ../../include/rec_type.h
qmgr_message.o: ../../include/sent.h
+qmgr_message.o: ../../include/deliver_request.h
+qmgr_message.o: ../../include/recipient_list.h
qmgr_message.o: ../../include/deliver_completed.h
qmgr_message.o: ../../include/opened.h
qmgr_message.o: ../../include/verp_sender.h
struct QMGR_MESSAGE {
int flags; /* delivery problems */
int qflags; /* queuing flags */
+ int tflags; /* tracing flags */
VSTREAM *fp; /* open queue file or null */
int refcount; /* queue entries */
int single_rcpt; /* send one rcpt at a time */
#include <recipient_list.h>
#include <bounce.h>
#include <defer.h>
+#include <trace.h>
#include <abounce.h>
#include <rec_type.h>
return;
}
+ /*
+ * As a temporary implementation, synchronously inform the sender of
+ * trace information. This will block for 10 seconds when the qmgr FIFO
+ * is full.
+ */
+ if (message->tflags & (DEL_REQ_FLAG_EXPAND | DEL_REQ_FLAG_RECORD))
+ message->flags |= trace_flush(message->tflags,
+ message->queue_name,
+ message->queue_id,
+ message->encoding,
+ message->sender);
+
/*
* If we get to this point we have tried all recipients for this message.
* If the message is too old, try to bounce it.
* concurrency limits. However, the delivery agent protocol expects
* nexthop only, so we must strip off the recipient local part.
*/
- flags = message->inspect_xport ?
- DEL_REQ_FLAG_BOUNCE : DEL_REQ_FLAG_DEFLT;
+ flags = message->tflags
+ | (message->inspect_xport ? DEL_REQ_FLAG_BOUNCE : DEL_REQ_FLAG_DEFLT);
nexthop = (cp = strrchr(entry->queue->name, '@')) != 0 && cp[1] ?
cp + 1 : entry->queue->name;
attr_print(stream, ATTR_FLAG_MORE,
qmgr_message_count++;
message->flags = 0;
message->qflags = qflags;
+ message->tflags = 0;
message->fp = 0;
message->refcount = 0;
message->single_rcpt = 0;
myfree(message->encoding);
message->encoding = mystrdup(value);
}
+ /* Optional tracing flags. */
+ else if (strcmp(name, MAIL_ATTR_TRACE_FLAGS) == 0) {
+ message->tflags = DEL_REQ_TRACE_FLAGS(atoi(value));
+ }
} else if (rec_type == REC_TYPE_ERTO) {
if (message->errors_to == 0) {
message->errors_to = mystrdup(start);
char **cpp;
char *nexthop;
int len;
+ int status;
#define STREQ(x,y) (strcmp(x,y) == 0)
#define STR vstring_str
if (strncasecmp(STR(reply.recipient), var_double_bounce_sender,
len) == 0
&& !var_double_bounce_sender[len]) {
- sent(message->queue_id, recipient->orig_rcpt,
- recipient->address, "none", message->arrival_time,
- "discarded");
- deliver_completed(message->fp, recipient->offset);
- msg_warn("%s: undeliverable postmaster notification discarded",
- message->queue_id);
+ status = sent(message->tflags, message->queue_id, recipient->orig_rcpt,
+ recipient->address, "none", message->arrival_time,
+ "undeliverable postmaster notification discarded");
+ if (status == 0) {
+ deliver_completed(message->fp, recipient->offset);
+ msg_warn("%s: undeliverable postmaster notification discarded",
+ message->queue_id);
+ } else
+ message->flags |= status;
continue;
}
}
}
#define STREQ(x,y) (strcmp(x,y) == 0)
- if (STREQ(attr_name, MAIL_ATTR_ENCODING)
- && (STREQ(attr_value, MAIL_ATTR_ENC_7BIT)
- || STREQ(attr_value, MAIL_ATTR_ENC_8BIT)
- || STREQ(attr_value, MAIL_ATTR_ENC_NONE))) {
+ if ((STREQ(attr_name, MAIL_ATTR_ENCODING)
+ && (STREQ(attr_value, MAIL_ATTR_ENC_7BIT)
+ || STREQ(attr_value, MAIL_ATTR_ENC_8BIT)
+ || STREQ(attr_value, MAIL_ATTR_ENC_NONE)))
+ || STREQ(attr_name, MAIL_ATTR_TRACE_FLAGS)) { /* XXX */
rec_fprintf(cleanup, REC_TYPE_ATTR, "%s=%s",
attr_name, attr_value);
} else if (info->st.st_uid != var_owner_uid) {
case PIPE_STAT_OK:
for (n = 0; n < request->rcpt_list.len; n++) {
rcpt = request->rcpt_list.info + n;
- sent(request->queue_id, rcpt->orig_addr, rcpt->address, service,
- request->arrival_time, "%s", request->nexthop);
- if (request->flags & DEL_REQ_FLAG_SUCCESS)
+ status = sent(DEL_REQ_TRACE_FLAGS(request->flags),
+ request->queue_id, rcpt->orig_addr,
+ rcpt->address, service,
+ request->arrival_time, "%s", request->nexthop);
+ if (status == 0 && (request->flags & DEL_REQ_FLAG_SUCCESS))
deliver_completed(src, rcpt->offset);
+ result |= status;
}
break;
case PIPE_STAT_BOUNCE:
for (n = 0; n < request->rcpt_list.len; n++) {
rcpt = request->rcpt_list.info + n;
- status = bounce_append(BOUNCE_FLAG_KEEP,
+ status = bounce_append(DEL_REQ_TRACE_FLAGS(request->flags),
request->queue_id, rcpt->orig_addr,
rcpt->address, service,
request->arrival_time, "%s", why);
case PIPE_STAT_DEFER:
for (n = 0; n < request->rcpt_list.len; n++) {
rcpt = request->rcpt_list.info + n;
- result |= defer_append(BOUNCE_FLAG_KEEP,
+ result |= defer_append(DEL_REQ_TRACE_FLAGS(request->flags),
request->queue_id, rcpt->orig_addr,
rcpt->address, service,
request->arrival_time, "%s", why);
return (deliver_status);
}
+ /*
+ * Don't deliver a trace-only request.
+ */
+ if (DEL_REQ_TRACE_ONLY(request->flags)) {
+ RECIPIENT *rcpt;
+ int status;
+ int n;
+
+ deliver_status = 0;
+ 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, rcpt->orig_addr,
+ rcpt->address, service,
+ request->arrival_time,
+ "delivers to command: %s", attr.command[0]);
+ if (status == 0 && (request->flags & DEL_REQ_FLAG_SUCCESS))
+ deliver_completed(request->fp, rcpt->offset);
+ deliver_status |= status;
+ }
+ DELIVER_MSG_CLEANUP();
+ return (deliver_status);
+ }
+
/*
* Deliver. Set the nexthop and sender variables, and expand the command
* argument vector. Recipients will be expanded on the fly. XXX Rewrite
/* \fB-s\fR and \fB-p\fR command-line options on all Postfix queue
/* directories - this includes the \fBincoming\fR, \fBactive\fR and
/* \fBdeferred\fR directories with mail files and the \fBbounce\fR,
-/* \fBdefer\fR and \fBflush\fR directories with log files.
+/* \fBdefer\fR, \fBtrace\fR and \fBflush\fR directories with log files.
/*
/* Options:
/* .IP "\fB-c \fIconfig_dir\fR"
MAIL_QUEUE_ACTIVE, MAIL_QUEUE_STAT_READY, RECURSE,
MAIL_QUEUE_DEFERRED, MAIL_QUEUE_STAT_READY, RECURSE,
MAIL_QUEUE_HOLD, MAIL_QUEUE_STAT_READY, RECURSE,
+ MAIL_QUEUE_TRACE, 0600, RECURSE,
MAIL_QUEUE_DEFER, 0600, RECURSE,
MAIL_QUEUE_BOUNCE, 0600, RECURSE,
MAIL_QUEUE_FLUSH, 0600, RECURSE,
const char *log_queue_names[] = {
MAIL_QUEUE_BOUNCE,
MAIL_QUEUE_DEFER,
+ MAIL_QUEUE_TRACE,
0,
};
log_path_buf = vstring_alloc(100);
/*
- * Skip meta file directories. Delete defer or bounce logfiles before
+ * Skip meta file directories. Delete trace/defer/bounce logfiles before
* deleting the corresponding message file, and only if the message file
* exists. This minimizes but does not eliminate a race condition with
* queue ID reuse which results in deleting the wrong files.
qmgr_active.o: ../../include/vstring.h
qmgr_active.o: ../../include/recipient_list.h
qmgr_active.o: ../../include/bounce.h
+qmgr_active.o: ../../include/deliver_request.h
qmgr_active.o: ../../include/defer.h
+qmgr_active.o: ../../include/trace.h
qmgr_active.o: ../../include/abounce.h
qmgr_active.o: ../../include/rec_type.h
qmgr_active.o: qmgr.h
qmgr_bounce.o: qmgr_bounce.c
qmgr_bounce.o: ../../include/sys_defs.h
qmgr_bounce.o: ../../include/bounce.h
-qmgr_bounce.o: ../../include/deliver_completed.h
-qmgr_bounce.o: ../../include/vstream.h
+qmgr_bounce.o: ../../include/deliver_request.h
+qmgr_bounce.o: ../../include/vstring.h
qmgr_bounce.o: ../../include/vbuf.h
+qmgr_bounce.o: ../../include/vstream.h
+qmgr_bounce.o: ../../include/recipient_list.h
+qmgr_bounce.o: ../../include/deliver_completed.h
qmgr_bounce.o: qmgr.h
qmgr_bounce.o: ../../include/scan_dir.h
qmgr_defer.o: qmgr_defer.c
qmgr_defer.o: ../../include/vbuf.h
qmgr_defer.o: ../../include/defer.h
qmgr_defer.o: ../../include/bounce.h
+qmgr_defer.o: ../../include/deliver_request.h
+qmgr_defer.o: ../../include/vstring.h
+qmgr_defer.o: ../../include/recipient_list.h
qmgr_defer.o: qmgr.h
qmgr_defer.o: ../../include/scan_dir.h
qmgr_deliver.o: qmgr_deliver.c
qmgr_message.o: ../../include/record.h
qmgr_message.o: ../../include/rec_type.h
qmgr_message.o: ../../include/sent.h
+qmgr_message.o: ../../include/deliver_request.h
+qmgr_message.o: ../../include/recipient_list.h
qmgr_message.o: ../../include/deliver_completed.h
qmgr_message.o: ../../include/opened.h
qmgr_message.o: ../../include/verp_sender.h
struct QMGR_MESSAGE {
int flags; /* delivery problems */
int qflags; /* queuing flags */
+ int tflags; /* tracing flags */
VSTREAM *fp; /* open queue file or null */
int refcount; /* queue entries */
int single_rcpt; /* send one rcpt at a time */
#include <recipient_list.h>
#include <bounce.h>
#include <defer.h>
+#include <trace.h>
#include <abounce.h>
#include <rec_type.h>
return;
}
+ /*
+ * As a temporary implementation, synchronously inform the sender of
+ * trace information. This will block for 10 seconds when the qmgr FIFO
+ * is full.
+ */
+ if (message->tflags & (DEL_REQ_FLAG_EXPAND | DEL_REQ_FLAG_RECORD))
+ message->flags |= trace_flush(message->tflags,
+ message->queue_name,
+ message->queue_id,
+ message->encoding,
+ message->sender);
+
/*
* If we get to this point we have tried all recipients for this message.
* If the message is too old, try to bounce it.
* concurrency limits. However, the delivery agent protocol expects
* nexthop only, so we must strip off the recipient local part.
*/
- flags = message->inspect_xport ?
- DEL_REQ_FLAG_BOUNCE : DEL_REQ_FLAG_DEFLT;
+ flags = message->tflags
+ | (message->inspect_xport ? DEL_REQ_FLAG_BOUNCE : DEL_REQ_FLAG_DEFLT);
nexthop = (cp = strrchr(entry->queue->name, '@')) != 0 && cp[1] ?
cp + 1 : entry->queue->name;
attr_print(stream, ATTR_FLAG_MORE,
qmgr_message_count++;
message->flags = 0;
message->qflags = qflags;
+ message->tflags = 0;
message->fp = 0;
message->refcount = 0;
message->single_rcpt = 0;
myfree(message->encoding);
message->encoding = mystrdup(value);
}
+ /* Optional tracing flags. */
+ else if (strcmp(name, MAIL_ATTR_TRACE_FLAGS) == 0) {
+ message->tflags = DEL_REQ_TRACE_FLAGS(atoi(value));
+ }
} else if (rec_type == REC_TYPE_ERTO) {
if (message->errors_to == 0)
message->errors_to = mystrdup(start);
char **cpp;
char *nexthop;
int len;
+ int status;
#define STREQ(x,y) (strcasecmp(x,y) == 0)
#define STR vstring_str
if (strncasecmp(STR(reply.recipient), var_double_bounce_sender,
len) == 0
&& !var_double_bounce_sender[len]) {
- sent(message->queue_id, recipient->orig_rcpt,
- recipient->address, "none", message->arrival_time,
- "discarded");
- deliver_completed(message->fp, recipient->offset);
- msg_warn("%s: undeliverable postmaster notification discarded",
- message->queue_id);
+ status = sent(message->tflags, message->queue_id, recipient->orig_rcpt,
+ recipient->address, "none", message->arrival_time,
+ "undeliverable postmaster notification discarded");
+ if (status == 0) {
+ deliver_completed(message->fp, recipient->offset);
+ msg_warn("%s: undeliverable postmaster notification discarded",
+ message->queue_id);
+ } else
+ message->flags |= status;
continue;
}
}
sendmail.o: ../../include/mail_flush.h
sendmail.o: ../../include/mail_stream.h
sendmail.o: ../../include/verp_sender.h
+sendmail.o: ../../include/deliver_request.h
+sendmail.o: ../../include/recipient_list.h
/* .sp
/* This mode of operation is implemented by running the
/* \fBsmtpd\fR(8) daemon.
+/* .IP \fB-bv\fR
+/* Send an email report after verifying each recipient address.
+/* Verification always happens in the background. This is useful
+/* for testing address rewriting and routing configurations.
/* .IP "\fB-f \fIsender\fR"
/* Set the envelope sender address. This is the address where
/* delivery problems are sent to, unless the message contains an
/* Extract recipients from message headers. This requires that no
/* recipients be specified on the command line.
/* .IP \fB-v\fR
-/* Enable verbose logging for debugging purposes. Multiple \fB-v\fR
-/* options make the software increasingly verbose. For compatibility
-/* with mailx and other mail submission software, a single \fB-v\fR
-/* option produces no output.
+/* Send an email report of all delivery attempts (mail delivery
+/* always happens in the background). When multiple \fB-v\fR
+/* options are given, enable verbose logging for debugging purposes.
/* SECURITY
/* .ad
/* .fi
#include <mail_flush.h>
#include <mail_stream.h>
#include <verp_sender.h>
+#include <deliver_request.h>
/* Application-specific. */
#define SM_MODE_FLUSHQ 6 /* user (stand-alone) mode */
/*
- * Flag parade.
+ * Flag parade. Flags 8-15 are reserved for delivery request trace flags.
*/
#define SM_FLAG_AEOF (1<<0) /* archaic EOF */
"-V option requires non-null sender address");
if (encoding)
rec_fprintf(dst, REC_TYPE_ATTR, "%s=%s", MAIL_ATTR_ENCODING, encoding);
+ if (DEL_REQ_TRACE_FLAGS(flags))
+ rec_fprintf(dst, REC_TYPE_ATTR, "%s=%d", MAIL_ATTR_TRACE_FLAGS,
+ DEL_REQ_TRACE_FLAGS(flags));
if (verp_delims)
rec_fputs(dst, REC_TYPE_VERP, verp_delims);
if (recipients) {
* of UUCP environments, also get rid of leading >>>From_ lines.
*/
rec_fprintf(dst, REC_TYPE_MESG, REC_TYPE_MESG_FORMAT, 0L);
- skip_from_ = 1;
- strip_cr = STRIP_CR_DUNNO;
- for (prev_type = 0; (type = rec_streamlf_get(VSTREAM_IN, buf, var_line_limit))
- != REC_TYPE_EOF; prev_type = type) {
- if (strip_cr == STRIP_CR_DUNNO && type == REC_TYPE_NORM) {
- if (VSTRING_LEN(buf) > 0 && vstring_end(buf)[-1] == '\r')
- strip_cr = STRIP_CR_DO;
- else
- strip_cr = STRIP_CR_DONT;
+ if (DEL_REQ_TRACE_ONLY(flags) != 0) {
+ rec_fprintf(dst, REC_TYPE_NORM, "Subject: probe");
+ if (recipients) {
+ rec_fprintf(dst, REC_TYPE_NORM, "To:");
+ for (cpp = recipients; *cpp != 0; cpp++) {
+ rec_fprintf(dst, REC_TYPE_NORM, " %s%s",
+ *cpp, cpp[1] ? "," : "");
+ }
}
- if (skip_from_) {
- if (type == REC_TYPE_NORM) {
- start = vstring_str(buf);
- if (strncmp(start + strspn(start, ">"), "From ", 5) == 0)
- continue;
+ } else {
+ skip_from_ = 1;
+ strip_cr = STRIP_CR_DUNNO;
+ for (prev_type = 0; (type = rec_streamlf_get(VSTREAM_IN, buf, var_line_limit))
+ != REC_TYPE_EOF; prev_type = type) {
+ if (strip_cr == STRIP_CR_DUNNO && type == REC_TYPE_NORM) {
+ if (VSTRING_LEN(buf) > 0 && vstring_end(buf)[-1] == '\r')
+ strip_cr = STRIP_CR_DO;
+ else
+ strip_cr = STRIP_CR_DONT;
+ }
+ if (skip_from_) {
+ if (type == REC_TYPE_NORM) {
+ start = vstring_str(buf);
+ if (strncmp(start + strspn(start, ">"), "From ", 5) == 0)
+ continue;
+ }
+ skip_from_ = 0;
}
- skip_from_ = 0;
+ if (strip_cr == STRIP_CR_DO && type == REC_TYPE_NORM)
+ if (VSTRING_LEN(buf) > 0 && vstring_end(buf)[-1] == '\r')
+ vstring_truncate(buf, VSTRING_LEN(buf) - 1);
+ if ((flags & SM_FLAG_AEOF) && prev_type != REC_TYPE_CONT
+ && VSTRING_LEN(buf) == 1 && *STR(buf) == '.')
+ break;
+ if (REC_PUT_BUF(dst, type, buf) < 0)
+ msg_fatal_status(EX_TEMPFAIL,
+ "%s(%ld): error writing queue file: %m",
+ saved_sender, (long) uid);
}
- if (strip_cr == STRIP_CR_DO && type == REC_TYPE_NORM)
- if (VSTRING_LEN(buf) > 0 && vstring_end(buf)[-1] == '\r')
- vstring_truncate(buf, VSTRING_LEN(buf) - 1);
- if ((flags & SM_FLAG_AEOF) && prev_type != REC_TYPE_CONT
- && VSTRING_LEN(buf) == 1 && *STR(buf) == '.')
- break;
- if (REC_PUT_BUF(dst, type, buf) < 0)
- msg_fatal_status(EX_TEMPFAIL,
- "%s(%ld): error writing queue file: %m",
- saved_sender, (long) uid);
}
/*
EX_UNAVAILABLE, "%s(%ld): %s", saved_sender,
(long) uid, cleanup_strerror(status));
+ /*
+ * Don't leave them in the dark.
+ */
+ if (DEL_REQ_TRACE_FLAGS(flags)) {
+ vstream_printf("Mail Delivery Status Report will be mailed to <%s>.\n",
+ saved_sender);
+ vstream_fflush(VSTREAM_OUT);
+ }
+
/*
* Cleanup. Not really necessary as we're about to exit, but good for
* debugging purposes.
* Further initialization...
*/
mail_conf_read();
+
if (chdir(var_queue_dir))
msg_fatal_status(EX_UNAVAILABLE, "chdir %s: %m", var_queue_dir);
case 's': /* stand-alone mode */
mode = SM_MODE_USER;
break;
+ case 'v': /* expand recipients */
+ flags |= DEL_REQ_FLAG_EXPAND;
+ break;
}
break;
case 'f':
}
}
- /*
- * Workaround: produce no output when verbose delivery is requested in
- * mail.rc.
- */
- if (msg_verbose > 0)
- msg_verbose--;
-
/*
* Look for conflicting options and arguments.
*/
msg_fatal_status(EX_USAGE,
"cannot handle command-line recipients with -t");
+ /*
+ * The -v option plays double duty. One requests verbose delivery, more
+ * than one requests verbose logging.
+ */
+ if (msg_verbose == 1 && mode == SM_MODE_ENQUEUE) {
+ msg_verbose = 0;
+ flags |= DEL_REQ_FLAG_RECORD;
+ }
+
/*
* Start processing. Everything is delegated to external commands.
*/
/* Timeout for sending the "\fB.\fR" command, and for
/* receiving the server response. When no response is received, a
/* warning is logged that the mail may be delivered multiple times.
+/* .IP \fBsmtp_rset_timeout\fR
+/* Timeout for sending the \fBRSET\fR command.
/* .IP \fBsmtp_quit_timeout\fR
/* Timeout for sending the \fBQUIT\fR command, and for
/* receiving the server response.
int var_smtp_data0_tmout;
int var_smtp_data1_tmout;
int var_smtp_data2_tmout;
+int var_smtp_rset_tmout;
int var_smtp_quit_tmout;
char *var_inet_interfaces;
char *var_notify_classes;
VAR_SMTP_DATA0_TMOUT, DEF_SMTP_DATA0_TMOUT, &var_smtp_data0_tmout, 1, 0,
VAR_SMTP_DATA1_TMOUT, DEF_SMTP_DATA1_TMOUT, &var_smtp_data1_tmout, 1, 0,
VAR_SMTP_DATA2_TMOUT, DEF_SMTP_DATA2_TMOUT, &var_smtp_data2_tmout, 1, 0,
+ VAR_SMTP_RSET_TMOUT, DEF_SMTP_RSET_TMOUT, &var_smtp_rset_tmout, 1, 0,
VAR_SMTP_QUIT_TMOUT, DEF_SMTP_QUIT_TMOUT, &var_smtp_quit_tmout, 1, 0,
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,
* Abort immediately if the connection is broken.
*/
if (vstream_ftimeout(session->stream))
- vstream_longjmp(session->stream, SMTP_ERR_TIME);
+ vstream_longjmp(session->stream, SMTP_ERR_TIME);
if (vstream_ferror(session->stream))
vstream_longjmp(session->stream, SMTP_ERR_EOF);
}
* generate from untrusted data.
*/
#define NULL_CLEANUP_FLAGS 0
+#define NULL_TRACE_FLAGS 0
#define LENGTH 78
#define INDENT 4
notice = post_mail_fopen_nowait(mail_addr_double_bounce(),
var_error_rcpt,
- NULL_CLEANUP_FLAGS);
+ NULL_CLEANUP_FLAGS,
+ NULL_TRACE_FLAGS);
if (notice == 0) {
msg_warn("postmaster notify: %m");
return;
&var_smtp_rcpt_tmout,
&var_smtp_data0_tmout,
&var_smtp_data2_tmout,
- &var_smtp_quit_tmout,
+ &var_smtp_rset_tmout,
&var_smtp_quit_tmout,
};
vstring_sprintf(next_command, "RCPT TO:<%s>",
vstring_str(state->scratch));
if ((next_rcpt = send_rcpt + 1) == request->rcpt_list.len)
- next_state = SMTP_STATE_DATA;
+ next_state = DEL_REQ_TRACE_ONLY(request->flags) ?
+ SMTP_STATE_ABORT : SMTP_STATE_DATA;
break;
/*
break;
/*
- * Can't happen. The SMTP_STATE_ABORT sender state is entered by
- * the receiver and is left before the bottom of the main loop.
+ * The SMTP_STATE_ABORT sender state is entered by sender when it
+ * has verified all recipients; or it is entered the receiver
+ * when all recipients are rejected and is then left before the
+ * bottom of the main loop.
*/
case SMTP_STATE_ABORT:
- msg_panic("%s: sender abort state", myname);
+ vstring_strcpy(next_command, "RSET");
+ next_state = SMTP_STATE_QUIT;
+ break;
/*
* Build the QUIT command before we have seen the "." or RSET
#endif
if (resp->code / 100 == 2) {
++nrcpt;
+ /* If trace-only, mark the recipient done. */
+ if (DEL_REQ_TRACE_ONLY(request->flags)
+ && sent(DEL_REQ_TRACE_FLAGS(request->flags),
+ request->queue_id, rcpt->orig_addr,
+ rcpt->address, session->namaddr,
+ request->arrival_time, "%s",
+ translit(resp->str, "\n", " ")) == 0) {
+ if (request->flags & DEL_REQ_FLAG_SUCCESS)
+ deliver_completed(state->src, rcpt->offset);
+ rcpt->offset = 0; /* in case deferred */
+ }
} else {
rcpt = request->rcpt_list.info + recv_rcpt;
smtp_rcpt_fail(state, resp->code, rcpt,
rcpt->offset = 0; /* in case deferred */
}
}
+ /* If trace-only, send RSET instead of DATA. */
if (++recv_rcpt == request->rcpt_list.len)
- recv_state = SMTP_STATE_DATA;
+ recv_state = DEL_REQ_TRACE_ONLY(request->flags) ?
+ SMTP_STATE_ABORT : SMTP_STATE_DATA;
break;
/*
for (nrcpt = 0; nrcpt < recv_rcpt; nrcpt++) {
rcpt = request->rcpt_list.info + nrcpt;
if (rcpt->offset) {
- sent(request->queue_id, rcpt->orig_addr,
- rcpt->address,
- session->namaddr,
- request->arrival_time, "%s",
- resp->str);
- if (request->flags & DEL_REQ_FLAG_SUCCESS)
- deliver_completed(state->src, rcpt->offset);
- rcpt->offset = 0;
+ if (sent(DEL_REQ_TRACE_FLAGS(request->flags),
+ request->queue_id, rcpt->orig_addr,
+ rcpt->address,
+ session->namaddr,
+ request->arrival_time,
+ "%s", resp->str) == 0) {
+ if (request->flags & DEL_REQ_FLAG_SUCCESS)
+ deliver_completed(state->src, rcpt->offset);
+ rcpt->offset = 0;
+ }
}
}
}
#define SMTP_SOFT(code) (((code) / 100) == 4)
#define SMTP_HARD(code) (((code) / 100) == 5)
-#define KEEP BOUNCE_FLAG_KEEP
/* smtp_check_code - check response code */
if (rcpt->offset == 0)
continue;
status = (soft_error ? defer_append : bounce_append)
- (KEEP, request->queue_id, rcpt->orig_addr, rcpt->address,
+ (DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
+ rcpt->orig_addr, rcpt->address,
session ? session->namaddr : "none",
request->arrival_time, "%s", vstring_str(why));
if (status == 0) {
if (rcpt->offset == 0)
continue;
status = (SMTP_SOFT(code) ? defer_append : bounce_append)
- (KEEP, request->queue_id, rcpt->orig_addr, rcpt->address,
+ (DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
+ rcpt->orig_addr, rcpt->address,
session->namaddr, request->arrival_time,
"%s", vstring_str(why));
if (status == 0) {
*/
va_start(ap, format);
status = (SMTP_SOFT(code) ? vdefer_append : vbounce_append)
- (KEEP, request->queue_id, rcpt->orig_addr, rcpt->address,
+ (DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
+ rcpt->orig_addr, rcpt->address,
session->namaddr, request->arrival_time, format, ap);
va_end(ap);
if (status == 0) {
rcpt = request->rcpt_list.info + nrcpt;
if (rcpt->offset == 0)
continue;
- state->status |= defer_append(KEEP, request->queue_id,
+ state->status |= defer_append(DEL_REQ_TRACE_FLAGS(request->flags),
+ request->queue_id,
rcpt->orig_addr, rcpt->address,
session->namaddr,
request->arrival_time,
smtpd_check.o: ../../include/mail_proto.h
smtpd_check.o: ../../include/iostuff.h
smtpd_check.o: ../../include/attr.h
+smtpd_check.o: ../../include/verify_clnt.h
+smtpd_check.o: ../../include/deliver_request.h
+smtpd_check.o: ../../include/recipient_list.h
smtpd_check.o: smtpd.h
smtpd_check.o: ../../include/mail_stream.h
smtpd_check.o: smtpd_sasl_glue.h
/* restriction.
/* .IP \fBmaps_rbl_reject_code\fR
/* Response code when a request is RBL blacklisted.
+/* .IP \fBmulti_recipient_bounce_reject_code\fR
+/* Response code when a multi-recipient bounce is blocked.
/* .IP \fBrbl_reply_maps\fR
/* Table with template responses for RBL blacklisted requests, indexed by
/* RBL domain name. These templates are used by the \fBreject_rbl_*\fR
/* .IP \fBunknown_hostname_reject_code\fR
/* Response code when a client violates the \fBreject_unknown_hostname\fR
/* restriction.
+/* .IP \fBunverified_sender_reject_code\fR
+/* Response code when a sender address is known to be undeliverable.
+/* .IP \fBunverified_recipient_reject_code\fR
+/* Response code when a recipient address is known to be undeliverable.
/* SEE ALSO
/* trivial-rewrite(8) address resolver
/* cleanup(8) message canonicalization
int var_smtpd_hist_thrsh;
char *var_smtpd_exp_filter;
char *var_def_rbl_reply;
+int var_unv_from_code;
+int var_unv_rcpt_code;
+int var_mul_rcpt_code;
char *var_relay_rcpt_maps;
+char *var_verify_sender;
int var_local_rcpt_code;
int var_virt_alias_code;
int var_virt_mailbox_code;
VAR_NON_FQDN_CODE, DEF_NON_FQDN_CODE, &var_non_fqdn_code, 0, 0,
VAR_SMTPD_JUNK_CMD, DEF_SMTPD_JUNK_CMD, &var_smtpd_junk_cmd_limit, 1, 0,
VAR_SMTPD_HIST_THRSH, DEF_SMTPD_HIST_THRSH, &var_smtpd_hist_thrsh, 1, 0,
+ VAR_UNV_FROM_CODE, DEF_UNV_FROM_CODE, &var_unv_from_code, 0, 0,
+ VAR_UNV_RCPT_CODE, DEF_UNV_RCPT_CODE, &var_unv_rcpt_code, 0, 0,
+ VAR_MUL_RCPT_CODE, DEF_MUL_RCPT_CODE, &var_mul_rcpt_code, 0, 0,
VAR_LOCAL_RCPT_CODE, DEF_LOCAL_RCPT_CODE, &var_local_rcpt_code, 0, 0,
VAR_VIRT_ALIAS_CODE, DEF_VIRT_ALIAS_CODE, &var_virt_alias_code, 0, 0,
VAR_VIRT_MAILBOX_CODE, DEF_VIRT_MAILBOX_CODE, &var_virt_mailbox_code, 0, 0,
VAR_SMTPD_NOOP_CMDS, DEF_SMTPD_NOOP_CMDS, &var_smtpd_noop_cmds, 0, 0,
VAR_SMTPD_NULL_KEY, DEF_SMTPD_NULL_KEY, &var_smtpd_null_key, 0, 0,
VAR_RELAY_RCPT_MAPS, DEF_RELAY_RCPT_MAPS, &var_relay_rcpt_maps, 0, 0,
+ VAR_VERIFY_SENDER, DEF_VERIFY_SENDER, &var_verify_sender, 0, 0,
VAR_VERP_CLIENTS, DEF_VERP_CLIENTS, &var_verp_clients, 0, 0,
0,
};
* generate from untrusted data.
*/
#define NULL_CLEANUP_FLAGS 0
+#define NULL_TRACE_FLAGS 0
#define LENGTH 78
#define INDENT 4
notice = post_mail_fopen_nowait(mail_addr_double_bounce(),
var_error_rcpt,
- NULL_CLEANUP_FLAGS);
+ NULL_CLEANUP_FLAGS,
+ NULL_TRACE_FLAGS);
if (notice == 0) {
msg_warn("postmaster notify: %m");
return;
/* .IP "check_recipient_maps"
/* Reject recipients not listed as valid local, virtual or relay
/* recipients.
+/* .IP reject_multi_recipient_bounce
+/* Reject mail from <> with multiple envelope recipients.
/* .IP reject_rbl_client rbl.domain.tld
/* Look up the reversed client network address in the specified
/* real-time blackhole DNS zone. The \fIrbl_reply_maps\fR configuration
/* DNS A or MX record.
/* The \fIunknown_address_reject_code\fR configuration parameter
/* specifies the reject status code (default: 450).
+/* .IP reject_unverified_sender
+/* Reject the request when mail to the sender address is known to
+/* bounce, or when the sender's address destination is not reachable.
+/* Address verification information is managed by the verify(8) daemon.
+/* .IP reject_unverified_recipient
+/* Reject the request when mail to the recipient address is known to
+/* bounce, or when the recipient's address destination is not reachable.
+/* Address verification information is managed by the verify(8) daemon.
/* .IP reject_unknown_recipient_domain
/* Reject the request when the resolved recipient address has no
/* DNS A or MX record.
#include <record.h>
#include <rec_type.h>
#include <mail_proto.h>
+#include <verify_clnt.h>
/* Application-specific. */
else \
(void) smtpd_check_reject((state), (class), (fmt), (a1), (a2)); \
} while (0)
+#define DEFER_IF_PERMIT3(state, class, fmt, a1, a2, a3) do { \
+ if ((state)->warn_if_reject == 0) \
+ defer_if(&(state)->defer_if_permit, (class), (fmt), (a1), (a2), (a3)); \
+ else \
+ (void) smtpd_check_reject((state), (class), (fmt), (a1), (a2), (a3)); \
+ } while (0)
/*
* Cached RBL lookup state.
return (reject_unknown_mailhost(state, domain, reply_name, reply_class));
}
+/* reject_unverified_address - fail if address bounces */
+
+static int reject_unverified_address(SMTPD_STATE *state, const char *addr,
+ const char *reply_name, const char *reply_class,
+ int unv_addr_code)
+{
+ char *myname = "reject_unverified_address";
+ VSTRING *why = vstring_alloc(10);
+ int rqst_status;
+ int rcpt_status;
+ int verify_status;
+ int count;
+
+ if (msg_verbose)
+ msg_info("%s: %s", myname, addr);
+
+ /*
+ * Verify the address. Don't waste too much of their or our time.
+ */
+ for (count = 0; count < 3; count++) {
+ verify_status = verify_clnt_query(addr, &rcpt_status, why);
+ if (verify_status != VRFY_STAT_OK || rcpt_status != DEL_RCPT_STAT_TODO)
+ break;
+ sleep(3);
+ }
+ if (verify_status != VRFY_STAT_OK) {
+ msg_warn("%s service failure", var_verify_service);
+ DEFER_IF_REJECT2(state, MAIL_ERROR_POLICY,
+ "450 <%s>: %s rejected: address verification problem",
+ reply_name, reply_class);
+ rqst_status = SMTPD_CHECK_DUNNO;
+ } else {
+ switch (rcpt_status) {
+ default:
+ msg_warn("unknown address verification status %d", rcpt_status);
+ rqst_status = SMTPD_CHECK_DUNNO;
+ break;
+ case DEL_RCPT_STAT_TODO:
+ case DEL_RCPT_STAT_DEFER:
+ DEFER_IF_PERMIT3(state, MAIL_ERROR_POLICY,
+ "450 <%s>: %s rejected: unverified address: %s",
+ reply_name, reply_class, STR(why));
+ rqst_status = SMTPD_CHECK_DUNNO;
+ break;
+ case DEL_RCPT_STAT_OK:
+ rqst_status = SMTPD_CHECK_DUNNO;
+ break;
+ case DEL_RCPT_STAT_BOUNCE:
+ if (unv_addr_code / 100 == 2)
+ rqst_status = SMTPD_CHECK_DUNNO;
+ else
+ rqst_status = smtpd_check_reject(state, MAIL_ERROR_POLICY,
+ "%d <%s>: %s rejected: undeliverable address: %s",
+ unv_addr_code, reply_name, reply_class, STR(why));
+ break;
+ }
+ }
+ vstring_free(why);
+ return (rqst_status);
+}
+
/* check_table_result - translate table lookup result into pass/reject */
static int check_table_result(SMTPD_STATE *state, const char *table,
if (state->sender && *state->sender)
status = reject_unknown_address(state, state->sender,
state->sender, SMTPD_NAME_SENDER);
+ } else if (strcasecmp(name, REJECT_UNVERIFIED_SENDER) == 0) {
+ if (state->sender && *state->sender)
+ status = reject_unverified_address(state, state->sender,
+ state->sender, SMTPD_NAME_SENDER,
+ var_unv_from_code);
} else if (strcasecmp(name, REJECT_NON_FQDN_SENDER) == 0) {
if (state->sender && *state->sender)
status = reject_non_fqdn_address(state, state->sender,
} else if (strcasecmp(name, CHECK_RCPT_MAPS) == 0) {
if (state->recipient && *state->recipient)
status = check_rcpt_maps(state, state->recipient);
+ } else if (strcasecmp(name, REJECT_MUL_RCPT_BOUNCE) == 0) {
+ if (state->sender && *state->sender == 0 && state->rcpt_count
+ > (strcmp(state->where, "DATA") ? 0 : 1))
+ status = smtpd_check_reject(state, MAIL_ERROR_POLICY,
+ "%d <%s>: %s rejected: Multi-recipient bounce",
+ var_mul_rcpt_code, reply_name, reply_class);
+ } else if (strcasecmp(name, REJECT_UNVERIFIED_RECIP) == 0) {
+ if (state->recipient && *state->recipient)
+ status = reject_unverified_address(state, state->recipient,
+ state->recipient, SMTPD_NAME_RECIPIENT,
+ var_unv_rcpt_code);
}
/*
int status;
char *saved_recipient;
char *err;
+ static VSTRING *canon_verify_sender;
/*
* Initialize.
if (strcasecmp(recipient, "postmaster") == 0)
return (0);
+ /*
+ * XXX Always say OK when we're probed with our own address verification
+ * sender address. Otherwise, some timeout or some UCE block may result
+ * in mutual negative caching, making it painful to get the mail through.
+ */
+#ifndef TEST
+ if (*recipient) {
+ if (canon_verify_sender == 0) {
+ canon_verify_sender = vstring_alloc(10);
+ canon_addr_internal(canon_verify_sender, var_verify_sender);
+ }
+ if (strcasecmp(STR(canon_verify_sender), recipient) == 0)
+ return (0);
+ }
+#endif
+
/*
* Minor kluge so that we can delegate work to the generic routine and so
* that we can syslog the recipient with the reject messages.
SMTPD_CHECK_RESET();
status = setjmp(smtpd_check_buf);
if (status == 0 && rcpt_restrctions->argc)
- status = generic_checks(state, rcpt_restrctions,
+ status = generic_checks(state, rcpt_restrctions,
recipient, SMTPD_NAME_RECIPIENT, CHECK_RECIP_ACL);
/*
char *var_smtpd_exp_filter;
char *var_def_rbl_reply;
char *var_relay_rcpt_maps;
+char *var_verify_sender;
typedef struct {
char *name;
char **target;
} STRING_TABLE;
-#undef DEF_LOCAL_RCPT_MAPS
-#define DEF_LOCAL_RCPT_MAPS ""
-
#undef DEF_VIRT_ALIAS_MAPS
#define DEF_VIRT_ALIAS_MAPS ""
+#undef DEF_LOCAL_RCPT_MAPS
+#define DEF_LOCAL_RCPT_MAPS ""
+
static STRING_TABLE string_table[] = {
VAR_MAPS_RBL_DOMAINS, DEF_MAPS_RBL_DOMAINS, &var_maps_rbl_domains,
VAR_MYORIGIN, DEF_MYORIGIN, &var_myorigin,
VAR_SMTPD_EXP_FILTER, DEF_SMTPD_EXP_FILTER, &var_smtpd_exp_filter,
VAR_DEF_RBL_REPLY, DEF_DEF_RBL_REPLY, &var_def_rbl_reply,
VAR_RELAY_RCPT_MAPS, DEF_RELAY_RCPT_MAPS, &var_relay_rcpt_maps,
+ VAR_VERIFY_SENDER, DEF_VERIFY_SENDER, &var_verify_sender,
0,
};
int var_non_fqdn_code;
int var_smtpd_delay_reject;
int var_allow_untrust_route;
+int var_mul_rcpt_code;
+int var_unv_from_code;
+int var_unv_rcpt_code;
int var_local_rcpt_code;
int var_relay_rcpt_code;
int var_virt_mailbox_code;
VAR_NON_FQDN_CODE, DEF_NON_FQDN_CODE, &var_non_fqdn_code,
VAR_SMTPD_DELAY_REJECT, DEF_SMTPD_DELAY_REJECT, &var_smtpd_delay_reject,
VAR_ALLOW_UNTRUST_ROUTE, DEF_ALLOW_UNTRUST_ROUTE, &var_allow_untrust_route,
+ VAR_MUL_RCPT_CODE, DEF_MUL_RCPT_CODE, &var_mul_rcpt_code,
+ VAR_UNV_FROM_CODE, DEF_UNV_FROM_CODE, &var_unv_from_code,
+ VAR_UNV_RCPT_CODE, DEF_UNV_RCPT_CODE, &var_unv_rcpt_code,
VAR_LOCAL_RCPT_CODE, DEF_LOCAL_RCPT_CODE, &var_local_rcpt_code,
VAR_RELAY_RCPT_CODE, DEF_RELAY_RCPT_CODE, &var_relay_rcpt_code,
VAR_VIRT_ALIAS_CODE, DEF_VIRT_ALIAS_CODE, &var_virt_alias_code,
* Subtle note: reset nexthop even when the transport table does not change
* the transport. Otherwise it is hard to get rid of main.cf specified
* nexthop information.
+ *
+ * XXX Don't override the virtual alias class (error:User unknown) result.
*/
- if (*var_transport_maps) {
+ if (*var_transport_maps && !(*flags & RESOLVE_CLASS_ALIAS)) {
if (transport_lookup(STR(nextrcpt), rcpt_domain, channel, nexthop) == 0
&& dict_errno != 0) {
msg_warn("%s lookup failure", VAR_TRANSPORT_MAPS);
static int transport_match_parent_style;
static VSTRING *wildcard_channel;
static VSTRING *wildcard_nexthop;
+static int transport_errno;
#define STR(x) vstring_str(x)
msg_info("wildcard_{chan:hop}={%s:%s}",
vstring_str(wildcard_channel), vstring_str(wildcard_nexthop));
} else {
- if (dict_errno != 0)
- msg_fatal("transport table initialization problem.");
+ transport_errno = dict_errno;
vstring_free(channel);
vstring_free(nexthop);
}
/*
* Fall back to the wild-card entry.
*/
- if (wildcard_channel) {
+ if (transport_errno) {
+ dict_errno = transport_errno;
+ RETURN_FREE(NOTFOUND);
+ } else if (wildcard_channel) {
update_entry(STR(wildcard_channel), STR(wildcard_nexthop),
rcpt_domain, channel, nexthop);
RETURN_FREE(FOUND);
--- /dev/null
+../../.indent.pro
\ No newline at end of file
--- /dev/null
+SHELL = /bin/sh
+SRCS = verify.c
+OBJS = verify.o
+HDRS =
+TESTSRC =
+WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \
+ -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \
+ -Wunused
+DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
+CFLAGS = $(DEBUG) $(OPT) $(DEFS)
+TESTPROG=
+PROG = verify
+INC_DIR = ../../include
+LIBS = ../../lib/libmaster.a ../../lib/libglobal.a ../../lib/libutil.a
+
+.c.o:; $(CC) $(CFLAGS) -c $*.c
+
+$(PROG): $(OBJS) $(LIBS)
+ $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
+
+Makefile: Makefile.in
+ (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+
+test: $(TESTPROG)
+
+tests: test
+
+update: ../../libexec/$(PROG)
+
+../../libexec/$(PROG): $(PROG)
+ cp $(PROG) ../../libexec
+
+printfck: $(OBJS) $(PROG)
+ rm -rf printfck
+ mkdir printfck
+ sed '1,/^# do not edit/!d' Makefile >printfck/Makefile
+ set -e; for i in *.c; do printfck -f .printfck $$i >printfck/$$i; done
+ cd printfck; make "INC_DIR=../../../include" `cd ..; ls *.o`
+
+lint:
+ lint $(DEFS) $(SRCS) $(LINTFIX)
+
+clean:
+ rm -f *.o *core $(PROG) $(TESTPROG) junk
+ rm -rf printfck
+
+tidy: clean
+
+depend: $(MAKES)
+ (sed '1,/^# do not edit/!d' Makefile.in; \
+ set -e; for i in [a-z][a-z0-9]*.c; do \
+ $(CC) -E $(DEFS) $(INCL) $$i | sed -n -e '/^# *1 *"\([^"]*\)".*/{' \
+ -e 's//'`echo $$i|sed 's/c$$/o/'`': \1/' -e 'p' -e '}'; \
+ done) | grep -v '[.][o][:][ ][/]' >$$$$ && mv $$$$ Makefile.in
+ @$(EXPORT) make -f Makefile.in Makefile 1>&2
+
+# do not edit below this line - it is generated by 'make depend'
+verify.o: verify.c
+verify.o: ../../include/sys_defs.h
+verify.o: ../../include/msg.h
+verify.o: ../../include/mymalloc.h
+verify.o: ../../include/htable.h
+verify.o: ../../include/dict_ht.h
+verify.o: ../../include/dict.h
+verify.o: ../../include/vstream.h
+verify.o: ../../include/vbuf.h
+verify.o: ../../include/argv.h
+verify.o: ../../include/split_at.h
+verify.o: ../../include/mail_conf.h
+verify.o: ../../include/mail_params.h
+verify.o: ../../include/mail_proto.h
+verify.o: ../../include/iostuff.h
+verify.o: ../../include/attr.h
+verify.o: ../../include/post_mail.h
+verify.o: ../../include/cleanup_user.h
+verify.o: ../../include/verify_clnt.h
+verify.o: ../../include/deliver_request.h
+verify.o: ../../include/vstring.h
+verify.o: ../../include/recipient_list.h
+verify.o: ../../include/mail_server.h
--- /dev/null
+/*++
+/* NAME
+/* verify 8
+/* SUMMARY
+/* Postfix address verification server
+/* SYNOPSIS
+/* \fBverify\fR [generic Postfix daemon options]
+/* DESCRIPTION
+/* The Postfix address verification server maintains a record
+/* of what recipient addresses are known to be deliverable or
+/* undeliverable.
+/*
+/* Addresses are verified by submitting probe messages to the
+/* Postfix queue. Probe messages are run through all the routing
+/* and rewriting machinery except for final delivery, and are
+/* discarded rather than being deferred or bounced.
+/*
+/* Address verification relies on the answer from the nearest
+/* MTA for the specified address, and will therefore not detect
+/* all undeliverable addresses.
+/*
+/* This server is designed to run under control by the Postfix
+/* master server. It maintains an optional persistent database.
+/* To avoid being interrupted by "postfix stop" in the middle
+/* of a database update, the process runs in a separate process
+/* group.
+/*
+/* This server implements the following requests:
+/* .IP "\fBVRFY_ADDR_UPDATE\fI address status text\fR"
+/* Update the status of the specified address.
+/* .IP "\fBVRFY_ADDR_QUERY\fI address\fR"
+/* Look up the \fIstatus\fR and \fItext\fR of the specified address.
+/* If the status is unknown, a probe is sent and a default status is
+/* returned.
+/* .PP
+/* The server reply status is one of:
+/* .IP \fBVRFYSTAT_OK\fR
+/* The request completed normally.
+/* .IP \fBVRFYSTAT_BAD\fR
+/* The server rejected the request (bad request name, bad
+/* request parameter value).
+/* .IP \fBVRFYSTAT_FAIL\fR
+/* The request failed.
+/* .PP
+/* The recipient status is one of:
+/* .IP \fBDEL_RCPT_STAT_OK\fR
+/* The address is deliverable.
+/* .IP \fBDEL_RCPT_STAT_DEFER\fR
+/* The address is undeliverable due to a temporary problem.
+/* .IP \fBDEL_RCPT_STAT_BOUNCE\fR
+/* The address is undeliverable due to a permanent problem.
+/* .IP \fBDEL_RCPT_STAT_TODO\fR
+/* The address status is being determined.
+/* SECURITY
+/* .ad
+/* .fi
+/* The address verification server is not security-sensitive. It does
+/* not talk to the network, and it does not talk to local users.
+/* The verify server can run chrooted at fixed low privilege.
+/*
+/* The address verification server can be coerced to store
+/* unlimited amounts of garbage. Limiting the cache size
+/* trades one problem (disk space exhaustion) for another
+/* one (poor response time to client requests).
+/* DIAGNOSTICS
+/* Problems and transactions are logged to \fBsyslogd\fR(8).
+/* BUGS
+/* This prototype server uses synchronous submission for sending
+/* a probe message, which can be slow on a busy machine.
+/*
+/* If the persistent database ever gets corrupted then the world
+/* comes to an end and human intervention is needed. This violates
+/* a basic Postfix principle.
+/* CONFIGURATION PARAMETERS
+/* .ad
+/* .fi
+/* See the Postfix \fBmain.cf\fR file for syntax details and for
+/* default values. Use the \fBpostfix reload\fR command after a
+/* configuration change.
+/* .IP \fBaddress_verify_map\fR
+/* Optional table for persistent recipient status storage. The file
+/* is opened before the process enters a chroot jail and before
+/* it drops root privileges.
+/* By default, the information is kept in volatile memory,
+/* and is lost after \fBpostfix reload\fR or \fBpostfix stop\fR.
+/* .sp
+/* To recover from a corrupted address verification database,
+/* delete the file and do \fBpostfix reload\fR.
+/* .IP \fBaddress_verify_sender\fR
+/* The sender address to use for probe messages. Specify an empty
+/* value (\fBaddress_verify_sender =\fR) or \fB<>\fR if you want
+/* to use the null sender address.
+/* .IP \fBaddress_verify_positive_expire_time\fR
+/* The amount of time after which a known to be good address expires.
+/* .IP \fBaddress_verify_positive_refresh_time\fR
+/* The minimal amount of time after which a proactive probe is sent to
+/* verify that a known to be good address is still good. The address
+/* status is not updated when the probe fails (optimistic caching).
+/* .IP \fBaddress_verify_negative_cache\fR
+/* A boolean parameter that controls whether negative probe results
+/* are stored in the address verification cache. When enabled, the
+/* cache may pollute quickly with garbage. When disabled, Postfix
+/* will generate an address probe for every lookup.
+/* .IP \fBaddress_verify_negative_expire_time\fR
+/* The amount of time after which a rejected address expires.
+/* .IP \fBaddress_verify_negative_refresh_time\fR
+/* The minimal amount of time after which a proactive probe is sent to
+/* verify that a known to be bad address is still bad.
+/* SEE ALSO
+/* verify_clnt(3) address verification client
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <mymalloc.h>
+#include <htable.h>
+#include <dict_ht.h>
+#include <dict.h>
+#include <split_at.h>
+
+/* Global library. */
+
+#include <mail_conf.h>
+#include <mail_params.h>
+#include <mail_proto.h>
+#include <post_mail.h>
+#include <verify_clnt.h>
+
+/* Single server skeleton. */
+
+#include <mail_server.h>
+
+/* Application-specific. */
+
+ /*
+ * Tunable parameters.
+ */
+char *var_verify_map;
+int var_verify_pos_exp;
+int var_verify_pos_try;
+int var_verify_neg_exp;
+int var_verify_neg_try;
+char *var_verify_sender;
+
+ /*
+ * State.
+ */
+static DICT *verify_map;
+
+ /*
+ * Silly little macros.
+ */
+#define STR(x) vstring_str(x)
+#define STREQ(x,y) (strcmp(x,y) == 0)
+
+ /*
+ * The address verification database consists of (address, data) tuples. The
+ * format of the data field is "status:probed:updated:text". The meaning of
+ * each field is:
+ *
+ * status: one of the four recipient status codes (OK, DEFER, BOUNCE or TODO).
+ * In the case of TODO, we have no information about the address, and the
+ * address is being probed.
+ *
+ * probed: if non-zero, the time of the last outstanding address probe. If
+ * zero, there is no outstanding address probe.
+ *
+ * updated: if non-zero, the time of the last processed address probe. If zero,
+ * we have no information about the address, and the address is being
+ * probed.
+ *
+ * text: descriptive text from delivery agents etc.
+ */
+
+ /*
+ * Quick test to see status without parsing the whole entry.
+ */
+#define STATUS_FROM_RAW_ENTRY(e) atoi(e)
+
+/* verify_make_entry - construct table entry */
+
+static void verify_make_entry(VSTRING *buf, int status, long probed,
+ long updated, const char *text)
+{
+ vstring_sprintf(buf, "%d:%ld:%ld:%s", status, probed, updated, text);
+}
+
+/* verify_parse_entry - parse table entry */
+
+static int verify_parse_entry(char *buf, int *status, long *probed,
+ long *updated, char **text)
+{
+ char *probed_text;
+ char *updated_text;
+
+ if ((probed_text = split_at(buf, ':')) != 0
+ && (updated_text = split_at(probed_text, ':')) != 0
+ && (*text = split_at(updated_text, ':')) != 0) {
+ *probed = atol(probed_text);
+ *updated = atol(updated_text);
+ *status = atoi(buf);
+ if ((*status == DEL_RCPT_STAT_OK
+ || *status == DEL_RCPT_STAT_DEFER
+ || *status == DEL_RCPT_STAT_BOUNCE
+ || *status == DEL_RCPT_STAT_TODO)
+ && (probed || updated))
+ return (0);
+ }
+ msg_warn("bad address verify table entry: %.100s", buf);
+ return (-1);
+}
+
+/* verify_stat2name - status to name */
+
+static const char *verify_stat2name(int addr_status)
+{
+ if (addr_status == DEL_RCPT_STAT_OK)
+ return ("deliverable");
+ if (addr_status == DEL_RCPT_STAT_DEFER)
+ return ("undeliverable");
+ if (addr_status == DEL_RCPT_STAT_BOUNCE)
+ return ("undeliverable");
+ return (0);
+}
+
+/* verify_update_service - update address service */
+
+static void verify_update_service(VSTREAM *client_stream)
+{
+ VSTRING *buf = vstring_alloc(10);
+ VSTRING *addr = vstring_alloc(10);
+ int addr_status;
+ VSTRING *text = vstring_alloc(10);
+ const char *status_name;
+ const char *raw_data;
+ long probed;
+ long updated;
+
+ if (attr_scan(client_stream, ATTR_FLAG_STRICT,
+ ATTR_TYPE_STR, MAIL_ATTR_ADDR, addr,
+ ATTR_TYPE_NUM, MAIL_ATTR_ADDR_STATUS, &addr_status,
+ ATTR_TYPE_STR, MAIL_ATTR_WHY, text,
+ ATTR_TYPE_END) == 3) {
+ if ((status_name = verify_stat2name(addr_status)) == 0) {
+ msg_warn("bad recipient status %d for recipient %s",
+ addr_status, STR(addr));
+ attr_print(client_stream, ATTR_FLAG_NONE,
+ ATTR_TYPE_NUM, MAIL_ATTR_STATUS, VRFY_STAT_BAD,
+ ATTR_TYPE_END);
+ } else {
+
+ /*
+ * Robustness: don't allow a failed probe to clobber an OK
+ * address before it expires. The failed probe is ignored so that
+ * the address will be re-probed upon the next query. As long as
+ * some probes succeed the address will remain cached as OK.
+ */
+ if (addr_status == DEL_RCPT_STAT_OK
+ || (raw_data = dict_get(verify_map, STR(addr))) == 0
+ || STATUS_FROM_RAW_ENTRY(raw_data) != DEL_RCPT_STAT_OK) {
+ probed = 0;
+ updated = (long) time((time_t *) 0);
+ verify_make_entry(buf, addr_status, probed, updated, STR(text));
+ if (msg_verbose)
+ msg_info("PUT %s status=%d probed=%ld updated=%ld text=%s",
+ STR(addr), addr_status, probed, updated, STR(text));
+ dict_put(verify_map, STR(addr), STR(buf));
+ }
+ attr_print(client_stream, ATTR_FLAG_NONE,
+ ATTR_TYPE_NUM, MAIL_ATTR_STATUS, VRFY_STAT_OK,
+ ATTR_TYPE_END);
+ }
+ }
+ vstring_free(buf);
+ vstring_free(addr);
+ vstring_free(text);
+}
+
+/* verify_query_service - query address status */
+
+static void verify_query_service(VSTREAM *client_stream)
+{
+ VSTRING *addr = vstring_alloc(10);
+ VSTRING *get_buf = 0;
+ VSTRING *put_buf = 0;
+ const char *raw_data;
+ int addr_status;
+ long probed;
+ long updated;
+ char *text;
+ VSTREAM *post;
+
+ if (attr_scan(client_stream, ATTR_FLAG_STRICT,
+ ATTR_TYPE_STR, MAIL_ATTR_ADDR, addr,
+ ATTR_TYPE_END) == 1) {
+ long now = (long) time((time_t *) 0);
+
+ /*
+ * Produce a default record when no usable record exists.
+ *
+ * If negative caching is disabled, purge an expired record from the
+ * database.
+ *
+ * XXX Assume that a probe is lost if no response is received in 1000
+ * seconds. If this number is too small the queue will slowly fill up
+ * with delayed probes.
+ *
+ * XXX Maintain a moving average for the probe turnaround time, and
+ * allow probe "retransmission" when a probe is outstanding for, say
+ * some minimal amount of time (1000 sec) plus several times the
+ * observed probe turnaround time. This causes probing to back off
+ * when the mail system becomes congested.
+ */
+#define POSITIVE_ENTRY_EXPIRED(addr_status, updated) \
+ (addr_status == DEL_RCPT_STAT_OK && updated + var_verify_pos_exp < now)
+#define NEGATIVE_ENTRY_EXPIRED(addr_status, updated) \
+ (addr_status != DEL_RCPT_STAT_OK && updated + var_verify_neg_exp < now)
+#define PROBE_TTL 1000
+
+ if ((raw_data = dict_get(verify_map, STR(addr))) == 0 /* not found */
+ || ((get_buf = vstring_alloc(10)),
+ vstring_strcpy(get_buf, raw_data), /* malformed */
+ verify_parse_entry(STR(get_buf), &addr_status, &probed,
+ &updated, &text) < 0)
+ || (now - probed > PROBE_TTL /* safe to probe */
+ && (POSITIVE_ENTRY_EXPIRED(addr_status, updated)
+ || NEGATIVE_ENTRY_EXPIRED(addr_status, updated)))) {
+ addr_status = DEL_RCPT_STAT_TODO;
+ probed = 0;
+ updated = 0;
+ text = "Address verification in progress";
+ if (raw_data != 0 && var_verify_neg_cache == 0)
+ dict_del(verify_map, STR(addr));
+ }
+ if (msg_verbose)
+ msg_info("GOT %s status=%d probed=%ld updated=%ld text=%s",
+ STR(addr), addr_status, probed, updated, text);
+
+ /*
+ * Respond to the client.
+ */
+ attr_print(client_stream, ATTR_FLAG_NONE,
+ ATTR_TYPE_NUM, MAIL_ATTR_STATUS, VRFY_STAT_OK,
+ ATTR_TYPE_NUM, MAIL_ATTR_ADDR_STATUS, addr_status,
+ ATTR_TYPE_STR, MAIL_ATTR_WHY, text,
+ ATTR_TYPE_END);
+
+ /*
+ * Send a new probe when the information needs to be refreshed.
+ *
+ * XXX For an initial proof of concept implementation, use synchronous
+ * mail submission. This needs to be made async for high-volume
+ * sites, which makes it even more interesting to eliminate duplicate
+ * queries while a probe is being built.
+ *
+ * If negative caching is turned off, update the database only when
+ * refreshing an existing entry.
+ */
+#define POSITIVE_REFRESH_NEEDED(addr_status, updated) \
+ (addr_status == DEL_RCPT_STAT_OK && updated + var_verify_pos_try < now)
+#define NEGATIVE_REFRESH_NEEDED(addr_status, updated) \
+ (addr_status != DEL_RCPT_STAT_OK && updated + var_verify_neg_try < now)
+#define NULL_CLEANUP_FLAGS 0
+
+ if (now - probed > PROBE_TTL
+ && (POSITIVE_REFRESH_NEEDED(addr_status, updated)
+ || NEGATIVE_REFRESH_NEEDED(addr_status, updated))) {
+ if (msg_verbose)
+ msg_info("PROBE %s status=%d probed=%ld updated=%ld",
+ STR(addr), addr_status, now, updated);
+ if ((post = post_mail_fopen(strcmp(var_verify_sender, "<>") == 0 ?
+ "" : var_verify_sender, STR(addr),
+ NULL_CLEANUP_FLAGS,
+ DEL_REQ_FLAG_VERIFY)) != 0
+ && post_mail_fclose(post) == 0
+ && (updated != 0 || var_verify_neg_cache != 0)) {
+ put_buf = vstring_alloc(10);
+ verify_make_entry(put_buf, addr_status, now, updated, text);
+ if (msg_verbose)
+ msg_info("PUT %s status=%d probed=%ld updated=%ld text=%s",
+ STR(addr), addr_status, now, updated, text);
+ dict_put(verify_map, STR(addr), STR(put_buf));
+ }
+ }
+ }
+ vstring_free(addr);
+ if (get_buf)
+ vstring_free(get_buf);
+ if (put_buf)
+ vstring_free(put_buf);
+}
+
+/* verify_service - perform service for client */
+
+static void verify_service(VSTREAM *client_stream, char *unused_service,
+ char **argv)
+{
+ VSTRING *request = vstring_alloc(10);
+
+ /*
+ * Sanity check. This service takes no command-line arguments.
+ */
+ if (argv[0])
+ msg_fatal("unexpected command-line argument: %s", argv[0]);
+
+ /*
+ * This routine runs whenever a client connects to the socket dedicated
+ * to the address verification service. All connection-management stuff
+ * is handled by the common code in multi_server.c.
+ */
+ if (attr_scan(client_stream,
+ ATTR_FLAG_MORE | ATTR_FLAG_STRICT,
+ ATTR_TYPE_STR, MAIL_ATTR_REQ, request,
+ ATTR_TYPE_END) == 1) {
+ if (STREQ(STR(request), VRFY_REQ_UPDATE)) {
+ verify_update_service(client_stream);
+ } else if (STREQ(STR(request), VRFY_REQ_QUERY)) {
+ verify_query_service(client_stream);
+ } else {
+ msg_warn("unrecognized request: \"%s\", ignored", STR(request));
+ attr_print(client_stream, ATTR_FLAG_NONE,
+ ATTR_TYPE_NUM, MAIL_ATTR_STATUS, VRFY_STAT_BAD,
+ ATTR_TYPE_END);
+ }
+ }
+ vstream_fflush(client_stream);
+ vstring_free(request);
+}
+
+/* post_jail_init - post-jail initialization */
+
+static void post_jail_init(char *unused_name, char **unused_argv)
+{
+
+ /*
+ * If the database is in volatile memory only, prevent automatic process
+ * suicide after a limited number of client requests or after a limited
+ * amount of idle time.
+ */
+ if (*var_verify_map == 0) {
+ var_use_limit = 0;
+ var_idle_limit = 0;
+ }
+}
+
+/* pre_jail_init - pre-jail initialization */
+
+static void pre_jail_init(char *unused_name, char **unused_argv)
+{
+ mode_t saved_mask;
+
+ /*
+ * Keep state in persistent (external) or volatile (internal) map.
+ */
+#define VERIFY_DICT_OPEN_FLAGS (DICT_FLAG_DUP_REPLACE | DICT_FLAG_SYNC_UPDATE)
+
+ if (*var_verify_map) {
+ saved_mask = umask(022);
+ verify_map = dict_open(var_verify_map,
+ O_CREAT | O_RDWR,
+ VERIFY_DICT_OPEN_FLAGS);
+ (void) umask(saved_mask);
+ } else {
+ verify_map = dict_ht_open("verify", htable_create(0), myfree);
+ }
+
+ /*
+ * Never, ever, get killed by a master signal, as that would corrupt the
+ * database when we're in the middle of an update.
+ */
+ setsid();
+}
+
+/* main - pass control to the single-threaded skeleton */
+
+int main(int argc, char **argv)
+{
+ static CONFIG_STR_TABLE str_table[] = {
+ VAR_VERIFY_MAP, DEF_VERIFY_MAP, &var_verify_map, 0, 0,
+ VAR_VERIFY_SENDER, DEF_VERIFY_SENDER, &var_verify_sender, 0, 0,
+ 0,
+ };
+ static CONFIG_TIME_TABLE time_table[] = {
+ VAR_VERIFY_POS_EXP, DEF_VERIFY_POS_EXP, &var_verify_pos_exp, 1, 0,
+ VAR_VERIFY_POS_TRY, DEF_VERIFY_POS_TRY, &var_verify_pos_try, 1, 0,
+ VAR_VERIFY_NEG_EXP, DEF_VERIFY_NEG_EXP, &var_verify_neg_exp, 1, 0,
+ VAR_VERIFY_NEG_TRY, DEF_VERIFY_NEG_TRY, &var_verify_neg_try, 1, 0,
+ 0,
+ };
+
+ multi_server_main(argc, argv, verify_service,
+ MAIL_SERVER_STR_TABLE, str_table,
+ MAIL_SERVER_TIME_TABLE, time_table,
+ MAIL_SERVER_PRE_INIT, pre_jail_init,
+ MAIL_SERVER_POST_INIT, post_jail_init,
+ MAIL_SERVER_SOLITARY,
+ 0);
+}
mailbox.o: ../../include/safe_open.h
mailbox.o: ../../include/defer.h
mailbox.o: ../../include/bounce.h
+mailbox.o: ../../include/deliver_request.h
+mailbox.o: ../../include/recipient_list.h
mailbox.o: ../../include/sent.h
mailbox.o: ../../include/mail_params.h
mailbox.o: ../../include/virtual8_maps.h
mailbox.o: ../../include/dict.h
mailbox.o: ../../include/argv.h
mailbox.o: virtual.h
-mailbox.o: ../../include/deliver_request.h
-mailbox.o: ../../include/recipient_list.h
mailbox.o: ../../include/mbox_conf.h
maildir.o: maildir.c
maildir.o: ../../include/sys_defs.h
maildir.o: ../../include/sane_fsops.h
maildir.o: ../../include/mail_copy.h
maildir.o: ../../include/bounce.h
+maildir.o: ../../include/deliver_request.h
+maildir.o: ../../include/recipient_list.h
maildir.o: ../../include/defer.h
maildir.o: ../../include/sent.h
maildir.o: ../../include/mail_params.h
maildir.o: virtual.h
-maildir.o: ../../include/deliver_request.h
-maildir.o: ../../include/recipient_list.h
maildir.o: ../../include/maps.h
maildir.o: ../../include/dict.h
maildir.o: ../../include/argv.h
recipient.o: ../../include/vstring.h
recipient.o: ../../include/vbuf.h
recipient.o: ../../include/bounce.h
-recipient.o: virtual.h
-recipient.o: ../../include/vstream.h
recipient.o: ../../include/deliver_request.h
+recipient.o: ../../include/vstream.h
recipient.o: ../../include/recipient_list.h
+recipient.o: virtual.h
recipient.o: ../../include/maps.h
recipient.o: ../../include/dict.h
recipient.o: ../../include/argv.h
unknown.o: ../../include/sys_defs.h
unknown.o: ../../include/msg.h
unknown.o: ../../include/bounce.h
-unknown.o: virtual.h
-unknown.o: ../../include/vstream.h
-unknown.o: ../../include/vbuf.h
-unknown.o: ../../include/vstring.h
unknown.o: ../../include/deliver_request.h
+unknown.o: ../../include/vstring.h
+unknown.o: ../../include/vbuf.h
+unknown.o: ../../include/vstream.h
unknown.o: ../../include/recipient_list.h
+unknown.o: virtual.h
unknown.o: ../../include/maps.h
unknown.o: ../../include/dict.h
unknown.o: ../../include/argv.h
if (msg_verbose)
MSG_LOG_STATE(myname, state);
+ /*
+ * Don't deliver trace-only requests.
+ */
+ if (DEL_REQ_TRACE_ONLY(state.request->flags))
+ return (sent(BOUNCE_FLAGS(state.request), SENT_ATTR(state.msg_attr),
+ "delivers to mailbox"));
+
/*
* Initialize. Assume the operation will fail. Set the delivered
* attribute to reflect the final recipient.
} else if (mail_copy_status != 0) {
deliver_status = (errno == EDQUOT || errno == EFBIG ?
bounce_append : defer_append)
- (BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+ (BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr),
"mailbox %s: %s", usr_attr.mailbox, vstring_str(why));
} else {
- deliver_status = sent(SENT_ATTR(state.msg_attr), "mailbox");
+ deliver_status = sent(BOUNCE_FLAGS(state.request),
+ SENT_ATTR(state.msg_attr),
+ "delivered to mailbox");
}
vstring_free(why);
return (deliver_status);
if (dict_errno == 0)
return (NO);
- *statusp = defer_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+ *statusp = defer_append(BOUNCE_FLAGS(state.request),
+ BOUNCE_ATTR(state.msg_attr),
"%s: lookup %s: %m",
virtual_mailbox_maps->title, state.msg_attr.user);
return (YES);
*/
uid_res = virtual8_maps_find(virtual_uid_maps, state.msg_attr.user);
if (uid_res == 0) {
- *statusp = defer_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+ *statusp = defer_append(BOUNCE_FLAGS(state.request),
+ BOUNCE_ATTR(state.msg_attr),
"recipient %s: uid not found in %s",
state.msg_attr.user, virtual_uid_maps->title);
RETURN(YES);
}
if ((n = atol(uid_res)) < var_virt_minimum_uid) {
- *statusp = defer_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+ *statusp = defer_append(BOUNCE_FLAGS(state.request),
+ BOUNCE_ATTR(state.msg_attr),
"recipient %s: bad uid %s in %s",
state.msg_attr.user, uid_res, virtual_uid_maps->title);
RETURN(YES);
*/
gid_res = virtual8_maps_find(virtual_gid_maps, state.msg_attr.user);
if (gid_res == 0) {
- *statusp = defer_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+ *statusp = defer_append(BOUNCE_FLAGS(state.request),
+ BOUNCE_ATTR(state.msg_attr),
"recipient %s: gid not found in %s",
state.msg_attr.user, virtual_gid_maps->title);
RETURN(YES);
}
if ((n = atol(gid_res)) <= 0) {
- *statusp = defer_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+ *statusp = defer_append(BOUNCE_FLAGS(state.request),
+ BOUNCE_ATTR(state.msg_attr),
"recipient %s: bad gid %s in %s",
state.msg_attr.user, gid_res, virtual_gid_maps->title);
RETURN(YES);
if (msg_verbose)
MSG_LOG_STATE(myname, state);
+ /*
+ * Don't deliver trace-only requests.
+ */
+ if (DEL_REQ_TRACE_ONLY(state.request->flags))
+ return (sent(BOUNCE_FLAGS(state.request), SENT_ATTR(state.msg_attr),
+ "delivers to maildir"));
+
/*
* Initialize. Assume the operation will fail. Set the delivered
* attribute to reflect the final recipient.
} else if (mail_copy_status != 0) {
deliver_status = (errno == EDQUOT || errno == EFBIG ?
bounce_append : defer_append)
- (BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+ (BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr),
"maildir delivery failed: %s", vstring_str(why));
} else {
- deliver_status = sent(SENT_ATTR(state.msg_attr), "maildir");
+ deliver_status = sent(BOUNCE_FLAGS(state.request),
+ SENT_ATTR(state.msg_attr),
+ "delivered to maildir");
}
vstring_free(buf);
vstring_free(why);
if (msg_verbose)
MSG_LOG_STATE(myname, state);
- return (bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+ return (bounce_append(BOUNCE_FLAGS(state.request),
+ BOUNCE_ATTR(state.msg_attr),
"unknown user: \"%s\"", state.msg_attr.user));
-
}
/*
* Bundle up some often-user attributes.
*/
+#define BOUNCE_FLAGS(request) DEL_REQ_TRACE_FLAGS((request)->flags)
+
#define BOUNCE_ATTR(attr) attr.queue_id, attr.orig_rcpt, attr.recipient, \
attr.relay, attr.arrival_time
#define SENT_ATTR(attr) attr.queue_id, attr.orig_rcpt, attr.recipient, \