Cutthrough: option to reflect 4xx errors from target to initiator
authorJeremy Harris <jgh146exb@wizmail.org>
Sun, 4 Sep 2016 13:54:18 +0000 (14:54 +0100)
committerJeremy Harris <jgh146exb@wizmail.org>
Mon, 5 Sep 2016 12:18:45 +0000 (13:18 +0100)
14 files changed:
doc/doc-docbook/spec.xfpt
doc/doc-txt/NewStuff
src/src/acl.c
src/src/globals.c
src/src/globals.h
src/src/receive.c
src/src/smtp_in.c
src/src/verify.c
test/confs/5400
test/confs/5405 [new symlink]
test/log/5405 [new file with mode: 0644]
test/rejectlog/5405 [new file with mode: 0644]
test/scripts/5400-cutthrough/5405 [new file with mode: 0644]
test/stdout/5405 [new file with mode: 0644]

index 622e5272d31f0e38e1f1333c3ff6e452ecd77fd7..4ebeaa0c605fc43af98bfec117622eb9b68ef274 100644 (file)
@@ -13003,8 +13003,7 @@ or external command, as described above. It is also used during a
 
 .vitem &$verify_mode$&
 .vindex "&$verify_mode$&"
-While a router or transport is being run in verify mode
-or for cutthrough delivery,
+While a router or transport is being run in verify mode or for cutthrough delivery,
 contains "S" for sender-verification or "R" for recipient-verification.
 Otherwise, empty.
 
@@ -28802,7 +28801,7 @@ Notice that we put back the lower cased version afterwards, assuming that
 is what is wanted for subsequent tests.
 
 
-.vitem &*control&~=&~cutthrough_delivery*&
+.vitem &*control&~=&~cutthrough_delivery/*&<&'options'&>
 .cindex "&ACL;" "cutthrough routing"
 .cindex "cutthrough" "requesting"
 This option requests delivery be attempted while the item is being received.
@@ -28842,11 +28841,20 @@ It is not supported for messages received with the SMTP PRDR option in use.
 
 Should the ultimate destination system positively accept or reject the mail,
 a corresponding indication is given to the source system and nothing is queued.
-If there is a temporary error the item is queued for later delivery in the
-usual fashion. If the item is successfully delivered in cutthrough mode
+If the item is successfully delivered in cutthrough mode
 the delivery log lines are tagged with ">>" rather than "=>" and appear
 before the acceptance "<=" line.
 
+.new
+If there is a temporary error the item is queued for later delivery in the
+usual fashion.
+This behaviour can be adjusted by appending the option &*defer=*&<&'value'&>
+to the control; the default value is &"spool"& and the alternate value
+&"pass"& copies an SMTP defer response from the target back to the initiator
+and does not queue the message.
+Note that this is independent of any receipient verify conditions in the ACL.
+.wen
+
 Delivery in this mode avoids the generation of a bounce mail to a
 (possibly faked)
 sender when the destination system is doing content-scan based rejection.
index 20af1a28fe6899c78e86e626b829d2d1d027d4fe..33b726536780db2317104061633740fccdfd8913 100644 (file)
@@ -43,6 +43,10 @@ Version 4.88
 
 11. Integer values for options can take a "G" multiplier.
 
+12. defer=pass option for the ACL control cutthrough_delivery, to reflect 4xx
+    returns from the target back to the initiator, rather than spooling the
+    message.
+
 
 Version 4.87
 ------------
index 492e9bf17543cf5546de8737353a9c4a12dff2e8..eff698b34dbfd2cca04ceeef9d26550f67d6d2af 100644 (file)
@@ -744,7 +744,7 @@ static control_def controls_list[] = {
   { US"fakereject",              CONTROL_FAKEREJECT,            TRUE },
   { US"submission",              CONTROL_SUBMISSION,            TRUE },
   { US"suppress_local_fixups",   CONTROL_SUPPRESS_LOCAL_FIXUPS, FALSE },
-  { US"cutthrough_delivery",     CONTROL_CUTTHROUGH_DELIVERY,   FALSE },
+  { US"cutthrough_delivery",     CONTROL_CUTTHROUGH_DELIVERY,   TRUE },
 #ifdef SUPPORT_I18N
   { US"utf8_downconvert",        CONTROL_UTF8_DOWNCONVERT,      TRUE }
 #endif
@@ -3398,7 +3398,23 @@ for (; cb != NULL; cb = cb->next)
            *log_msgptr = US"fakereject";
          else
            {
-           if (rcpt_count == 1) cutthrough.delivery = TRUE;
+           if (rcpt_count == 1)
+             {
+             cutthrough.delivery = TRUE;
+             while (*p == '/')
+               {
+               const uschar * pp = p+1;
+               if (Ustrncmp(pp, "defer=", 6) == 0)
+                 {
+                 pp += 6;
+                 if (Ustrncmp(pp, "pass", 4) == 0) cutthrough.defer_pass = TRUE;
+                 /* else if (Ustrncmp(pp, "spool") == 0) ;     default */
+                 }
+               else
+                 while (*pp && *pp != '/') pp++;
+               p = pp;
+               }
+             }
            break;
            }
          *log_msgptr = string_sprintf("\"control=%s\" on %s item",
@@ -4502,32 +4518,50 @@ If temp-reject, close the conn (and keep the spooled copy).
 If conn-failure, no action (and keep the spooled copy).
 */
 switch (where)
-{
-case ACL_WHERE_RCPT:
+  {
+  case ACL_WHERE_RCPT:
 #ifndef DISABLE_PRDR
-case ACL_WHERE_PRDR:
+  case ACL_WHERE_PRDR:
 #endif
-  if (host_checking_callout)   /* -bhc mode */
-    cancel_cutthrough_connection("host-checking mode");
-  else if (rc == OK && cutthrough.delivery && rcpt_count > cutthrough.nrcpt)
-    rc = open_cutthrough_connection(addr);
-  break;
+    if (host_checking_callout) /* -bhc mode */
+      cancel_cutthrough_connection("host-checking mode");
+
+    else if (  rc == OK
+           && cutthrough.delivery
+           && rcpt_count > cutthrough.nrcpt
+           && (rc = open_cutthrough_connection(addr)) == DEFER
+           )
+      if (cutthrough.defer_pass)
+       {
+       uschar * s = addr->message;
+       /* Horrid kludge to recover target's SMTP message */
+       while (*s) s++;
+       do --s; while (!isdigit(*s));
+       if (*--s && isdigit(*s) && *--s && isdigit(*s)) *user_msgptr = s;
+       acl_temp_details = TRUE;
+       }
+       else
+       {
+       HDEBUG(D_acl) debug_printf("cutthrough defer; will spool\n");
+       rc = OK;
+       }
+    break;
 
-case ACL_WHERE_PREDATA:
-  if (rc == OK)
-    cutthrough_predata();
-  else
-    cancel_cutthrough_connection("predata acl not ok");
-  break;
+  case ACL_WHERE_PREDATA:
+    if (rc == OK)
+      cutthrough_predata();
+    else
+      cancel_cutthrough_connection("predata acl not ok");
+    break;
 
-case ACL_WHERE_QUIT:
-case ACL_WHERE_NOTQUIT:
-  cancel_cutthrough_connection("quit or notquit");
-  break;
+  case ACL_WHERE_QUIT:
+  case ACL_WHERE_NOTQUIT:
+    cancel_cutthrough_connection("quit or notquit");
+    break;
 
-default:
-  break;
-}
+  default:
+    break;
+  }
 
 deliver_domain = deliver_localpart = deliver_address_data =
   sender_address_data = NULL;
index 9e6f9d34782e69ceb6f6d38f45e51bf9f6ca9017..8d201027352483291ec141bf260102c9a9099d83 100644 (file)
@@ -532,6 +532,7 @@ uschar *continue_transport     = NULL;
 uschar *csa_status             = NULL;
 cut_t   cutthrough = {
   FALSE,                               /* delivery: when to attempt */
+  FALSE,                               /* on defer: spool locally */
   -1,                                  /* fd: open connection */
   0,                                   /* nrcpt: number of addresses */
 };
index b2bfca64cb45dbfa24d088340ff0d182729df9d9..0faf713bfbc7ee4fa3c97d66759561971c6b8317 100644 (file)
@@ -301,7 +301,8 @@ extern uschar *continue_transport;     /* Transport for continued delivery */
 extern uschar *csa_status;             /* Client SMTP Authorization result */
 
 typedef struct {
-  BOOL         delivery;               /* When to attempt */
+  unsigned     delivery:1;             /* When to attempt */
+  unsigned     defer_pass:1;           /* Pass 4xx to caller rather than spoolling */
   int          fd;                     /* Open connection */
   int          nrcpt;                  /* Count of addresses */
   uschar *     interface;              /* (address of) */
index 4d30419f05cad2dcae901a4c826752ce6da76818..51ce2844ecdb283172407d8449064addadcef6de 100644 (file)
@@ -4052,7 +4052,8 @@ for this message. */
    Send dot onward.  If accepted, wipe the spooled files, log as delivered and accept
    the sender's dot (below).
    If rejected: copy response to sender, wipe the spooled files, log approriately.
-   If temp-reject: accept to sender, keep the spooled files.
+   If temp-reject: normally accept to sender, keep the spooled file - unless defer=pass
+   in which case pass temp-reject back to initiator and dump the files.
 
    Having the normal spool files lets us do data-filtering, and store/forward on temp-reject.
 
@@ -4068,13 +4069,17 @@ if(cutthrough.fd >= 0)
       cutthrough_done = ACCEPTED;
       break;                                   /* message_id needed for SMTP accept below */
 
+    case '4':  /* Temp-reject. Keep spoolfiles and accept, unless defer-pass mode.
+               ... for which, pass back the exact error */
+      if (cutthrough.defer_pass) smtp_reply = string_copy_malloc(msg);
+      /*FALLTRHOUGH*/
+
     default:   /* Unknown response, or error.  Treat as temp-reject.         */
-    case '4':  /* Temp-reject. Keep spoolfiles and accept. */
       cutthrough_done = TMP_REJ;               /* Avoid the usual immediate delivery attempt */
       break;                                   /* message_id needed for SMTP accept below */
 
     case '5':  /* Perm-reject.  Do the same to the source.  Dump any spoolfiles */
-      smtp_reply= msg;         /* Pass on the exact error */
+      smtp_reply = string_copy_malloc(msg);            /* Pass on the exact error */
       cutthrough_done = PERM_REJ;
       break;
     }
@@ -4188,27 +4193,37 @@ if (smtp_input)
     /* smtp_reply is set non-empty */
 
     else if (smtp_reply[0] != 0)
-      {
       if (fake_response != OK && (smtp_reply[0] == '2'))
         smtp_respond((fake_response == DEFER)? US"450" : US"550", 3, TRUE,
           fake_response_text);
       else
         smtp_printf("%.1024s\r\n", smtp_reply);
-      }
 
     switch (cutthrough_done)
       {
-      case ACCEPTED: log_write(0, LOG_MAIN, "Completed");/* Delivery was done */
+      case ACCEPTED:
+       log_write(0, LOG_MAIN, "Completed");/* Delivery was done */
       case PERM_REJ:
-             {                                          /* Delete spool files */
-             Uunlink(spool_fname(US"input", message_subdir, message_id, US"-D"));
-             Uunlink(spool_fname(US"input", message_subdir, message_id, US"-H"));
-             Uunlink(spool_fname(US"msglog", message_subdir, message_id, US""));
-             }
-      case TMP_REJ: message_id[0] = 0;   /* Prevent a delivery from starting */
-      default:break;
+                                                        /* Delete spool files */
+       Uunlink(spool_fname(US"input", message_subdir, message_id, US"-D"));
+       Uunlink(spool_fname(US"input", message_subdir, message_id, US"-H"));
+       Uunlink(spool_fname(US"msglog", message_subdir, message_id, US""));
+       message_id[0] = 0;        /* Prevent a delivery from starting */
+       break;
+
+      case TMP_REJ:
+       if (cutthrough.defer_pass)
+         {
+         Uunlink(spool_fname(US"input", message_subdir, message_id, US"-D"));
+         Uunlink(spool_fname(US"input", message_subdir, message_id, US"-H"));
+         Uunlink(spool_fname(US"msglog", message_subdir, message_id, US""));
+         }
+       message_id[0] = 0;        /* Prevent a delivery from starting */
+      default:
+       break;
       }
     cutthrough.delivery = FALSE;
+    cutthrough.defer_pass = FALSE;
     }
 
   /* For batched SMTP, generate an error message on failure, and do
index 597b88e389421493f84a79f616edf9f92bf5c4dc..387affaf380a42d07487b26a784c3a6c7ec7979b 100644 (file)
@@ -2961,8 +2961,9 @@ if (lognl != NULL) *lognl = 0;
 always a 5xx one - see comments at the start of this function. If the original
 rc was FAIL_DROP we drop the connection and yield 2. */
 
-if (rc == FAIL) smtp_respond(smtp_code, codelen, TRUE, (user_msg == NULL)?
-  US"Administrative prohibition" : user_msg);
+if (rc == FAIL)
+  smtp_respond(smtp_code, codelen, TRUE,
+    user_msg ? user_msg : US"Administrative prohibition");
 
 /* Send temporary failure response to the command. Don't give any details,
 unless acl_temp_details is set. This is TRUE for a callout defer, a "defer"
@@ -2973,21 +2974,19 @@ interactions between temp_details and return_error_details. One day it should
 be re-implemented in a tidier fashion. */
 
 else
-  {
-  if (acl_temp_details && user_msg != NULL)
+  if (acl_temp_details && user_msg)
     {
-    if (smtp_return_error_details &&
-        sender_verified_failed != NULL &&
-        sender_verified_failed->message != NULL)
-      {
+    if (  smtp_return_error_details
+       && sender_verified_failed
+       && sender_verified_failed->message
+       )
       smtp_respond(smtp_code, codelen, FALSE, sender_verified_failed->message);
-      }
+
     smtp_respond(smtp_code, codelen, TRUE, user_msg);
     }
   else
     smtp_respond(smtp_code, codelen, TRUE,
       US"Temporary local problem - please try later");
-  }
 
 /* Log the incident to the logs that are specified by log_reject_target
 (default main, reject). This can be empty to suppress logging of rejections. If
index d890f5fc60a96d54a4c1c948aec6c06754d75f2e..865a01d07f4e836ecedf793d62ae1fc78b1b1fec 100644 (file)
@@ -226,7 +226,7 @@ else if ((dbm_file = dbfn_open(US"callout", O_RDWR, &dbblock, FALSE)) == NULL)
 /* If a cache database is available see if we can avoid the need to do an
 actual callout by making use of previously-obtained data. */
 
-if (dbm_file != NULL)
+if (dbm_file)
   {
   dbdata_callout_cache_address *cache_address_record;
   dbdata_callout_cache *cache_record = get_callout_cache_record(dbm_file,
@@ -237,7 +237,7 @@ if (dbm_file != NULL)
   /* If an unexpired cache record was found for this domain, see if the callout
   process can be short-circuited. */
 
-  if (cache_record != NULL)
+  if (cache_record)
     {
     /* In most cases, if an early command (up to and including MAIL FROM:<>)
     was rejected, there is no point carrying on. The callout fails. However, if
@@ -297,7 +297,7 @@ if (dbm_file != NULL)
     but has not been done before, we are going to have to do a callout, so skip
     remaining cache processing. */
 
-    if (pm_mailfrom != NULL)
+    if (pm_mailfrom)
       {
       if (cache_record->postmaster_result == ccache_reject)
         {
@@ -343,7 +343,7 @@ if (dbm_file != NULL)
       callout_cache_positive_expire,
       callout_cache_negative_expire);
 
-  if (cache_address_record != NULL)
+  if (cache_address_record)
     {
     if (cache_address_record->result == ccache_accept)
       {
@@ -404,7 +404,7 @@ else
   and cause the client to time out. So in this case we forgo the PIPELINING
   optimization. */
 
-  if (smtp_out != NULL && !disable_callout_flush) mac_smtp_fflush();
+  if (smtp_out && !disable_callout_flush) mac_smtp_fflush();
 
 /* cutthrough-multi: if a nonfirst rcpt has the same routing as the first,
 and we are holding a cutthrough conn open, we can just append the rcpt to
@@ -516,7 +516,7 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
   /* Now make connections to the hosts and do real callouts. The list of hosts
   is passed in as an argument. */
 
-  for (host = host_list; host != NULL && !done; host = host->next)
+  for (host = host_list; host && !done; host = host->next)
     {
     smtp_inblock inblock;
     smtp_outblock outblock;
@@ -544,7 +544,7 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
 
     /* Skip this host if we don't have an IP address for it. */
 
-    if (host->address == NULL)
+    if (!host->address)
       {
       DEBUG(D_verify) debug_printf("no IP address for host name %s: skipping\n",
         host->name);
@@ -561,7 +561,7 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
 
     /* Set IPv4 or IPv6 */
 
-    host_af = (Ustrchr(host->address, ':') == NULL)? AF_INET:AF_INET6;
+    host_af = Ustrchr(host->address, ':') == NULL ? AF_INET : AF_INET6;
 
     /* Expand and interpret the interface and port strings. The latter will not
     be used if there is a host-specific port (e.g. from a manualroute router).
@@ -659,10 +659,10 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
 
     /* Expand the helo_data string to find the host name to use. */
 
-    if (tf->helo_data != NULL)
+    if (tf->helo_data)
       {
-      uschar *s = expand_string(tf->helo_data);
-      if (s == NULL)
+      uschar * s = expand_string(tf->helo_data);
+      if (!s)
         log_write(0, LOG_MAIN|LOG_PANIC, "<%s>: failed to expand transport's "
           "helo_data value for callout: %s", addr->address,
           expand_string_message);
@@ -1299,8 +1299,9 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
       {
       /* Ensure no cutthrough on multiple address verifies */
       if (options & vopt_callout_recipsender)
-        cancel_cutthrough_connection("multiple verify calls");
-      if (send_quit) (void)smtp_write_command(&outblock, FALSE, "QUIT\r\n");
+        cancel_cutthrough_connection("not usable for cutthrough");
+      if (send_quit)
+       (void) smtp_write_command(&outblock, FALSE, "QUIT\r\n");
 
 #ifdef SUPPORT_TLS
       tls_close(FALSE, TRUE);
@@ -1353,9 +1354,9 @@ if (done)
   if (  !(options & vopt_callout_no_cache)
      && new_address_record.result != ccache_unknown)
     {
-    if (dbm_file == NULL)
+    if (!dbm_file)
       dbm_file = dbfn_open(US"callout", O_RDWR|O_CREAT, &dbblock, FALSE);
-    if (dbm_file == NULL)
+    if (!dbm_file)
       {
       HDEBUG(D_verify) debug_printf("no callout cache available\n");
       }
@@ -1376,22 +1377,24 @@ it alone if supplying details. Otherwise, give a generic response. */
 
 else   /* !done */
   {
-  uschar *dullmsg = string_sprintf("Could not complete %s verify callout",
+  uschar * dullmsg = string_sprintf("Could not complete %s verify callout",
     options & vopt_is_recipient ? "recipient" : "sender");
   yield = DEFER;
 
-  if (host_list->next != NULL || addr->message == NULL) addr->message = dullmsg;
+  if (host_list->next || !addr->message)
+    addr->message = dullmsg;
 
-  addr->user_message = (!smtp_return_error_details)? dullmsg :
-    string_sprintf("%s for <%s>.\n"
+  addr->user_message = smtp_return_error_details
+    string_sprintf("%s for <%s>.\n"
       "The mail server(s) for the domain may be temporarily unreachable, or\n"
       "they may be permanently unreachable from this server. In the latter case,\n%s",
       dullmsg, addr->address,
       options & vopt_is_recipient
-       ?  "the address will never be accepted."
+       ? "the address will never be accepted."
         : "you need to change the address or create an MX record for its domain\n"
          "if it is supposed to be generally accessible from the Internet.\n"
-         "Talk to your mail administrator for details.");
+         "Talk to your mail administrator for details.")
+    : dullmsg;
 
   /* Force a specific error code */
 
@@ -1401,7 +1404,7 @@ else   /* !done */
 /* Come here from within the cache-reading code on fast-track exit. */
 
 END_CALLOUT:
-if (dbm_file != NULL) dbfn_close(dbm_file);
+if (dbm_file) dbfn_close(dbm_file);
 return yield;
 }
 
@@ -1423,10 +1426,12 @@ get rewritten. */
 addr2 = *addr;
 HDEBUG(D_acl) debug_printf("----------- %s cutthrough setup ------------\n",
   rcpt_count > 1 ? "more" : "start");
-rc= verify_address(&addr2, NULL,
+rc = verify_address(&addr2, NULL,
        vopt_is_recipient | vopt_callout_recipsender | vopt_callout_no_cache,
        CUTTHROUGH_CMD_TIMEOUT, -1, -1,
        NULL, NULL, NULL);
+addr->message = addr2.message;
+addr->user_message = addr2.user_message;
 HDEBUG(D_acl) debug_printf("----------- end cutthrough setup ------------\n");
 return rc;
 }
index f87f985fd299ce4aa994ada7e093cbfe149e16e9..9be13fea6b4f24184306b74fa786ed8de1092f98 100644 (file)
@@ -1,10 +1,17 @@
 # Exim test configuration 5400
 
+# any options on the cutthrough_delivery contol
+CONTROL=
+
+# optional verify-callout
+OPT=
+
 .include DIR/aux-var/std_conf_prefix
 
 primary_hostname = myhost.test.ex
 
 log_selector = +received_recipients
+queue_only
 
 # ----- Main settings -----
 
@@ -18,7 +25,9 @@ acl_smtp_rcpt = ar
 begin acl
 
 ar:
-       accept control = cutthrough_delivery
+  accept
+       control = cutthrough_deliveryCONTROL
+       OPT
        logwrite = rcpt for $local_part@$domain
 
 # ----- Routers -----
diff --git a/test/confs/5405 b/test/confs/5405
new file mode 120000 (symlink)
index 0000000..8f6811b
--- /dev/null
@@ -0,0 +1 @@
+5400
\ No newline at end of file
diff --git a/test/log/5405 b/test/log/5405
new file mode 100644 (file)
index 0000000..ae3ad76
--- /dev/null
@@ -0,0 +1,23 @@
+1999-03-02 09:44:33 rcpt for usera@domain.com
+1999-03-02 09:44:33 10HmaX-0005vi-00 >> usera@domain.com R=all T=smtp H=127.0.0.1 [127.0.0.1] C="250 OK"
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss for usera@domain.com
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 rcpt for userb@domain.com
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss for userb@domain.com
+1999-03-02 09:44:33 rcpt for userc@domain.com
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss for userc@domain.com
+1999-03-02 09:44:33 rcpt for userd@domain.com
+1999-03-02 09:44:33 U=CALLER F=<CALLER@myhost.test.ex> temporarily rejected RCPT <userd@domain.com>
+1999-03-02 09:44:33 rcpt for usere@domain.com
+1999-03-02 09:44:33 10HmbA-0005vi-00 U=CALLER usere@domain.com F=<CALLER@myhost.test.ex> tmp-reject from cutthrough after DATA: R=all T=smtp H=127.0.0.1 [127.0.0.1] C="459 content reject"
+1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss for usere@domain.com
+1999-03-02 09:44:33 rcpt for userf@domain.com
+1999-03-02 09:44:33 10HmbB-0005vi-00 U=CALLER userf@domain.com F=<CALLER@myhost.test.ex> tmp-reject from cutthrough after DATA: R=all T=smtp H=127.0.0.1 [127.0.0.1] C="459 content reject"
+1999-03-02 09:44:33 10HmbB-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss for userf@domain.com
+1999-03-02 09:44:33 rcpt for userg@domain.com
+1999-03-02 09:44:33 10HmbC-0005vi-00 U=CALLER userg@domain.com F=<CALLER@myhost.test.ex> tmp-reject from cutthrough after DATA: R=all T=smtp H=127.0.0.1 [127.0.0.1] C="459 content reject"
+1999-03-02 09:44:33 rcpt for userh@domain.com
+1999-03-02 09:44:33 10HmbD-0005vi-00 >> userh@domain.com R=all T=smtp H=127.0.0.1 [127.0.0.1] C="250 OK"
+1999-03-02 09:44:33 10HmbD-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss for userh@domain.com
+1999-03-02 09:44:33 10HmbD-0005vi-00 Completed
+1999-03-02 09:44:33 U=CALLER F=<CALLER@myhost.test.ex> temporarily rejected RCPT <useri@domain.com>: response to "RCPT TO:<useri@domain.com>" from 127.0.0.1 [127.0.0.1] was: 450 not right now
diff --git a/test/rejectlog/5405 b/test/rejectlog/5405
new file mode 100644 (file)
index 0000000..7df2e10
--- /dev/null
@@ -0,0 +1,2 @@
+1999-03-02 09:44:33 U=CALLER F=<CALLER@myhost.test.ex> temporarily rejected RCPT <userd@domain.com>
+1999-03-02 09:44:33 U=CALLER F=<CALLER@myhost.test.ex> temporarily rejected RCPT <useri@domain.com>: response to "RCPT TO:<useri@domain.com>" from 127.0.0.1 [127.0.0.1] was: 450 not right now
diff --git a/test/scripts/5400-cutthrough/5405 b/test/scripts/5400-cutthrough/5405
new file mode 100644 (file)
index 0000000..2e7a333
--- /dev/null
@@ -0,0 +1,228 @@
+# cutthrough_delivery tmp-rejects
+need_ipv4
+munge loopback
+#
+# basic operation.  Should deliver in cutthrough mode.
+server PORT_S
+220 ESMTP
+EHLO
+250 OK
+MAIL FROM:
+250 Sender OK
+RCPT TO:
+250 Recipient OK
+DATA
+354 Send data
+.
+250 OK
+QUIT
+250 OK
+****
+exim -bs
+EHLO myhost.test.ex
+MAIL FROM:<CALLER@myhost.test.ex>
+RCPT TO:<usera@domain.com>
+DATA
+
+.
+QUIT
+****
+######################################################
+# RCPT-time
+#
+# temp-reject (at RCPT), default.  Should spool msg.
+server PORT_S
+220 ESMTP
+EHLO
+250 OK
+MAIL FROM:
+250 Sender OK
+RCPT TO:
+450 not right now
+QUIT
+250 OK
+****
+exim -bs
+EHLO myhost.test.ex
+MAIL FROM:<CALLER@myhost.test.ex>
+RCPT TO:<userb@domain.com>
+DATA
+
+.
+QUIT
+****
+#
+# temp-reject (at RCPT), option "spool".  Should spool msg (again).
+server PORT_S
+220 ESMTP
+EHLO
+250 OK
+MAIL FROM:
+250 Sender OK
+RCPT TO:
+450 not right now
+QUIT
+250 OK
+****
+exim -DCONTROL=/defer=spool -bs
+EHLO myhost.test.ex
+MAIL FROM:<CALLER@myhost.test.ex>
+RCPT TO:<userc@domain.com>
+DATA
+
+.
+QUIT
+****
+#
+# temp-reject (at RCPT), option "pass".  Should tmp-rej source, at RCPT.
+server PORT_S
+220 ESMTP
+EHLO
+250 OK
+MAIL FROM:
+250 Sender OK
+RCPT TO:
+450 not right now
+QUIT
+250 OK
+****
+exim -DCONTROL=/defer=pass -bs
+EHLO myhost.test.ex
+MAIL FROM:<CALLER@myhost.test.ex>
+RCPT TO:<userd@domain.com>
+QUIT
+****
+#########################################################
+# DATA-time
+#
+#
+# temp-reject (at DATA-dot), default.  Should spool msg.
+server PORT_S
+220 ESMTP
+EHLO
+250 OK
+MAIL FROM:
+250 Sender OK
+RCPT TO:
+250 good rcpt
+DATA
+354 Send data
+.
+459 content reject
+QUIT
+250 OK
+****
+exim -bs
+EHLO myhost.test.ex
+MAIL FROM:<CALLER@myhost.test.ex>
+RCPT TO:<usere@domain.com>
+DATA
+
+.
+QUIT
+****
+#
+# temp-reject (at DATA-dot), option "spool".  Should spool msg (again).
+server PORT_S
+220 ESMTP
+EHLO
+250 OK
+MAIL FROM:
+250 Sender OK
+RCPT TO:
+250 good rcpt
+DATA
+354 Send data
+.
+459 content reject
+QUIT
+250 OK
+****
+exim -DCONTROL=/defer=spool -bs
+EHLO myhost.test.ex
+MAIL FROM:<CALLER@myhost.test.ex>
+RCPT TO:<userf@domain.com>
+DATA
+
+.
+QUIT
+****
+#
+# temp-reject (at DATA-dot), option "pass".  Should tmp-rej source, at DATA.
+server PORT_S
+220 ESMTP
+EHLO
+250 OK
+MAIL FROM:
+250 Sender OK
+RCPT TO:
+250 good rcpt
+DATA
+354 Send data
+.
+459 content reject
+QUIT
+250 OK
+****
+exim -DCONTROL=/defer=pass -bs
+EHLO myhost.test.ex
+MAIL FROM:<CALLER@myhost.test.ex>
+RCPT TO:<userg@domain.com>
+DATA
+
+.
+QUIT
+****
+#
+#########################################################
+#, Now using a conn opened by a recipient verify
+#
+# basic operation.  Should deliver in cutthrough mode.
+server PORT_S
+220 ESMTP
+EHLO
+250 OK
+MAIL FROM:
+250 Sender OK
+RCPT TO:
+250 Recipient OK
+DATA
+354 Send data
+.
+250 OK
+QUIT
+250 OK
+****
+exim -DOPT=verify=recipient/callout=use_sender -bs
+EHLO myhost.test.ex
+MAIL FROM:<CALLER@myhost.test.ex>
+RCPT TO:<userh@domain.com>
+DATA
+
+.
+QUIT
+****
+#
+# temp-reject (at RCPT), default.  Should tmp-rej, due to the r-verify
+server PORT_S
+220 ESMTP
+EHLO
+250 OK
+MAIL FROM:
+250 Sender OK
+RCPT TO:
+450 not right now
+QUIT
+250 OK
+****
+exim -DOPT=verify=recipient/callout=use_sender -bs
+EHLO myhost.test.ex
+MAIL FROM:<CALLER@myhost.test.ex>
+RCPT TO:<useri@domain.com>
+DATA
+
+.
+QUIT
+****
+#
+no_msglog_check
diff --git a/test/stdout/5405 b/test/stdout/5405
new file mode 100644 (file)
index 0000000..14bfdab
--- /dev/null
@@ -0,0 +1,280 @@
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
+250-myhost.test.ex Hello CALLER at myhost.test.ex\r
+250-SIZE 52428800\r
+250-8BITMIME\r
+250-PIPELINING\r
+250 HELP\r
+250 OK\r
+250 Accepted\r
+354 Enter message, ending with "." on a line by itself\r
+250 OK id=10HmaX-0005vi-00\r
+221 myhost.test.ex closing connection\r
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
+250-myhost.test.ex Hello CALLER at myhost.test.ex\r
+250-SIZE 52428800\r
+250-8BITMIME\r
+250-PIPELINING\r
+250 HELP\r
+250 OK\r
+250 Accepted\r
+354 Enter message, ending with "." on a line by itself\r
+250 OK id=10HmaY-0005vi-00\r
+221 myhost.test.ex closing connection\r
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
+250-myhost.test.ex Hello CALLER at myhost.test.ex\r
+250-SIZE 52428800\r
+250-8BITMIME\r
+250-PIPELINING\r
+250 HELP\r
+250 OK\r
+250 Accepted\r
+354 Enter message, ending with "." on a line by itself\r
+250 OK id=10HmaZ-0005vi-00\r
+221 myhost.test.ex closing connection\r
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
+250-myhost.test.ex Hello CALLER at myhost.test.ex\r
+250-SIZE 52428800\r
+250-8BITMIME\r
+250-PIPELINING\r
+250 HELP\r
+250 OK\r
+450 not right now\r
+221 myhost.test.ex closing connection\r
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
+250-myhost.test.ex Hello CALLER at myhost.test.ex\r
+250-SIZE 52428800\r
+250-8BITMIME\r
+250-PIPELINING\r
+250 HELP\r
+250 OK\r
+250 Accepted\r
+354 Enter message, ending with "." on a line by itself\r
+250 OK id=10HmbA-0005vi-00\r
+221 myhost.test.ex closing connection\r
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
+250-myhost.test.ex Hello CALLER at myhost.test.ex\r
+250-SIZE 52428800\r
+250-8BITMIME\r
+250-PIPELINING\r
+250 HELP\r
+250 OK\r
+250 Accepted\r
+354 Enter message, ending with "." on a line by itself\r
+250 OK id=10HmbB-0005vi-00\r
+221 myhost.test.ex closing connection\r
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
+250-myhost.test.ex Hello CALLER at myhost.test.ex\r
+250-SIZE 52428800\r
+250-8BITMIME\r
+250-PIPELINING\r
+250 HELP\r
+250 OK\r
+250 Accepted\r
+354 Enter message, ending with "." on a line by itself\r
+459 content reject\r
+221 myhost.test.ex closing connection\r
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
+250-myhost.test.ex Hello CALLER at myhost.test.ex\r
+250-SIZE 52428800\r
+250-8BITMIME\r
+250-PIPELINING\r
+250 HELP\r
+250 OK\r
+250 Accepted\r
+354 Enter message, ending with "." on a line by itself\r
+250 OK id=10HmbD-0005vi-00\r
+221 myhost.test.ex closing connection\r
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
+250-myhost.test.ex Hello CALLER at myhost.test.ex\r
+250-SIZE 52428800\r
+250-8BITMIME\r
+250-PIPELINING\r
+250 HELP\r
+250 OK\r
+451 Could not complete recipient verify callout\r
+503-All RCPT commands were rejected with this error:\r
+503-Could not complete recipient verify callout\r
+503 Valid RCPT command must precede DATA\r
+500 unrecognized command\r
+500 unrecognized command\r
+221 myhost.test.ex closing connection\r
+
+******** SERVER ********
+Listening on port 1224 ... 
+Connection request from [ip4.ip4.ip4.ip4]
+220 ESMTP
+EHLO myhost.test.ex
+250 OK
+MAIL FROM:<CALLER@myhost.test.ex>
+250 Sender OK
+RCPT TO:<usera@domain.com>
+250 Recipient OK
+DATA
+354 Send data
+Received: from CALLER (helo=myhost.test.ex)
+       by myhost.test.ex with local-esmtp (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmaX-0005vi-00
+       for usera@domain.com; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaX-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+X-hdr-rtr-new: +++
+
+.
+250 OK
+QUIT
+250 OK
+End of script
+Listening on port 1224 ... 
+Connection request from [ip4.ip4.ip4.ip4]
+220 ESMTP
+EHLO myhost.test.ex
+250 OK
+MAIL FROM:<CALLER@myhost.test.ex>
+250 Sender OK
+RCPT TO:<userb@domain.com>
+450 not right now
+QUIT
+250 OK
+End of script
+Listening on port 1224 ... 
+Connection request from [ip4.ip4.ip4.ip4]
+220 ESMTP
+EHLO myhost.test.ex
+250 OK
+MAIL FROM:<CALLER@myhost.test.ex>
+250 Sender OK
+RCPT TO:<userc@domain.com>
+450 not right now
+QUIT
+250 OK
+End of script
+Listening on port 1224 ... 
+Connection request from [ip4.ip4.ip4.ip4]
+220 ESMTP
+EHLO myhost.test.ex
+250 OK
+MAIL FROM:<CALLER@myhost.test.ex>
+250 Sender OK
+RCPT TO:<userd@domain.com>
+450 not right now
+QUIT
+250 OK
+End of script
+Listening on port 1224 ... 
+Connection request from [ip4.ip4.ip4.ip4]
+220 ESMTP
+EHLO myhost.test.ex
+250 OK
+MAIL FROM:<CALLER@myhost.test.ex>
+250 Sender OK
+RCPT TO:<usere@domain.com>
+250 good rcpt
+DATA
+354 Send data
+Received: from CALLER (helo=myhost.test.ex)
+       by myhost.test.ex with local-esmtp (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmbA-0005vi-00
+       for usere@domain.com; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmbA-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+X-hdr-rtr-new: +++
+
+.
+459 content reject
+QUIT
+250 OK
+End of script
+Listening on port 1224 ... 
+Connection request from [ip4.ip4.ip4.ip4]
+220 ESMTP
+EHLO myhost.test.ex
+250 OK
+MAIL FROM:<CALLER@myhost.test.ex>
+250 Sender OK
+RCPT TO:<userf@domain.com>
+250 good rcpt
+DATA
+354 Send data
+Received: from CALLER (helo=myhost.test.ex)
+       by myhost.test.ex with local-esmtp (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmbB-0005vi-00
+       for userf@domain.com; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmbB-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+X-hdr-rtr-new: +++
+
+.
+459 content reject
+QUIT
+250 OK
+End of script
+Listening on port 1224 ... 
+Connection request from [ip4.ip4.ip4.ip4]
+220 ESMTP
+EHLO myhost.test.ex
+250 OK
+MAIL FROM:<CALLER@myhost.test.ex>
+250 Sender OK
+RCPT TO:<userg@domain.com>
+250 good rcpt
+DATA
+354 Send data
+Received: from CALLER (helo=myhost.test.ex)
+       by myhost.test.ex with local-esmtp (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmbC-0005vi-00
+       for userg@domain.com; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmbC-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+X-hdr-rtr-new: +++
+
+.
+459 content reject
+QUIT
+250 OK
+End of script
+Listening on port 1224 ... 
+Connection request from [ip4.ip4.ip4.ip4]
+220 ESMTP
+EHLO myhost.test.ex
+250 OK
+MAIL FROM:<CALLER@myhost.test.ex>
+250 Sender OK
+RCPT TO:<userh@domain.com>
+250 Recipient OK
+DATA
+354 Send data
+Received: from CALLER (helo=myhost.test.ex)
+       by myhost.test.ex with local-esmtp (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmbD-0005vi-00
+       for userh@domain.com; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmbD-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+X-hdr-rtr-new: +++
+
+.
+250 OK
+QUIT
+250 OK
+End of script
+Listening on port 1224 ... 
+Connection request from [ip4.ip4.ip4.ip4]
+220 ESMTP
+EHLO myhost.test.ex
+250 OK
+MAIL FROM:<CALLER@myhost.test.ex>
+250 Sender OK
+RCPT TO:<useri@domain.com>
+450 not right now
+QUIT
+250 OK
+End of script