bounce/bounce_warn_service.c.
TODO: unit test coverage.
+
+20211218
+
+ Feature: the postqueue command now also lists recipients
+ in bounce logfiles (in JSON output, this uses a new object
+ member 'bounce_reason' instead of the existing 'delay_reason').
+ Such recipients have already been deleted from the message
+ queue file, but they are still pending the creation of a
+ non-delivery status notification message that will be
+ returned to the sender. Files: showq/showq.c,
+ postqueue/showq_compat.c, postqueue/showq_json.c.
+
+ Wordsmiting: after a queue manager request failure to
+ generate a verp-style delivery status notification, log
+ "verp-bounce failed" instead of "verp failed". File:
+ global/abounce.c.
Each queue entry shows the queue file ID, message size, arrival
time, sender, and the recipients that still need to be deliv-
ered. If mail could not be delivered upon the last attempt, the
- reason for failure is shown. The queue ID string is followed by
- an optional status character:
+ reason for failure is shown. With Postfix >= 3.11, the output
+ may also show bounced recipients that are pending the creation
+ of a non-delivery status notification message that will be
+ returned to the sender.
- <b>*</b> The message is in the <b>active</b> queue, i.e. the message is
+ The queue ID string is followed by an optional status character:
+
+ <b>*</b> The message is in the <b>active</b> queue, i.e. the message is
selected for delivery.
- <b>!</b> The message is in the <b>hold</b> queue, i.e. no further deliv-
- ery attempt will be made until the mail is taken off
+ <b>!</b> The message is in the <b>hold</b> queue, i.e. no further deliv-
+ ery attempt will be made until the mail is taken off
hold.
- <b>#</b> The message is forced to expire. See the <a href="postsuper.1.html"><b>postsuper</b>(1)</a>
+ <b>#</b> The message is forced to expire. See the <a href="postsuper.1.html"><b>postsuper</b>(1)</a>
options <b>-e</b> or <b>-f</b>.
This feature is available in Postfix 3.5 and later.
<b>-s</b> <i>site</i>
- Schedule immediate delivery of all mail that is queued for the
- named <i>site</i>. A numerical site must be specified as a valid <a href="https://tools.ietf.org/html/rfc5321">RFC</a>
+ Schedule immediate delivery of all mail that is queued for the
+ named <i>site</i>. A numerical site must be specified as a valid <a href="https://tools.ietf.org/html/rfc5321">RFC</a>
<a href="https://tools.ietf.org/html/rfc5321">5321</a> address literal enclosed in [], just like in email
- addresses. The site must be eligible for the "fast flush" ser-
- vice. See <a href="flush.8.html"><b>flush</b>(8)</a> for more information about the "fast flush"
+ addresses. The site must be eligible for the "fast flush" ser-
+ vice. See <a href="flush.8.html"><b>flush</b>(8)</a> for more information about the "fast flush"
service.
- This option implements the traditional "<b>sendmail -qR</b><i>site</i>" com-
+ This option implements the traditional "<b>sendmail -qR</b><i>site</i>" com-
mand, by contacting the Postfix <a href="flush.8.html"><b>flush</b>(8)</a> daemon.
- <b>-v</b> Enable verbose logging for debugging purposes. Multiple <b>-v</b>
- options make the software increasingly verbose. As of Postfix
+ <b>-v</b> Enable verbose logging for debugging purposes. Multiple <b>-v</b>
+ options make the software increasingly verbose. As of Postfix
2.3, this option is available for the super-user only.
<b><a name="json_object_format">JSON OBJECT FORMAT</a></b>
- Each JSON object represents one queue file; it is emitted as a single
+ Each JSON object represents one queue file; it is emitted as a single
text line followed by a newline character.
Object members have string values unless indicated otherwise. Programs
bers is expected to grow over time.
<b>queue_name</b>
- The name of the queue where the message was found. Note that
- the contents of the mail queue may change while it is being
- listed; some messages may appear more than once, and some mes-
+ The name of the queue where the message was found. Note that
+ the contents of the mail queue may change while it is being
+ listed; some messages may appear more than once, and some mes-
sages may be missed.
<b>queue_id</b>
The queue file name. The queue_id may be reused within a Postfix
instance unless "<a href="postconf.5.html#enable_long_queue_ids">enable_long_queue_ids</a> = true" and time is mono-
- tonic. Even then, the queue_id is not expected to be unique
- between different Postfix instances. Management tools that
- require a unique name should combine the queue_id with the
+ tonic. Even then, the queue_id is not expected to be unique
+ between different Postfix instances. Management tools that
+ require a unique name should combine the queue_id with the
<a href="postconf.5.html#myhostname">myhostname</a> setting of the Postfix instance.
<b>arrival_time</b>
The number of seconds since the start of the UNIX epoch.
<b>message_size</b>
- The number of bytes in the message header and body. This number
- does not include message envelope information. It is approxi-
- mately equal to the number of bytes that would be transmitted
+ The number of bytes in the message header and body. This number
+ does not include message envelope information. It is approxi-
+ mately equal to the number of bytes that would be transmitted
via SMTP including the <CR><LF> line endings.
<b>forced_expire</b> (Postfix >= 3.5)
- The message is forced to expire (<b>true</b> or <b>false</b>). See the <a href="postsuper.1.html"><b>post-</b></a>
+ The message is forced to expire (<b>true</b> or <b>false</b>). See the <a href="postsuper.1.html"><b>post-</b></a>
<a href="postsuper.1.html"><b>super</b>(1)</a> options <b>-e</b> or <b>-f</b>.
<b>sender</b> The envelope sender address.
One original recipient address.
<b>delay_reason</b>
- If present, the reason for delayed delivery. Delayed
- recipients may have no delay reason, for example, while
- delivery is in progress, or after the system was stopped
+ If present, the reason for delayed delivery. Delayed
+ recipients may have no delay reason, for example, while
+ delivery is in progress, or after the system was stopped
before it could record the reason.
+ <b>bounce_reason</b> (Postfix >= 3.11)
+ If present, the reason why this recipient was bounced.
+ The recipient is still pending the creation of a
+ non-delivery status notification message that will be
+ returned to the sender.
+
<b><a name="security">SECURITY</a></b>
This program is designed to run with set-group ID privileges, so that
it can connect to Postfix daemon processes.
Each queue entry shows the queue file ID, message
size, arrival time, sender, and the recipients that still need to
be delivered. If mail could not be delivered upon the last attempt,
-the reason for failure is shown. The queue ID string
-is followed by an optional status character:
+the reason for failure is shown. With Postfix >= 3.11, the output
+may also show bounced recipients that are pending the creation
+of a non\-delivery status notification message that will be
+returned to the sender.
+
+The queue ID string is followed by an optional status character:
.RS
.IP \fB*\fR
The message is in the \fBactive\fR queue, i.e. the message is
.RS
.IP \fBaddress\fR
One recipient address.
-.IP "\fBorig_address\fR (Postfix >= 3.11)
+.IP "\fBorig_address\fR (Postfix >= 3.11)"
One original recipient address.
.IP \fBdelay_reason\fR
If present, the reason for delayed delivery. Delayed
recipients may have no delay reason, for example, while
delivery is in progress, or after the system was stopped
before it could record the reason.
+.IP "\fBbounce_reason\fR (Postfix >= 3.11)"
+If present, the reason why this recipient was bounced. The
+recipient is still pending the creation of a non\-delivery status
+notification message that will be returned to the sender.
.RE
.SH "SECURITY"
.na
msg_info("%s: status=deferred (%s failed)", ap->id,
ap->command == BOUNCE_CMD_FLUSH ? "bounce" :
ap->command == BOUNCE_CMD_WARN ? "delay warning" :
- ap->command == BOUNCE_CMD_VERP ? "bounce" :
+ ap->command == BOUNCE_CMD_VERP ? "verp-bounce" :
ap->command == BOUNCE_CMD_TRACE ? "trace" :
"whatever");
ap->callback(status, ap->context);
#define MAIL_ATTR_MESSAGE_ID "message_id" /* Used for threaded bounce */
+#define MAIL_ATTR_LOG_CLASS "log_class" /* bounce/defer/trace */
+
/*
* XCLIENT/XFORWARD in SMTP.
*/
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20251217"
+#define MAIL_RELEASE_DATE "20251218"
#define MAIL_VERSION_NUMBER "3.11"
#ifdef SNAPSHOT
/* Each queue entry shows the queue file ID, message
/* size, arrival time, sender, and the recipients that still need to
/* be delivered. If mail could not be delivered upon the last attempt,
-/* the reason for failure is shown. The queue ID string
-/* is followed by an optional status character:
+/* the reason for failure is shown. With Postfix >= 3.11, the output
+/* may also show bounced recipients that are pending the creation
+/* of a non-delivery status notification message that will be
+/* returned to the sender.
+/*
+/* The queue ID string is followed by an optional status character:
/* .RS
/* .IP \fB*\fR
/* The message is in the \fBactive\fR queue, i.e. the message is
/* .RS
/* .IP \fBaddress\fR
/* One recipient address.
-/* .IP "\fBorig_address\fR (Postfix >= 3.11)
+/* .IP "\fBorig_address\fR (Postfix >= 3.11)"
/* One original recipient address.
/* .IP \fBdelay_reason\fR
/* If present, the reason for delayed delivery. Delayed
/* recipients may have no delay reason, for example, while
/* delivery is in progress, or after the system was stopped
/* before it could record the reason.
+/* .IP "\fBbounce_reason\fR (Postfix >= 3.11)"
+/* If present, the reason why this recipient was bounced. The
+/* recipient is still pending the creation of a non-delivery status
+/* notification message that will be returned to the sender.
/* .RE
/* SECURITY
/* .ad
static VSTRING *id_status = 0;
static VSTRING *oaddr = 0;
static VSTRING *addr = 0;
+ static VSTRING *log_class = 0;
static VSTRING *why = 0;
long arrival_time;
long message_size;
id_status = vstring_alloc(100);
oaddr = vstring_alloc(100);
addr = vstring_alloc(100);
+ log_class = vstring_alloc(100);
why = vstring_alloc(100);
}
| ATTR_FLAG_PRINTABLE,
RECV_ATTR_STR(MAIL_ATTR_ORCPT, oaddr),
RECV_ATTR_STR(MAIL_ATTR_RECIP, addr),
+ RECV_ATTR_STR(MAIL_ATTR_LOG_CLASS, log_class),
RECV_ATTR_STR(MAIL_ATTR_WHY, why),
- ATTR_TYPE_END) != 3)
+ ATTR_TYPE_END) != 4)
msg_fatal_status(EX_SOFTWARE, "malformed showq server response");
/*
static VSTRING *queue_id = 0;
static VSTRING *oaddr = 0;
static VSTRING *addr = 0;
+ static VSTRING *log_class = 0;
static VSTRING *why = 0;
static VSTRING *quote_buf = 0;
long arrival_time;
queue_id = vstring_alloc(100);
oaddr = vstring_alloc(100);
addr = vstring_alloc(100);
+ log_class = vstring_alloc(100);
why = vstring_alloc(100);
quote_buf = vstring_alloc(100);
}
| ATTR_FLAG_PRINTABLE,
RECV_ATTR_STR(MAIL_ATTR_ORCPT, oaddr),
RECV_ATTR_STR(MAIL_ATTR_RECIP, addr),
+ RECV_ATTR_STR(MAIL_ATTR_LOG_CLASS, log_class),
RECV_ATTR_STR(MAIL_ATTR_WHY, why),
- ATTR_TYPE_END) != 3)
+ ATTR_TYPE_END) != 4)
msg_fatal_status(EX_SOFTWARE, "malformed showq server response");
vstream_printf("\"orig_address\": \"%s\", ",
QUOTE_JSON(quote_buf, STR(oaddr)));
vstream_printf("\"address\": \"%s\"",
QUOTE_JSON(quote_buf, STR(addr)));
if (LEN(why) > 0)
- vstream_printf(", \"delay_reason\": \"%s\"",
+ vstream_printf(", \"%s\": \"%s\"",
+ strcmp(STR(log_class), MAIL_QUEUE_DEFER) == 0 ? "delay_reason" :
+ strcmp(STR(log_class), MAIL_QUEUE_BOUNCE) == 0 ? "bounce_reason" :
+ "other_reason",
QUOTE_JSON(quote_buf, STR(why)));
vstream_printf("}");
}
int var_dup_filter_limit;
char *var_empty_addr;
-static void showq_reasons(VSTREAM *, BOUNCE_LOG *, RCPT_BUF *, DSN_BUF *,
- HTABLE *);
+static void showq_reasons(VSTREAM *, const char *, BOUNCE_LOG *, RCPT_BUF *,
+ DSN_BUF *, HTABLE *);
#define STR(x) vstring_str(x)
* interrupted (postfix stop or reload) before all recipients have
* been tried.
*
- * Therefore we keep a record of recipients found in the defer logfile,
- * and try to avoid listing those recipients again when processing
- * recipients from the queue file.
+ * With Postfix 3.11 also list recipients in a bounce logfile. Such
+ * recipients were already deleted from the message file, but they
+ * haven't yet been persisted to a non-delivery status notification
+ * message.
+ *
+ * We remember recipients found in a defer or bounce logfile, and try to
+ * avoid listing those recipients again when processing recipients
+ * from the queue file.
*/
- if (rec_type == REC_TYPE_FROM
- && (logfile = bounce_log_open(MAIL_QUEUE_DEFER, id, O_RDONLY, 0)) != 0) {
+ if (rec_type == REC_TYPE_FROM) {
+ const char *log_names[] = {MAIL_QUEUE_DEFER, MAIL_QUEUE_BOUNCE, 0};
+ const char **cpp;
+
if (dup_filter != 0)
msg_panic("showq_report: attempt to reuse duplicate filter");
- dup_filter = htable_create(var_dup_filter_limit);
if (rcpt_buf == 0)
rcpt_buf = rcpb_create();
if (dsn_buf == 0)
dsn_buf = dsb_create();
- showq_reasons(client, logfile, rcpt_buf, dsn_buf, dup_filter);
- if (bounce_log_close(logfile))
- msg_warn("close %s %s: %m", MAIL_QUEUE_DEFER, id);
+ dup_filter = htable_create(var_dup_filter_limit);
+ for (cpp = log_names; *cpp; cpp++) {
+ if ((logfile = bounce_log_open(*cpp, id, O_RDONLY, 0)) != 0) {
+ showq_reasons(client, *cpp, logfile, rcpt_buf, dsn_buf,
+ dup_filter);
+ if (bounce_log_close(logfile))
+ msg_warn("close %s %s: %m", *cpp, id);
+ }
+ }
}
}
SHOWQ_CLEANUP_AND_RETURN;
}
-/* showq_reasons - show deferral reasons */
+/* showq_reasons - show defer or bounce reasons */
-static void showq_reasons(VSTREAM *client, BOUNCE_LOG *bp, RCPT_BUF *rcpt_buf,
- DSN_BUF *dsn_buf, HTABLE *dup_filter)
+static void showq_reasons(VSTREAM *client, const char *log_class, BOUNCE_LOG *bp,
+ RCPT_BUF *rcpt_buf, DSN_BUF *dsn_buf,
+ HTABLE *dup_filter)
{
RECIPIENT *rcpt = &rcpt_buf->rcpt;
DSN *dsn = &dsn_buf->dsn;
attr_print(client, ATTR_FLAG_MORE,
SEND_ATTR_STR(MAIL_ATTR_ORCPT, rcpt->orig_addr),
SEND_ATTR_STR(MAIL_ATTR_RECIP, rcpt->address),
+ SEND_ATTR_STR(MAIL_ATTR_LOG_CLASS, log_class),
SEND_ATTR_STR(MAIL_ATTR_WHY, dsn->reason),
ATTR_TYPE_END);
}