Remove details of errors in bounce and delay warning messages, unless
authorPhilip Hazel <ph10@hermes.cam.ac.uk>
Thu, 28 Apr 2005 13:06:32 +0000 (13:06 +0000)
committerPhilip Hazel <ph10@hermes.cam.ac.uk>
Thu, 28 Apr 2005 13:06:32 +0000 (13:06 +0000)
explicitly specified (e.g. :fail:) or a message from a remote host.

doc/doc-txt/ChangeLog
src/README.UPDATING
src/src/deliver.c
src/src/routers/queryprogram.c
src/src/routers/redirect.c
src/src/structs.h
src/src/transports/smtp.c

index d8272ab92b07481f2b3e6f5139859bf7e1d70e4b..cbb8e9cbbc45707587f1dd2baa3d9320fe4822f6 100644 (file)
@@ -1,4 +1,4 @@
-$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.127 2005/04/27 13:29:32 ph10 Exp $
+$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.128 2005/04/28 13:06:32 ph10 Exp $
 
 Change log file for Exim from version 4.21
 -------------------------------------------
 
 Change log file for Exim from version 4.21
 -------------------------------------------
@@ -249,6 +249,20 @@ PH/41 $message_linecount is a new variable that contains the total number of
       lines in the message. Compare $body_linecount, which is the count for the
       body only.
 
       lines in the message. Compare $body_linecount, which is the count for the
       body only.
 
+PH/42 Exim no longer gives details of delivery errors for specific addresses in
+      bounce and delay warning messages, except in certain special cases, which
+      are as follows:
+
+      (a) An SMTP error message from a remote host;
+      (b) A message specified in a :fail: redirection;
+      (c) A message specified in a "fail" command in a system filter;
+      (d) A message specified in a FAIL return from the queryprogram router;
+      (e) A message specified by the cannot_route_message router option.
+
+      In these cases only, Exim does include the error details in bounce and
+      warning messages. There are also a few cases where bland messages such
+      as "unrouteable address" or "local delivery error" are given.
+
 
 A note about Exim versions 4.44 and 4.50
 ----------------------------------------
 
 A note about Exim versions 4.44 and 4.50
 ----------------------------------------
index c91c5768069d185e6dee6e173167f67c1a5e5776..efc123c15f4387a0187e4e1a75f5ff27e0c310f0 100644 (file)
@@ -1,4 +1,4 @@
-$Cambridge: exim/src/README.UPDATING,v 1.6 2005/04/06 16:26:42 ph10 Exp $
+$Cambridge: exim/src/README.UPDATING,v 1.7 2005/04/28 13:06:32 ph10 Exp $
 
 This document contains detailed information about incompatibilities that might
 be encountered when upgrading from one release of Exim to another. The
 
 This document contains detailed information about incompatibilities that might
 be encountered when upgrading from one release of Exim to another. The
@@ -50,6 +50,10 @@ uses prefixes or suffixes on addresses that could be used for callouts, and you
 want the affixes to be retained, you must make sure that rcpt_include_affixes
 is set on the transport.
 
 want the affixes to be retained, you must make sure that rcpt_include_affixes
 is set on the transport.
 
+3. Bounce and delay warning messages no longer contain details of delivery
+errors, except for explicit messages (e.g. generated by :fail:) and SMTP
+responses from remote hosts.
+
 
 Version 4.50
 ------------
 
 Version 4.50
 ------------
index 78eb65bc6b2969fcfa5bb56d38f874075c23627c..a7b367d800433951688d66a815905437a1d2552e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/deliver.c,v 1.13 2005/04/07 15:40:50 ph10 Exp $ */
+/* $Cambridge: exim/src/src/deliver.c,v 1.14 2005/04/28 13:06:32 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -4180,7 +4180,6 @@ if (addr->parent != NULL && testflag(addr, af_hide_child))
   printed = US"an undisclosed address";
   yield = FALSE;
   }
   printed = US"an undisclosed address";
   yield = FALSE;
   }
-
 else if (!testflag(addr, af_pfr) || addr->parent == NULL)
   printed = addr->address;
 
 else if (!testflag(addr, af_pfr) || addr->parent == NULL)
   printed = addr->address;
 
@@ -4217,7 +4216,6 @@ return yield;
 
 
 
 
 
 
-
 /*************************************************
 *         Print error for an address             *
 *************************************************/
 /*************************************************
 *         Print error for an address             *
 *************************************************/
@@ -4227,53 +4225,62 @@ a bounce or a warning message. It tries to format the message reasonably by
 introducing newlines. All lines are indented by 4; the initial printing
 position must be set before calling.
 
 introducing newlines. All lines are indented by 4; the initial printing
 position must be set before calling.
 
+This function used always to print the error. Nowadays we want to restrict it
+to cases such as SMTP errors from a remote host, and errors from :fail: and
+filter "fail". We no longer pass other information willy-nilly in bounce and
+warning messages. Text in user_message is always output; text in message only
+if the af_pass_message flag is set.
+
 Arguments:
 Arguments:
-  addr         points to the address
+  addr         the address
   f            the FILE to print on
   f            the FILE to print on
+  s            some leading text
 
 Returns:       nothing
 */
 
 static void
 
 Returns:       nothing
 */
 
 static void
-print_address_error(address_item *addr, FILE *f)
+print_address_error(address_item *addr, FILE *f, uschar *t)
 {
 {
+int count = Ustrlen(t);
 uschar *s = (addr->user_message != NULL)? addr->user_message : addr->message;
 uschar *s = (addr->user_message != NULL)? addr->user_message : addr->message;
-if (addr->basic_errno > 0)
-  {
-  fprintf(f, "%s%s", strerror(addr->basic_errno),
-    (s == NULL)? "" : ":\n    ");
-  }
-if (s == NULL)
+
+if (addr->user_message != NULL)
+  s = addr->user_message;
+else
   {
   {
-  if (addr->basic_errno <= 0) fprintf(f, "unknown error");
+  if (!testflag(addr, af_pass_message) || addr->message == NULL) return;
+  s = addr->message;
   }
   }
-else
+
+fprintf(f, "\n    %s", t);
+
+while (*s != 0)
   {
   {
-  int count = 0;
-  while (*s != 0)
+  if (*s == '\\' && s[1] == 'n')
+    {
+    fprintf(f, "\n    ");
+    s += 2;
+    count = 0;
+    }
+  else
     {
     {
-    if (*s == '\\' && s[1] == 'n')
+    fputc(*s, f);
+    count++;
+    if (*s++ == ':' && isspace(*s) && count > 45)
       {
       {
-      fprintf(f, "\n    ");
-      s += 2;
+      fprintf(f, "\n   ");  /* sic (because space follows) */
       count = 0;
       }
       count = 0;
       }
-    else
-      {
-      fputc(*s, f);
-      count++;
-      if (*s++ == ':' && isspace(*s) && count > 45)
-        {
-        fprintf(f, "\n   ");  /* sic (because space follows) */
-        count = 0;
-        }
-      }
     }
   }
 }
 
 
 
     }
   }
 }
 
 
 
+
+
+
 /*************************************************
 *     Check list of addresses for duplication    *
 *************************************************/
 /*************************************************
 *     Check list of addresses for duplication    *
 *************************************************/
@@ -4994,6 +5001,7 @@ if (process_recipients != RECIP_IGNORE)
         case RECIP_FAIL_FILTER:
         new->message =
           (filter_message == NULL)? US"delivery cancelled" : filter_message;
         case RECIP_FAIL_FILTER:
         new->message =
           (filter_message == NULL)? US"delivery cancelled" : filter_message;
+        setflag(new, af_pass_message);
         goto RECIP_QUEUE_FAILED;   /* below */
 
 
         goto RECIP_QUEUE_FAILED;   /* below */
 
 
@@ -6182,26 +6190,15 @@ wording. */
 
       /* Process the addresses, leaving them on the msgchain if they have a
       file name for a return message. (There has already been a check in
 
       /* Process the addresses, leaving them on the msgchain if they have a
       file name for a return message. (There has already been a check in
-      post_process_one() for the existence of data in the message file.) */
+      post_process_one() for the existence of data in the message file.) A TRUE
+      return from print_address_information() means that the address is not
+      hidden. */
 
       paddr = &msgchain;
       for (addr = msgchain; addr != NULL; addr = *paddr)
         {
         if (print_address_information(addr, f, US"  ", US"\n    ", US""))
 
       paddr = &msgchain;
       for (addr = msgchain; addr != NULL; addr = *paddr)
         {
         if (print_address_information(addr, f, US"  ", US"\n    ", US""))
-          {
-          /* A TRUE return from print_address_information() means that the
-          address is not hidden. If there is a return file, it has already
-          been checked to ensure it is not empty. Omit the bland "return
-          message generated" error, but otherwise include error information. */
-
-          if (addr->return_file < 0 ||
-              addr->message == NULL ||
-              Ustrcmp(addr->message, "return message generated") != 0)
-            {
-            fprintf(f, "\n    ");
-            print_address_error(addr, f);
-            }
-          }
+          print_address_error(addr, f, US"");
 
         /* End the final line for the address */
 
 
         /* End the final line for the address */
 
@@ -6703,21 +6700,15 @@ else if (addr_defer != (address_item *)(+1))
             (addr_defer->next == NULL)? "is": "are");
           }
 
             (addr_defer->next == NULL)? "is": "are");
           }
 
-        /* List the addresses. For any that are hidden, don't give the delay
-        reason, because it might expose that which is hidden. Also, do not give
-        "retry time not reached" because that isn't helpful. */
+        /* List the addresses, with error information if allowed */
 
         fprintf(f, "\n");
         while (addr_defer != NULL)
           {
           address_item *addr = addr_defer;
           addr_defer = addr->next;
 
         fprintf(f, "\n");
         while (addr_defer != NULL)
           {
           address_item *addr = addr_defer;
           addr_defer = addr->next;
-          if (print_address_information(addr, f, US"  ", US"\n    ", US"") &&
-              addr->basic_errno > ERRNO_RETRY_BASE)
-            {
-            fprintf(f, "\n    Delay reason: ");
-            print_address_error(addr, f);
-            }
+          if (print_address_information(addr, f, US"  ", US"\n    ", US""))
+            print_address_error(addr, f, US"Delay reason: ");
           fprintf(f, "\n");
           }
         fprintf(f, "\n");
           fprintf(f, "\n");
           }
         fprintf(f, "\n");
index 5d7a51fdf9dca14c1150a621f5ebc6ef926beb8f..5282a1fa6bdce12cedf75d20808fc487fa6c649e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/routers/queryprogram.c,v 1.3 2005/04/06 14:40:24 ph10 Exp $ */
+/* $Cambridge: exim/src/src/routers/queryprogram.c,v 1.4 2005/04/28 13:06:32 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -416,7 +416,11 @@ if (strcmpic(rword, US"accept") != 0)
   if (strcmpic(rword, US"decline") == 0) return DECLINE;
   if (strcmpic(rword, US"pass") == 0) return PASS;
   addr->message = string_copy(rdata);                /* data is a message */
   if (strcmpic(rword, US"decline") == 0) return DECLINE;
   if (strcmpic(rword, US"pass") == 0) return PASS;
   addr->message = string_copy(rdata);                /* data is a message */
-  if (strcmpic(rword, US"fail") == 0) return FAIL;
+  if (strcmpic(rword, US"fail") == 0)
+    {
+    setflag(addr, af_pass_message);
+    return FAIL;
+    }
   if (strcmpic(rword, US"freeze") == 0) addr->special_action = SPECIAL_FREEZE;
   else if (strcmpic(rword, US"defer") != 0)
     {
   if (strcmpic(rword, US"freeze") == 0) addr->special_action = SPECIAL_FREEZE;
   else if (strcmpic(rword, US"defer") != 0)
     {
index 0153a4d499e704c2f041484408e97effa4b64d97..8e8fc876c5af80642aca54bf5c712c6174e55c44 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/routers/redirect.c,v 1.9 2005/04/06 14:40:24 ph10 Exp $ */
+/* $Cambridge: exim/src/src/routers/redirect.c,v 1.10 2005/04/28 13:06:32 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -655,8 +655,13 @@ switch (frc)
   if ((xrc = sort_errors_and_headers(rblock, addr, verify, &addr_prop)) != OK)
     return xrc;
   add_generated(rblock, addr_new, addr, generated, &addr_prop, &ugid, pw);
   if ((xrc = sort_errors_and_headers(rblock, addr, verify, &addr_prop)) != OK)
     return xrc;
   add_generated(rblock, addr_new, addr, generated, &addr_prop, &ugid, pw);
-  if (addr->message == NULL) addr->message = US"forced rejection";
-    else addr->user_message = addr->message;
+  if (addr->message == NULL)
+    addr->message = US"forced rejection";
+  else
+    {
+    addr->user_message = addr->message;
+    setflag(addr, af_pass_message);
+    }
   return FAIL;
 
   /* As in the case of a system filter, a freeze does not happen after a manual
   return FAIL;
 
   /* As in the case of a system filter, a freeze does not happen after a manual
index 791e11c698eb563fe689539335b8adef76ff5d23..645dfc25cf25b91f2fb888238a5e5253baeb1ae2 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/structs.h,v 1.4 2005/02/17 11:58:26 ph10 Exp $ */
+/* $Cambridge: exim/src/src/structs.h,v 1.5 2005/04/28 13:06:32 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -498,6 +498,7 @@ typedef struct address_item_propagated {
 #define af_verify_callout      0x00400000 /* for cached sender verify: callout was specified */
 #define af_include_affixes     0x00800000 /* delivered with affixes in RCPT */
 #define af_cert_verified       0x01000000 /* delivered with verified TLS cert */
 #define af_verify_callout      0x00400000 /* for cached sender verify: callout was specified */
 #define af_include_affixes     0x00800000 /* delivered with affixes in RCPT */
 #define af_cert_verified       0x01000000 /* delivered with verified TLS cert */
+#define af_pass_message        0x02000000 /* pass message in bounces */
 
 /* These flags must be propagated when a child is created */
 
 
 /* These flags must be propagated when a child is created */
 
index f53d742e4cc89ca80e21abf7f8a05c1afa72f230..69b1c1965bed1544d4b78b631077245f90e6f7f6 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/transports/smtp.c,v 1.10 2005/04/07 10:54:54 ph10 Exp $ */
+/* $Cambridge: exim/src/src/transports/smtp.c,v 1.11 2005/04/28 13:06:32 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -313,10 +313,11 @@ host_build_hostlist(&(ob->fallback_hostlist), ob->fallback_hosts, FALSE);
 status means that an address is not currently being processed.
 
 Arguments:
 status means that an address is not currently being processed.
 
 Arguments:
-  addrlist     points to a chain of addresses
-  errno_value  to put in each address's errno field
-  msg          to put in each address's message field
-  rc           to put in each address's transport_return field
+  addrlist       points to a chain of addresses
+  errno_value    to put in each address's errno field
+  msg            to put in each address's message field
+  rc             to put in each address's transport_return field
+  pass_message   if TRUE, set the "pass message" flag in the address
 
 If errno_value has the special value ERRNO_CONNECTTIMEOUT, ETIMEDOUT is put in
 the errno field, and RTEF_CTOUT is ORed into the more_errno field, to indicate
 
 If errno_value has the special value ERRNO_CONNECTTIMEOUT, ETIMEDOUT is put in
 the errno field, and RTEF_CTOUT is ORed into the more_errno field, to indicate
@@ -326,7 +327,8 @@ Returns:       nothing
 */
 
 static
 */
 
 static
-void set_errno(address_item *addrlist, int errno_value, uschar *msg, int rc)
+void set_errno(address_item *addrlist, int errno_value, uschar *msg, int rc,
+  BOOL pass_message)
 {
 address_item *addr;
 int orvalue = 0;
 {
 address_item *addr;
 int orvalue = 0;
@@ -340,7 +342,11 @@ for (addr = addrlist; addr != NULL; addr = addr->next)
   if (addr->transport_return < PENDING) continue;
   addr->basic_errno = errno_value;
   addr->more_errno |= orvalue;
   if (addr->transport_return < PENDING) continue;
   addr->basic_errno = errno_value;
   addr->more_errno |= orvalue;
-  if (msg != NULL) addr->message = msg;
+  if (msg != NULL)
+    {
+    addr->message = msg;
+    if (pass_message) setflag(addr, af_pass_message);
+    }
   addr->transport_return = rc;
   }
 }
   addr->transport_return = rc;
   }
 }
@@ -358,18 +364,19 @@ the yield variable. If no response was actually read, a suitable digit is
 chosen.
 
 Arguments:
 chosen.
 
 Arguments:
-  host         the current host, to get its name for messages
-  errno_value  pointer to the errno value
-  more_errno   from the top address for use with ERRNO_FILTER_FAIL
-  buffer       the SMTP response buffer
-  yield        where to put a one-digit SMTP response code
-  message      where to put an errror message
-
-Returns:       TRUE if an SMTP "QUIT" command should be sent, else FALSE
+  host           the current host, to get its name for messages
+  errno_value    pointer to the errno value
+  more_errno     from the top address for use with ERRNO_FILTER_FAIL
+  buffer         the SMTP response buffer
+  yield          where to put a one-digit SMTP response code
+  message        where to put an errror message
+  pass_message   set TRUE if message is an SMTP response
+
+Returns:         TRUE if an SMTP "QUIT" command should be sent, else FALSE
 */
 
 static BOOL check_response(host_item *host, int *errno_value, int more_errno,
 */
 
 static BOOL check_response(host_item *host, int *errno_value, int more_errno,
-  uschar *buffer, int *yield, uschar **message)
+  uschar *buffer, int *yield, uschar **message, BOOL *pass_message)
 {
 uschar *pl = US"";
 
 {
 uschar *pl = US"";
 
@@ -444,8 +451,9 @@ if (*errno_value == ERRNO_WRITEINCOMPLETE)
 if (buffer[0] != 0)
   {
   uschar *s = string_printing(buffer);
 if (buffer[0] != 0)
   {
   uschar *s = string_printing(buffer);
-  *message = US string_sprintf("SMTP error from remote mailer after %s%s: "
+  *message = US string_sprintf("SMTP error from remote mail server after %s%s: "
     "host %s [%s]: %s", pl, smtp_command, host->name, host->address, s);
     "host %s [%s]: %s", pl, smtp_command, host->name, host->address, s);
+  *pass_message = TRUE;
   *yield = buffer[0];
   return TRUE;
   }
   *yield = buffer[0];
   return TRUE;
   }
@@ -623,7 +631,7 @@ while (count-- > 0)
     uschar *message = string_sprintf("SMTP timeout while connected to %s [%s] "
       "after RCPT TO:<%s>", host->name, host->address,
       transport_rcpt_address(addr, include_affixes));
     uschar *message = string_sprintf("SMTP timeout while connected to %s [%s] "
       "after RCPT TO:<%s>", host->name, host->address,
       transport_rcpt_address(addr, include_affixes));
-    set_errno(addrlist, save_errno, message, DEFER);
+    set_errno(addrlist, save_errno, message, DEFER, FALSE);
     retry_add_item(addr, addr->address_retry_key, 0);
     host->update_waiting = FALSE;
     return -1;
     retry_add_item(addr, addr->address_retry_key, 0);
     host->update_waiting = FALSE;
     return -1;
@@ -646,9 +654,10 @@ while (count-- > 0)
   else
     {
     addr->message =
   else
     {
     addr->message =
-      string_sprintf("SMTP error from remote mailer after RCPT TO:<%s>: "
+      string_sprintf("SMTP error from remote mail server after RCPT TO:<%s>: "
         "host %s [%s]: %s", transport_rcpt_address(addr, include_affixes),
         host->name, host->address, string_printing(buffer));
         "host %s [%s]: %s", transport_rcpt_address(addr, include_affixes),
         host->name, host->address, string_printing(buffer));
+    setflag(addr, af_pass_message);
     deliver_msglog("%s %s\n", tod_stamp(tod_log), addr->message);
 
     /* The response was 5xx */
     deliver_msglog("%s %s\n", tod_stamp(tod_log), addr->message);
 
     /* The response was 5xx */
@@ -699,8 +708,9 @@ if (pending_DATA != 0 &&
   {
   int code;
   uschar *msg;
   {
   int code;
   uschar *msg;
+  BOOL pass_message;
   if (pending_DATA > 0 || (yield & 1) != 0) return -3;
   if (pending_DATA > 0 || (yield & 1) != 0) return -3;
-  (void)check_response(host, &errno, 0, buffer, &code, &msg);
+  (void)check_response(host, &errno, 0, buffer, &code, &msg, &pass_message);
   DEBUG(D_transport) debug_printf("%s\nerror for DATA ignored: pipelining "
     "is in use and there were no good recipients\n", msg);
   }
   DEBUG(D_transport) debug_printf("%s\nerror for DATA ignored: pipelining "
     "is in use and there were no good recipients\n", msg);
   }
@@ -782,6 +792,7 @@ BOOL setting_up = TRUE;
 BOOL completed_address = FALSE;
 BOOL esmtp = TRUE;
 BOOL pending_MAIL;
 BOOL completed_address = FALSE;
 BOOL esmtp = TRUE;
 BOOL pending_MAIL;
+BOOL pass_message = FALSE;
 smtp_inblock inblock;
 smtp_outblock outblock;
 int max_rcpt = tblock->max_addresses;
 smtp_inblock inblock;
 smtp_outblock outblock;
 int max_rcpt = tblock->max_addresses;
@@ -822,7 +833,7 @@ if (helo_data == NULL)
   {
   uschar *message = string_sprintf("failed to expand helo_data: %s",
     expand_string_message);
   {
   uschar *message = string_sprintf("failed to expand helo_data: %s",
     expand_string_message);
-  set_errno(addrlist, 0, message, DEFER);
+  set_errno(addrlist, 0, message, DEFER, FALSE);
   return ERROR;
   }
 
   return ERROR;
   }
 
@@ -842,7 +853,7 @@ if (ob->authenticated_sender != NULL)
       {
       uschar *message = string_sprintf("failed to expand "
         "authenticated_sender: %s", expand_string_message);
       {
       uschar *message = string_sprintf("failed to expand "
         "authenticated_sender: %s", expand_string_message);
-      set_errno(addrlist, 0, message, DEFER);
+      set_errno(addrlist, 0, message, DEFER, FALSE);
       return ERROR;
       }
     }
       return ERROR;
       }
     }
@@ -861,7 +872,7 @@ if (continue_hostname == NULL)
   if (inblock.sock < 0)
     {
     set_errno(addrlist, (errno == ETIMEDOUT)? ERRNO_CONNECTTIMEOUT : errno,
   if (inblock.sock < 0)
     {
     set_errno(addrlist, (errno == ETIMEDOUT)? ERRNO_CONNECTTIMEOUT : errno,
-      NULL, DEFER);
+      NULL, DEFER, FALSE);
     return DEFER;
     }
 
     return DEFER;
     }
 
@@ -1186,7 +1197,7 @@ if (continue_hostname == NULL
 
             case ERROR:
             yield = ERROR;
 
             case ERROR:
             yield = ERROR;
-            set_errno(addrlist, 0, string_copy(buffer), DEFER);
+            set_errno(addrlist, 0, string_copy(buffer), DEFER, FALSE);
             goto SEND_QUIT;
             }
 
             goto SEND_QUIT;
             }
 
@@ -1202,7 +1213,8 @@ if (continue_hostname == NULL
     {
     yield = DEFER;
     set_errno(addrlist, ERRNO_AUTHFAIL,
     {
     yield = DEFER;
     set_errno(addrlist, ERRNO_AUTHFAIL,
-      string_sprintf("authentication required but %s", fail_reason), DEFER);
+      string_sprintf("authentication required but %s", fail_reason), DEFER,
+      FALSE);
     goto SEND_QUIT;
     }
   }
     goto SEND_QUIT;
     }
   }
@@ -1228,7 +1240,8 @@ if (tblock->filter_command != NULL)
 
   if (!rc)
     {
 
   if (!rc)
     {
-    set_errno(addrlist->next, addrlist->basic_errno, addrlist->message, DEFER);
+    set_errno(addrlist->next, addrlist->basic_errno, addrlist->message, DEFER,
+      FALSE);
     yield = ERROR;
     goto SEND_QUIT;
     }
     yield = ERROR;
     goto SEND_QUIT;
     }
@@ -1368,7 +1381,8 @@ if (mua_wrapper)
     }
   if (badaddr != NULL)
     {
     }
   if (badaddr != NULL)
     {
-    set_errno(addrlist, 0, badaddr->message, FAIL);
+    set_errno(addrlist, 0, badaddr->message, FAIL,
+      testflag(badaddr, af_pass_message));
     ok = FALSE;
     }
   }
     ok = FALSE;
     }
   }
@@ -1597,7 +1611,7 @@ if (!ok)
   save_errno = errno;
   message = NULL;
   send_quit = check_response(host, &save_errno, addrlist->more_errno,
   save_errno = errno;
   message = NULL;
   send_quit = check_response(host, &save_errno, addrlist->more_errno,
-    buffer, &code, &message);
+    buffer, &code, &message, &pass_message);
   goto FAILED;
 
   SEND_FAILED:
   goto FAILED;
 
   SEND_FAILED:
@@ -1632,11 +1646,11 @@ if (!ok)
     {
     if (code == '5')
       {
     {
     if (code == '5')
       {
-      set_errno(addrlist, save_errno, message, FAIL);
+      set_errno(addrlist, save_errno, message, FAIL, pass_message);
       }
     else
       {
       }
     else
       {
-      set_errno(addrlist, save_errno, message, DEFER);
+      set_errno(addrlist, save_errno, message, DEFER, pass_message);
       yield = DEFER;
       }
     }
       yield = DEFER;
       }
     }
@@ -1662,7 +1676,7 @@ if (!ok)
     {
     yield = (save_errno == ERRNO_CHHEADER_FAIL ||
              save_errno == ERRNO_FILTER_FAIL)? ERROR : DEFER;
     {
     yield = (save_errno == ERRNO_CHHEADER_FAIL ||
              save_errno == ERRNO_FILTER_FAIL)? ERROR : DEFER;
-    set_errno(addrlist, save_errno, message, DEFER);
+    set_errno(addrlist, save_errno, message, DEFER, pass_message);
     }
 
   /* Otherwise we have a message-specific error response from the remote
     }
 
   /* Otherwise we have a message-specific error response from the remote
@@ -1683,7 +1697,8 @@ if (!ok)
     {
     if (mua_wrapper) code = '5';  /* Force hard failure in wrapper mode */
 
     {
     if (mua_wrapper) code = '5';  /* Force hard failure in wrapper mode */
 
-    set_errno(addrlist, save_errno, message, (code == '5')? FAIL : DEFER);
+    set_errno(addrlist, save_errno, message, (code == '5')? FAIL : DEFER,
+      pass_message);
 
     /* If there's an errno, the message contains just the identity of
     the host. */
 
     /* If there's an errno, the message contains just the identity of
     the host. */
@@ -1747,6 +1762,7 @@ if (completed_address && ok && send_quit)
         ))
     {
     uschar *msg;
         ))
     {
     uschar *msg;
+    BOOL pass_message;
 
     if (send_rset)
       {
 
     if (send_rset)
       {
@@ -1760,7 +1776,8 @@ if (completed_address && ok && send_quit)
                   ob->command_timeout)))
         {
         int code;
                   ob->command_timeout)))
         {
         int code;
-        send_quit = check_response(host, &errno, 0, buffer, &code, &msg);
+        send_quit = check_response(host, &errno, 0, buffer, &code, &msg,
+          &pass_message);
         if (!send_quit)
           {
           DEBUG(D_transport) debug_printf("%s\n", msg);
         if (!send_quit)
           {
           DEBUG(D_transport) debug_printf("%s\n", msg);
@@ -1806,7 +1823,7 @@ if (completed_address && ok && send_quit)
 
     /* If RSET failed and there are addresses left, they get deferred. */
 
 
     /* If RSET failed and there are addresses left, they get deferred. */
 
-    else set_errno(first_addr, errno, msg, DEFER);
+    else set_errno(first_addr, errno, msg, DEFER, FALSE);
     }
   }
 
     }
   }
 
@@ -2449,7 +2466,7 @@ for (cutoff_retry = 0; expired &&
     if (dont_deliver)
       {
       host_item *host2;
     if (dont_deliver)
       {
       host_item *host2;
-      set_errno(addrlist, 0, NULL, OK);
+      set_errno(addrlist, 0, NULL, OK, FALSE);
       for (addr = addrlist; addr != NULL; addr = addr->next)
         {
         addr->host_used = host;
       for (addr = addrlist; addr != NULL; addr = addr->next)
         {
         addr->host_used = host;