Events: add recipient-deferred events, both per-host and all-hosts.
authorJasen Betts <jasen@xnet.co.nz>
Tue, 10 Nov 2015 16:58:33 +0000 (16:58 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Sat, 14 Nov 2015 15:59:47 +0000 (15:59 +0000)
doc/doc-txt/ChangeLog
doc/doc-txt/experimental-spec.txt
src/src/acl.c
src/src/deliver.c
src/src/functions.h
src/src/transports/smtp.c
test/confs/5700
test/log/5700
test/scripts/5700-events/5700
test/stdout/5700

index 742243c2dc5d5fc4899acdda3580c0367a6fd5c2..142d81e05476f99ad0a139c96c5572486abd114a 100644 (file)
@@ -90,6 +90,12 @@ JH/18 Bug 1709: When built with TLS support, the tls_advertise_hosts option now
 HS/03 Add -bP config_file as a synonym for -bP configure_file, for consistency
       with the $config_file variable.
 
+JH/19 Two additional event types: msg:rcpt:defer and msg:rcpt:host:defer. Both
+      in transport context, after the attempt, and per-recipient. The latter type
+      is per host attempted.  The event data is the error message, and the errno
+      information encodes the lookup type (A vs. MX) used for the (first) host,
+      and the trailing two digits of the smtp 4xx reponse.
+
 
 Exim version 4.86
 -----------------
index c93123c39f9df588872b97127bf789f076dce22a..74614cd3f35e0f6670cbb05a15ee29e72bf85f95 100644 (file)
@@ -798,6 +798,8 @@ expansion is done.  The current list of events is:
 
  msg:complete          after  main       per message
  msg:delivery          after  transport  per recipient
+ msg:rcpt:host:defer   after  transport  per recipient per host
+ msg:rcpt:defer        after  transport  per recipient
  msg:host:defer                after  transport  per attempt
  msg:fail:delivery     after  main       per recipient
  msg:fail:internal     after  main       per recipient
@@ -811,16 +813,20 @@ variable to decide when to act.  The value of the variable is a colon-separated
 list, defining a position in the tree of possible events; it may be used as
 a list or just matched on as a whole.  There will be no whitespace.
 
+New event types may be added in the future.
+
 
 There is an auxilary variable, $event_data, for which the
 content is event_dependent:
 
        msg:delivery            smtp confirmation mssage
+       msg:rcpt:host:defer     error string
+       msg:rcpt:defer          error string
        msg:host:defer          error string
        tls:cert                verification chain depth
        smtp:connect            smtp banner
 
-The msg:host:defer event populates one extra variable, $event_defer_errno.
+The :defer events populate one extra variable, $event_defer_errno.
 
 The following variables are likely to be useful depending on the event type:
 
@@ -848,7 +854,14 @@ event_action = ${if eq {msg:delivery}{$event_name} \
 
 The string is expanded when each of the supported events occur
 and any side-effects of the expansion will happen.
-Note that for complex operations an ACL expansion can be used.
+
+Note that for complex operations an ACL expansion can be used,
+however due to the multiple contexts the Exim operates in
+a) variables set in events raised from transports will not
+   be visible outside that transport call.
+b) acl_m variables in a server context are lost on a new connection,
+   and after helo/ehlo/mail/starttls/rset commands
+
 
 
 The expansion of the event_action option should normally
index 064ee6ccbc3f12c85f693b7847ddc6edf9baa2b8..911ecfed2ae10b9dac2250a7e39c653e9c1a2ef5 100644 (file)
@@ -3743,7 +3743,12 @@ for (; cb != NULL; cb = cb->next)
     case ACLC_SET:
       {
       int old_pool = store_pool;
-      if (cb->u.varname[0] == 'c') store_pool = POOL_PERM;
+      if (  cb->u.varname[0] == 'c'
+#ifdef EXPERIMENTAL_EVENT
+        || event_name          /* An event is being delivered */
+#endif
+        )
+        store_pool = POOL_PERM;
       acl_var_create(cb->u.varname)->data.ptr = string_copy(arg);
       store_pool = old_pool;
       }
index e1f4e0e293cb69a24a0be0e750f1eb298b4c0ab9..65f148c07b93aadabd62b11d4a37d4303b5f2d33 100644 (file)
@@ -785,12 +785,14 @@ if (action)
 return NULL;
 }
 
-static void
+void
 msg_event_raise(const uschar * event, const address_item * addr)
 {
 const uschar * save_domain = deliver_domain;
 uschar * save_local =  deliver_localpart;
 const uschar * save_host = deliver_host;
+const uschar * save_address = deliver_host_address;
+const int      save_port =   deliver_host_port;
 
 if (!addr->transport)
   return;
@@ -802,9 +804,13 @@ deliver_localpart = addr->local_part;
 deliver_host =   addr->host_used ? addr->host_used->name : NULL;
 
 (void) event_raise(addr->transport->event_action, event,
-         addr->host_used || Ustrcmp(addr->transport->driver_name, "lmtp") == 0
-         ? addr->message : NULL);
+         addr->host_used
+          || Ustrcmp(addr->transport->driver_name, "smtp") == 0
+         || Ustrcmp(addr->transport->driver_name, "lmtp") == 0
+        ? addr->message : NULL); 
 
+deliver_host_port =    save_port;
+deliver_host_address = save_address;
 deliver_host =      save_host;
 deliver_localpart = save_local;
 deliver_domain =    save_domain;
index 6f6c643b86e2f02acc356592db5353906204aa1b..e9f7ab658a7f322ca065582f1f4b94bc23053ccb 100644 (file)
@@ -166,6 +166,7 @@ extern void    enq_end(uschar *);
 extern BOOL    enq_start(uschar *, unsigned);
 #ifdef EXPERIMENTAL_EVENT
 extern uschar *event_raise(uschar *, const uschar *, uschar *);
+extern void    msg_event_raise(const uschar *, const address_item *);
 #endif
 extern void    exim_exit(int);
 extern void    exim_nullstd(void);
index 59afe42aa84229b636eb96a97769007d7c209248..66d632fad7803767b010a65ebea6484bef1bb802 100644 (file)
@@ -919,12 +919,22 @@ while (count-- > 0)
       addr->basic_errno = ERRNO_RCPT4XX;
       addr->more_errno |= ((buffer[1] - '0')*10 + buffer[2] - '0') << 8;
 
+#ifdef EXPERIMENTAL_EVENT
+      event_defer_errno = addr->more_errno;
+      msg_event_raise(US"msg:rcpt:host:defer", addr);
+#endif
+
       /* Log temporary errors if there are more hosts to be tried.
       If not, log this last one in the == line. */
 
       if (host->next)
        log_write(0, LOG_MAIN, "H=%s [%s]: %s", host->name, host->address, addr->message);
 
+#ifdef EXPERIMENTAL_EVENT
+      else
+       msg_event_raise(US"msg:rcpt:defer", addr);
+#endif
+
       /* Do not put this message on the list of those waiting for specific
       hosts, as otherwise it is likely to be tried too often. */
 
index 7a060cdb6d106dc06f07813c134ad3527d797d5f..db1aa2a6e2da109b7b7aa3ef7c0789fbe3efdf5e 100644 (file)
@@ -46,6 +46,18 @@ ev_msg_fail:
            domain <$domain> \
            reason <$event_data>
 
+ev_msg_log:
+    accept logwrite = . \
+           $acl_arg1 \
+           ip <$host_address> \
+           port <$host_port> \
+           fqdn <$host> \
+           local_part <$local_part> \
+           domain <$domain> \
+           $acl_arg2 \
+           router <$router_name> \
+           transport <$transport_name>
+
 ev_msg:
     accept condition = ${if eq {fail} {${listextract{2}{$event_name}}}}
           acl = ev_msg_fail
@@ -57,29 +69,21 @@ ev_msg:
           logwrite = $this_expansion_will_fail
 
     accept condition = ${if eq {$event_name}{msg:delivery}}
-          logwrite = . \
-           delivery \
-           ip <$host_address> \
-           port <$host_port> \
-           fqdn <$host> \
-           local_part <$local_part> \
-           domain <$domain> \
-           confirmation <$event_data> \
-           router <$router_name> \
-           transport <$transport_name>
+          acl = ev_msg_log delivery "confirmation <$event_data>"
 
     accept condition = ${if eq {$event_name}{msg:host:defer}}
-          logwrite = . \
-           deferral \
-           ip <$host_address> \
-           port <$host_port> \
-           fqdn <$host> \
-           local_part <$local_part> \
-           domain <$domain> \
-           errno <$event_defer_errno> \
-           errstr <$event_data> \
-           router <$router_name> \
-           transport <$transport_name>
+          acl = ev_msg_log "host deferral" \
+                       "errno <$event_defer_errno> errstr <$event_data>"
+
+    accept condition = ${if eq {$event_name}{msg:rcpt:defer}}
+          set acl_m_ev_lkup =  ${eval:$event_defer_errno & 0xff}
+          set acl_m_ev_lkup =  ${if = {$acl_m_ev_lkup}{65} {A} \
+                               { ${if = {$acl_m_ev_lkup}{77} {MX} \
+                                 {$acl_m_ev_lkup}}}}
+          set acl_m_ev_code =  4${eval:$event_defer_errno >>8}
+          acl = ev_msg_log "rcpt deferral" \
+                       "err <$event_defer_errno>:<$acl_m_ev_lkup:$acl_m_ev_code> \
+                       errstr <$event_data>"
 
 logger:
     warn   logwrite = event $event_name
@@ -105,6 +109,7 @@ others:
   route_list = * 127.0.0.1 byname
   self = send
   transport = smtp
+  errors_to = ""
   no_more
 
 
index 6af2a901104c61c3d23e201d0ba29160463ad353..37eace60502b6c102b17a3a606411a450d93e817 100644 (file)
 1999-03-02 09:44:33 10HmaZ-0005vi-00 . [127.0.0.1] -> [127.0.0.1]:1224
 1999-03-02 09:44:33 10HmaZ-0005vi-00 H=127.0.0.1 [127.0.0.1]: SMTP timeout after EHLO the.local.host.name: Connection timed out
 1999-03-02 09:44:33 10HmaZ-0005vi-00 event msg:host:defer
-1999-03-02 09:44:33 10HmaZ-0005vi-00 . deferral ip <127.0.0.1> port <1224> fqdn <127.0.0.1> local_part <userx> domain <domain1> errno <110> errstr <SMTP timeout after EHLO the.local.host.name: Connection timed out> router <others> transport <smtp>
+1999-03-02 09:44:33 10HmaZ-0005vi-00 . host deferral ip <127.0.0.1> port <1224> fqdn <127.0.0.1> local_part <userx> domain <domain1> errno <110> errstr <SMTP timeout after EHLO the.local.host.name: Connection timed out> router <others> transport <smtp>
 1999-03-02 09:44:33 10HmaZ-0005vi-00 == userx@domain1 R=others T=smtp defer (dd): Connection timed out H=127.0.0.1 [127.0.0.1]: SMTP timeout after EHLO the.local.host.name
 1999-03-02 09:44:33 10HmaZ-0005vi-00 ** userx@domain1: retry timeout exceeded
-1999-03-02 09:44:33 10HmbA-0005vi-00 <= <> R=10HmaZ-0005vi-00 U=EXIMUSER P=local S=sss
-1999-03-02 09:44:33 10HmbA-0005vi-00 => :blackhole: <CALLER@the.local.host.name> R=dump_bounces
-1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
-1999-03-02 09:44:33 10HmbA-0005vi-00 event msg:complete
-1999-03-02 09:44:33 10HmbA-0005vi-00 . finished: 10HmbA-0005vi-00
+1999-03-02 09:44:33 10HmaZ-0005vi-00 userx@domain1: error ignored
 1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
 1999-03-02 09:44:33 10HmaZ-0005vi-00 event msg:complete
 1999-03-02 09:44:33 10HmaZ-0005vi-00 . finished: 10HmaZ-0005vi-00
+1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@the.local.host.name U=CALLER P=local S=sss
+1999-03-02 09:44:33 Start queue run: pid=pppp -qqf
+1999-03-02 09:44:33 10HmbA-0005vi-00 event tcp:connect
+1999-03-02 09:44:33 10HmbA-0005vi-00 . [127.0.0.1]:1111
+1999-03-02 09:44:33 10HmbA-0005vi-00 event smtp:connect
+1999-03-02 09:44:33 10HmbA-0005vi-00 . [127.0.0.1] -> [127.0.0.1]:1224
+1999-03-02 09:44:33 10HmbA-0005vi-00 . banner <220 ESMTP>
+1999-03-02 09:44:33 10HmbA-0005vi-00 event msg:rcpt:host:defer
+1999-03-02 09:44:33 10HmbA-0005vi-00 event msg:rcpt:defer
+1999-03-02 09:44:33 10HmbA-0005vi-00 . rcpt deferral ip <127.0.0.1> port <1224> fqdn <127.0.0.1> local_part <userx> domain <domain1> err <12865>:<A:450> errstr <SMTP error from remote mail server after RCPT TO:<userx@domain1>: 450 NOT RIGHT NOW> router <others> transport <smtp>
+1999-03-02 09:44:33 10HmbA-0005vi-00 event tcp:close
+1999-03-02 09:44:33 10HmbA-0005vi-00 . [127.0.0.1] -> [127.0.0.1]:1224
+1999-03-02 09:44:33 10HmbA-0005vi-00 == userx@domain1 R=others T=smtp defer (-44) H=127.0.0.1 [127.0.0.1]: SMTP error from remote mail server after RCPT TO:<userx@domain1>: 450 NOT RIGHT NOW
+1999-03-02 09:44:33 10HmbA-0005vi-00 ** userx@domain1: retry timeout exceeded
+1999-03-02 09:44:33 10HmbA-0005vi-00 userx@domain1: error ignored
+1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbA-0005vi-00 event msg:complete
+1999-03-02 09:44:33 10HmbA-0005vi-00 . finished: 10HmbA-0005vi-00
+1999-03-02 09:44:33 End queue run: pid=pppp -qqf
 1999-03-02 09:44:33 10HmbB-0005vi-00 <= CALLER@the.local.host.name U=CALLER P=local S=sss
 1999-03-02 09:44:33 Start queue run: pid=pppp -qqf
 1999-03-02 09:44:33 10HmbB-0005vi-00 event tcp:connect
 1999-03-02 09:44:33 10HmbB-0005vi-00 ** userx@domain1 R=others T=smtp H=127.0.0.1 [127.0.0.1]: SMTP error from remote mail server after RCPT TO:<userx@domain1>: 550 GO AWAY
 1999-03-02 09:44:33 10HmbB-0005vi-00 event msg:fail:delivery
 1999-03-02 09:44:33 10HmbB-0005vi-00 . refused by fdqn <127.0.0.1> local_part <userx> domain <domain1>
-1999-03-02 09:44:33 10HmbC-0005vi-00 <= <> R=10HmbB-0005vi-00 U=EXIMUSER P=local S=sss
-1999-03-02 09:44:33 10HmbC-0005vi-00 => :blackhole: <CALLER@the.local.host.name> R=dump_bounces
-1999-03-02 09:44:33 10HmbC-0005vi-00 Completed
-1999-03-02 09:44:33 10HmbC-0005vi-00 event msg:complete
-1999-03-02 09:44:33 10HmbC-0005vi-00 . finished: 10HmbC-0005vi-00
+1999-03-02 09:44:33 10HmbB-0005vi-00 userx@domain1: error ignored
 1999-03-02 09:44:33 10HmbB-0005vi-00 Completed
 1999-03-02 09:44:33 10HmbB-0005vi-00 event msg:complete
 1999-03-02 09:44:33 10HmbB-0005vi-00 . finished: 10HmbB-0005vi-00
 1999-03-02 09:44:33 End queue run: pid=pppp -qqf
-1999-03-02 09:44:33 10HmbD-0005vi-00 <= CALLER@the.local.host.name U=CALLER P=local S=sss
-1999-03-02 09:44:33 10HmbD-0005vi-00 cancelled by CALLER
-1999-03-02 09:44:33 10HmbD-0005vi-00 event msg:fail:internal
-1999-03-02 09:44:33 10HmbD-0005vi-00 . local_part <userx> domain <domain1> reason <delivery cancelled by administrator>
-1999-03-02 09:44:33 10HmbE-0005vi-00 <= <> R=10HmbD-0005vi-00 U=EXIMUSER P=local S=sss
-1999-03-02 09:44:33 10HmbE-0005vi-00 => :blackhole: <CALLER@the.local.host.name> R=dump_bounces
-1999-03-02 09:44:33 10HmbE-0005vi-00 Completed
-1999-03-02 09:44:33 10HmbE-0005vi-00 event msg:complete
-1999-03-02 09:44:33 10HmbE-0005vi-00 . finished: 10HmbE-0005vi-00
+1999-03-02 09:44:33 10HmbC-0005vi-00 <= CALLER@the.local.host.name U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmbC-0005vi-00 cancelled by CALLER
+1999-03-02 09:44:33 10HmbC-0005vi-00 event msg:fail:internal
+1999-03-02 09:44:33 10HmbC-0005vi-00 . local_part <userx> domain <domain1> reason <delivery cancelled by administrator>
+1999-03-02 09:44:33 10HmbD-0005vi-00 <= <> R=10HmbC-0005vi-00 U=EXIMUSER P=local S=sss
+1999-03-02 09:44:33 10HmbD-0005vi-00 => :blackhole: <CALLER@the.local.host.name> R=dump_bounces
 1999-03-02 09:44:33 10HmbD-0005vi-00 Completed
 1999-03-02 09:44:33 10HmbD-0005vi-00 event msg:complete
 1999-03-02 09:44:33 10HmbD-0005vi-00 . finished: 10HmbD-0005vi-00
+1999-03-02 09:44:33 10HmbC-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbC-0005vi-00 event msg:complete
+1999-03-02 09:44:33 10HmbC-0005vi-00 . finished: 10HmbC-0005vi-00
index f7cd8272cc2cef08abe6c1e43c08c64e57aa4dde..8fb2010f267196ef85f210b55aeb4ab6017b4421 100644 (file)
@@ -1,5 +1,5 @@
 # Arbitrary expansion after transport
-# (EXPERIMENTAL_TPDA)
+# (EXPERIMENTAL_EVENT)
 #
 need_ipv4
 #
@@ -67,6 +67,24 @@ A message which will hit a timeout at the destination server
 #
 #
 exim -odq userx@domain1
+A message which will get deferred
+****
+server PORT_S
+220 ESMTP
+EHLO
+250-OK
+250 HELP
+MAIL
+250 OK
+RCPT
+450 NOT RIGHT NOW
+QUIT
+220 OK
+****
+exim -qqf
+****
+#
+exim -odq userx@domain1
 A message which will get refused
 ****
 server PORT_S
index b185dca05916d0263127676a8af8b8b75bdd56a2..a8f3b7482c13a9dd894b3a5db1b76fb3ff8bb6aa 100644 (file)
@@ -6,7 +6,7 @@ Connection request from [127.0.0.1]
 EHLO the.local.host.name
 250-OK
 250 HELP
-MAIL FROM:<CALLER@the.local.host.name>
+MAIL FROM:<>
 250 OK
 RCPT TO:<userx@domain1>
 250 OK
@@ -32,7 +32,7 @@ Connection request from [127.0.0.1]
 EHLO the.local.host.name
 250-OK
 250 HELP
-MAIL FROM:<CALLER@the.local.host.name>
+MAIL FROM:<>
 250 OK
 RCPT TO:<userx@domain2>
 250 OK
@@ -64,7 +64,20 @@ Connection request from [127.0.0.1]
 EHLO the.local.host.name
 250-OK
 250 HELP
-MAIL FROM:<CALLER@the.local.host.name>
+MAIL FROM:<>
+250 OK
+RCPT TO:<userx@domain1>
+450 NOT RIGHT NOW
+QUIT
+220 OK
+End of script
+Listening on port 1224 ... 
+Connection request from [127.0.0.1]
+220 ESMTP
+EHLO the.local.host.name
+250-OK
+250 HELP
+MAIL FROM:<>
 250 OK
 RCPT TO:<userx@domain1>
 550 GO AWAY