+ g = string_catn(g, US"*", 1);
+
+#ifndef DISABLE_EVENT
+ deliver_host_address = addr->host_used->address;
+ deliver_host_port = addr->host_used->port;
+ deliver_host = addr->host_used->name;
+
+ /* DNS lookup status */
+ lookup_dnssec_authenticated = addr->host_used->dnssec==DS_YES ? US"yes"
+ : addr->host_used->dnssec==DS_NO ? US"no"
+ : NULL;
+#endif
+ }
+
+#ifndef DISABLE_TLS
+ g = d_tlslog(g, addr);
+#endif
+
+ if (addr->authenticator)
+ {
+ g = string_append(g, 2, US" A=", addr->authenticator);
+ if (addr->auth_id)
+ {
+ g = string_append(g, 2, US":", addr->auth_id);
+ if (LOGGING(smtp_mailauth) && addr->auth_sndr)
+ g = string_append(g, 2, US":", addr->auth_sndr);
+ }
+ }
+
+ if (LOGGING(pipelining))
+ {
+ if (testflag(addr, af_pipelining))
+ g = string_catn(g, US" L", 2);
+#ifndef DISABLE_PIPE_CONNECT
+ if (testflag(addr, af_early_pipe))
+ g = string_catn(g, US"*", 1);
+#endif
+ }
+
+#ifndef DISABLE_PRDR
+ if (testflag(addr, af_prdr_used))
+ g = string_catn(g, US" PRDR", 5);
+#endif
+
+ if (testflag(addr, af_chunking_used))
+ g = string_catn(g, US" K", 2);
+ }
+
+/* confirmation message (SMTP (host_used) and LMTP (driver_name)) */
+
+if ( LOGGING(smtp_confirmation)
+ && addr->message
+ && (addr->host_used || Ustrcmp(addr->transport->driver_name, "lmtp") == 0)
+ )
+ {
+ unsigned lim = big_buffer_size < 1024 ? big_buffer_size : 1024;
+ uschar *p = big_buffer;
+ uschar *ss = addr->message;
+ *p++ = '\"';
+ for (int i = 0; i < lim && ss[i] != 0; i++) /* limit logged amount */
+ {
+ if (ss[i] == '\"' || ss[i] == '\\') *p++ = '\\'; /* quote \ and " */
+ *p++ = ss[i];
+ }
+ *p++ = '\"';
+ *p = 0;
+ g = string_append(g, 2, US" C=", big_buffer);
+ }
+
+/* Time on queue and actual time taken to deliver */
+
+if (LOGGING(queue_time))
+ g = string_append(g, 2, US" QT=",
+ string_timesince(&received_time));
+
+if (LOGGING(deliver_time))
+ g = string_append(g, 2, US" DT=", string_timediff(&addr->delivery_time));
+
+/* string_cat() always leaves room for the terminator. Release the
+store we used to build the line after writing it. */
+
+log_write(0, flags, "%s", string_from_gstring(g));
+
+#ifndef DISABLE_EVENT
+if (!msg) msg_event_raise(US"msg:delivery", addr);
+#endif
+
+store_reset(reset_point);
+return;
+}
+
+
+
+static void
+deferral_log(address_item * addr, uschar * now,
+ int logflags, uschar * driver_name, uschar * driver_kind)
+{
+rmark reset_point = store_mark();
+gstring * g = string_get(256);
+
+/* Build up the line that is used for both the message log and the main
+log. */
+
+/* Create the address string for logging. Must not do this earlier, because
+an OK result may be changed to FAIL when a pipe returns text. */
+
+g = string_log_address(g, addr, LOGGING(all_parents), FALSE);
+
+if (*queue_name)
+ g = string_append(g, 2, US" Q=", queue_name);
+
+/* Either driver_name contains something and driver_kind contains
+" router" or " transport" (note the leading space), or driver_name is
+a null string and driver_kind contains "routing" without the leading
+space, if all routing has been deferred. When a domain has been held,
+so nothing has been done at all, both variables contain null strings. */
+
+if (driver_name)
+ {
+ if (driver_kind[1] == 't' && addr->router)
+ g = string_append(g, 2, US" R=", addr->router->name);
+ g = string_fmt_append(g, " %c=%s", toupper(driver_kind[1]), driver_name);
+ }
+else if (driver_kind)
+ g = string_append(g, 2, US" ", driver_kind);
+
+g = string_fmt_append(g, " defer (%d)", addr->basic_errno);
+
+if (addr->basic_errno > 0)
+ g = string_append(g, 2, US": ",
+ US strerror(addr->basic_errno));
+
+if (addr->host_used)
+ {
+ g = string_append(g, 5,
+ US" H=", addr->host_used->name,
+ US" [", addr->host_used->address, US"]");
+ if (LOGGING(outgoing_port))
+ {
+ int port = addr->host_used->port;
+ g = string_fmt_append(g, ":%d", port == PORT_NONE ? 25 : port);
+ }
+ }
+
+if (LOGGING(deliver_time))
+ g = string_append(g, 2, US" DT=", string_timediff(&addr->delivery_time));
+
+if (addr->message)
+ g = string_append(g, 2, US": ", addr->message);
+
+(void) string_from_gstring(g);
+
+/* Log the deferment in the message log, but don't clutter it
+up with retry-time defers after the first delivery attempt. */
+
+if (f.deliver_firsttime || addr->basic_errno > ERRNO_RETRY_BASE)
+ deliver_msglog("%s %s\n", now, g->s);
+
+/* Write the main log and reset the store.
+For errors of the type "retry time not reached" (also remotes skipped
+on queue run), logging is controlled by L_retry_defer. Note that this kind
+of error number is negative, and all the retry ones are less than any
+others. */
+
+
+log_write(addr->basic_errno <= ERRNO_RETRY_BASE ? L_retry_defer : 0, logflags,
+ "== %s", g->s);
+
+store_reset(reset_point);
+return;
+}
+
+
+
+static void
+failure_log(address_item * addr, uschar * driver_kind, uschar * now)
+{
+rmark reset_point = store_mark();
+gstring * g = string_get(256);
+
+#ifndef DISABLE_EVENT
+/* Message failures for which we will send a DSN get their event raised
+later so avoid doing it here. */
+
+if ( !addr->prop.ignore_error
+ && !(addr->dsn_flags & (rf_dsnflags & ~rf_notify_failure))
+ )
+ msg_event_raise(US"msg:fail:delivery", addr);
+#endif
+
+/* Build up the log line for the message and main logs */
+
+/* Create the address string for logging. Must not do this earlier, because
+an OK result may be changed to FAIL when a pipe returns text. */
+
+g = string_log_address(g, addr, LOGGING(all_parents), FALSE);
+
+if (LOGGING(sender_on_delivery))
+ g = string_append(g, 3, US" F=<", sender_address, US">");
+
+if (*queue_name)
+ g = string_append(g, 2, US" Q=", queue_name);
+
+/* Return path may not be set if no delivery actually happened */
+
+if (used_return_path && LOGGING(return_path_on_delivery))
+ g = string_append(g, 3, US" P=<", used_return_path, US">");
+
+if (addr->router)
+ g = string_append(g, 2, US" R=", addr->router->name);
+if (addr->transport)
+ g = string_append(g, 2, US" T=", addr->transport->name);
+
+if (addr->host_used)
+ g = d_hostlog(g, addr);
+
+#ifndef DISABLE_TLS
+g = d_tlslog(g, addr);
+#endif
+
+if (addr->basic_errno > 0)
+ g = string_append(g, 2, US": ", US strerror(addr->basic_errno));