+if (!(options & vopt_callout_no_cache))
+ cache_callout_write(&new_domain_record, addr->domain,
+ done, &new_address_record, address_key);
+
+/* Failure to connect to any host, or any response other than 2xx or 5xx is a
+temporary error. If there was only one host, and a response was received, leave
+it alone if supplying details. Otherwise, give a generic response. */
+
+if (!done)
+ {
+ uschar * dullmsg = string_sprintf("Could not complete %s verify callout",
+ options & vopt_is_recipient ? "recipient" : "sender");
+ yield = DEFER;
+
+ addr->message = host_list->next || !addr->message
+ ? dullmsg : string_sprintf("%s: %s", dullmsg, addr->message);
+
+ 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."
+ : "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.")
+ : dullmsg;
+
+ /* Force a specific error code */
+
+ addr->basic_errno = ERRNO_CALLOUTDEFER;
+ }
+
+/* Come here from within the cache-reading code on fast-track exit. */
+
+END_CALLOUT:
+tls_modify_variables(&tls_in);
+return yield;
+}
+
+
+
+/* Called after recipient-acl to get a cutthrough connection open when
+ one was requested and a recipient-verify wasn't subsequently done.
+*/
+int
+open_cutthrough_connection(address_item * addr)
+{
+address_item addr2;
+int rc;
+
+/* Use a recipient-verify-callout to set up the cutthrough connection. */
+/* We must use a copy of the address for verification, because it might
+get rewritten. */
+
+addr2 = *addr;
+HDEBUG(D_acl) debug_printf_indent("----------- %s cutthrough setup ------------\n",
+ rcpt_count > 1 ? "more" : "start");
+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_indent("----------- end cutthrough setup ------------\n");
+return rc;
+}
+
+
+
+/* Send given number of bytes from the buffer */
+static BOOL
+cutthrough_send(int n)
+{
+if(cutthrough.cctx.sock < 0)
+ return TRUE;
+
+if(
+#ifdef SUPPORT_TLS
+ cutthrough.is_tls
+ ? tls_write(cutthrough.cctx.tls_ctx, ctctx.outblock.buffer, n, FALSE)
+ :
+#endif
+ send(cutthrough.cctx.sock, ctctx.outblock.buffer, n, 0) > 0
+ )
+{
+ transport_count += n;
+ ctctx.outblock.ptr= ctctx.outblock.buffer;
+ return TRUE;
+}
+
+HDEBUG(D_transport|D_acl) debug_printf_indent("cutthrough_send failed: %s\n", strerror(errno));
+return FALSE;
+}
+
+
+
+static BOOL
+_cutthrough_puts(uschar * cp, int n)
+{
+while(n--)
+ {
+ if(ctctx.outblock.ptr >= ctctx.outblock.buffer+ctctx.outblock.buffersize)
+ if(!cutthrough_send(ctctx.outblock.buffersize))
+ return FALSE;
+
+ *ctctx.outblock.ptr++ = *cp++;
+ }
+return TRUE;
+}
+
+/* Buffered output of counted data block. Return boolean success */
+static BOOL
+cutthrough_puts(uschar * cp, int n)
+{
+if (cutthrough.cctx.sock < 0) return TRUE;
+if (_cutthrough_puts(cp, n)) return TRUE;
+cancel_cutthrough_connection(TRUE, US"transmit failed");
+return FALSE;
+}
+
+void
+cutthrough_data_puts(uschar * cp, int n)
+{
+if (cutthrough.delivery) (void) cutthrough_puts(cp, n);
+return;
+}
+
+
+static BOOL
+_cutthrough_flush_send(void)
+{
+int n = ctctx.outblock.ptr - ctctx.outblock.buffer;
+
+if(n>0)
+ if(!cutthrough_send(n))
+ return FALSE;
+return TRUE;
+}
+
+
+/* Send out any bufferred output. Return boolean success. */
+BOOL
+cutthrough_flush_send(void)
+{
+if (_cutthrough_flush_send()) return TRUE;
+cancel_cutthrough_connection(TRUE, US"transmit failed");
+return FALSE;
+}
+
+
+static BOOL
+cutthrough_put_nl(void)
+{
+return cutthrough_puts(US"\r\n", 2);
+}