-DBL (Database Logging)
+Transport post-delivery actions
--------------------------------------------------------------
An arbitrary per-transport string can be expanded on successful delivery,
and (for SMTP transports) a second string on deferrals caused by a host error.
-This feature allows the writing of exim internal log information
+This feature may be used, for example, to write exim internal log information
(not available otherwise) into a database.
-In order to use DBL, you must set
+In order to use the feature, you must set
-EXPERIMENTAL_DBL=yes
+EXPERIMENTAL_TPDA=yes
in your Local/Makefile
and define the expandable strings in the runtime config file, to
be executed at end of delivery.
-Additionally, there are 8 more variables, available at end of
+Additionally, there are 6 more variables, available at end of
delivery:
-dbl_delivery_ip IP of host, which has accepted delivery
-dbl_delivery_port Port of remote host which has accepted delivery
-dbl_delivery_fqdn FQDN of host, which has accepted delivery
-dbl_delivery_local_part local part of address being delivered
-dbl_delivery_domain domain part of address being delivered
-dbl_delivery_confirmation SMTP confirmation message
-router_name name of router
-transport_name name of transport
+tpda_delivery_ip IP of host, which has accepted delivery
+tpda_delivery_port Port of remote host which has accepted delivery
+tpda_delivery_fqdn FQDN of host, which has accepted delivery
+tpda_delivery_local_part local part of address being delivered
+tpda_delivery_domain domain part of address being delivered
+tpda_delivery_confirmation SMTP confirmation message
In case of a deferral caused by a host-error:
-dbl_defer_errno Error number
-dbl_defer_errstr Error string possibly containing more details
+tpda_defer_errno Error number
+tpda_defer_errstr Error string possibly containing more details
+The $router_name and $transport_name variables are also usable.
-To log successful deliveries, set the following option
+To take action after successful deliveries, set the following option
on any transport of interest.
-dbl_delivery_query
+tpda_delivery_action
An example might look like:
-dbl_delivery_query = \
+tpda_delivery_action = \
${lookup pgsql {SELECT * FROM record_Delivery( \
'${quote_pgsql:$sender_address_domain}',\
'${quote_pgsql:${lc:$sender_address_local_part}}', \
- '${quote_pgsql:$dbl_delivery_domain}', \
- '${quote_pgsql:${lc:$dbl_delivery_local_part}}', \
- '${quote_pgsql:$dbl_delivery_ip}', \
- '${quote_pgsql:${lc:$dbl_delivery_fqdn}}', \
+ '${quote_pgsql:$tpda_delivery_domain}', \
+ '${quote_pgsql:${lc:$tpda_delivery_local_part}}', \
+ '${quote_pgsql:$tpda_delivery_ip}', \
+ '${quote_pgsql:${lc:$tpda_delivery_fqdn}}', \
'${quote_pgsql:$message_exim_id}')}}
The string is expanded after the delivery completes and any
In order to log host deferrals, add the following option to an SMTP
transport:
-dbl_host_defer_query
+tpda_host_defer_action
This is a private option of the SMTP transport. It is intended to
log failures of remote hosts. It is executed only when exim has
Example:
-dbl_host_defer_query = \
+tpda_host_defer_action = \
${lookup mysql {insert into delivlog set \
msgid = '${quote_mysql:$message_exim_id}', \
senderlp = '${quote_mysql:${lc:$sender_address_local_part}}', \
senderdom = '${quote_mysql:$sender_address_domain}', \
- delivlp = '${quote_mysql:${lc:$dbl_delivery_local_part}}', \
- delivdom = '${quote_mysql:$dbl_delivery_domain}', \
- delivip = '${quote_mysql:$dbl_delivery_ip}', \
- delivport = '${quote_mysql:$dbl_delivery_port}', \
- delivfqdn = '${quote_mysql:$dbl_delivery_fqdn}', \
- deliverrno = '${quote_mysql:$dbl_defer_errno}', \
- deliverrstr = '${quote_mysql:$dbl_defer_errstr}' \
+ delivlp = '${quote_mysql:${lc:$tpda_delivery_local_part}}', \
+ delivdom = '${quote_mysql:$tpda_delivery_domain}', \
+ delivip = '${quote_mysql:$tpda_delivery_ip}', \
+ delivport = '${quote_mysql:$tpda_delivery_port}', \
+ delivfqdn = '${quote_mysql:$tpda_delivery_fqdn}', \
+ deliverrno = '${quote_mysql:$tpda_defer_errno}', \
+ deliverrstr = '${quote_mysql:$tpda_defer_errstr}' \
}}
--------------------------------------------------------------
# Uncomment the following line to add Per-Recipient-Data-Response support.
# EXPERIMENTAL_PRDR=yes
-# This feature allows to write log information about a completed
-# delivery into a database
-# EXPERIMENTAL_DBL=yes
+# Uncomment the following line to support Transport post-delivery actions,
+# eg. for logging to a database.
+# EXPERIMENTAL_TPDA=yes
###############################################################################
#define EXPERIMENTAL_PRDR
#define EXPERIMENTAL_SPF
#define EXPERIMENTAL_SRS
-#define EXPERIMENTAL_DBL
+#define EXPERIMENTAL_TPDA
/* For developers */
#define WANT_DEEPER_PRINTF_CHECKS
have a pointer to the host item that succeeded; local deliveries can have a
pointer to a single host item in their host list, for use by the transport. */
-#ifdef EXPERIMENTAL_DBL
- dbl_delivery_ip = NULL; /* presume no successful remote delivery */
- dbl_delivery_port = 0;
- dbl_delivery_fqdn = NULL;
- dbl_delivery_local_part = NULL;
- dbl_delivery_domain = NULL;
- dbl_delivery_confirmation = NULL;
+#ifdef EXPERIMENTAL_TPDA
+ tpda_delivery_ip = NULL; /* presume no successful remote delivery */
+ tpda_delivery_port = 0;
+ tpda_delivery_fqdn = NULL;
+ tpda_delivery_local_part = NULL;
+ tpda_delivery_domain = NULL;
+ tpda_delivery_confirmation = NULL;
#endif
s = reset_point = store_get(size);
if (addr->host_list != NULL)
{
s = string_append(s, &size, &ptr, 2, US" H=", addr->host_list->name);
- #ifdef EXPERIMENTAL_DBL
- dbl_delivery_fqdn = addr->host_list->name;
+ #ifdef EXPERIMENTAL_TPDA
+ tpda_delivery_fqdn = addr->host_list->name;
#endif
}
if (addr->shadow_message != NULL)
if (continue_sequence > 1)
s = string_cat(s, &size, &ptr, US"*", 1);
- #ifdef EXPERIMENTAL_DBL
- dbl_delivery_ip = addr->host_used->address;
- dbl_delivery_port = addr->host_used->port;
- dbl_delivery_fqdn = addr->host_used->name;
- dbl_delivery_local_part = addr->local_part;
- dbl_delivery_domain = addr->domain;
- dbl_delivery_confirmation = addr->message;
+ #ifdef EXPERIMENTAL_TPDA
+ tpda_delivery_ip = addr->host_used->address;
+ tpda_delivery_port = addr->host_used->port;
+ tpda_delivery_fqdn = addr->host_used->name;
+ tpda_delivery_local_part = addr->local_part;
+ tpda_delivery_domain = addr->domain;
+ tpda_delivery_confirmation = addr->message;
#endif
}
s[ptr] = 0;
log_write(0, flags, "%s", s);
-#ifdef EXPERIMENTAL_DBL
-if (addr->transport->dbl_delivery_query)
+#ifdef EXPERIMENTAL_TPDA
+if (addr->transport->tpda_delivery_action)
{
DEBUG(D_deliver)
- {
- debug_printf(" DBL(Delivery): dbl_delivery_query=|%s| dbl_delivery_IP=%s\n",
- addr->transport->dbl_delivery_query, dbl_delivery_ip);
- }
+ debug_printf(" TPDA(Delivery): tpda_deliver_action=|%s| tpda_delivery_IP=%s\n",
+ addr->transport->tpda_delivery_action, tpda_delivery_ip);
+
router_name = addr->router->name;
transport_name = addr->transport->name;
- expand_string(addr->transport->dbl_delivery_query);
+ expand_string(addr->transport->tpda_delivery_action);
router_name = NULL;
transport_name = NULL;
}
#ifdef EXPERIMENTAL_PRDR
fprintf(f, " Experimental_PRDR");
#endif
-#ifdef EXPERIMENTAL_DBL
- fprintf(f, " Experimental_DBL");
+#ifdef EXPERIMENTAL_TPDA
+ fprintf(f, " Experimental_TPDA");
#endif
fprintf(f, "\n");
{ "compile_date", vtype_stringptr, &version_date },
{ "compile_number", vtype_stringptr, &version_cnumber },
{ "csa_status", vtype_stringptr, &csa_status },
-#ifdef EXPERIMENTAL_DBL
- { "dbl_defer_errno", vtype_int, &dbl_defer_errno },
- { "dbl_defer_errstr", vtype_stringptr, &dbl_defer_errstr },
- { "dbl_delivery_confirmation", vtype_stringptr, &dbl_delivery_confirmation },
- { "dbl_delivery_domain", vtype_stringptr, &dbl_delivery_domain },
- { "dbl_delivery_fqdn", vtype_stringptr, &dbl_delivery_fqdn },
- { "dbl_delivery_ip", vtype_stringptr, &dbl_delivery_ip },
- { "dbl_delivery_local_part",vtype_stringptr,&dbl_delivery_local_part },
- { "dbl_delivery_port", vtype_int, &dbl_delivery_port },
-#endif
#ifdef EXPERIMENTAL_DCC
{ "dcc_header", vtype_stringptr, &dcc_header },
{ "dcc_result", vtype_stringptr, &dcc_result },
{ "tod_logfile", vtype_todlf, NULL },
{ "tod_zone", vtype_todzone, NULL },
{ "tod_zulu", vtype_todzulu, NULL },
+#ifdef EXPERIMENTAL_TPDA
+ { "tpda_defer_errno", vtype_int, &tpda_defer_errno },
+ { "tpda_defer_errstr", vtype_stringptr, &tpda_defer_errstr },
+ { "tpda_delivery_confirmation", vtype_stringptr, &tpda_delivery_confirmation },
+ { "tpda_delivery_domain", vtype_stringptr, &tpda_delivery_domain },
+ { "tpda_delivery_fqdn", vtype_stringptr, &tpda_delivery_fqdn },
+ { "tpda_delivery_ip", vtype_stringptr, &tpda_delivery_ip },
+ { "tpda_delivery_local_part",vtype_stringptr,&tpda_delivery_local_part },
+ { "tpda_delivery_port", vtype_int, &tpda_delivery_port },
+#endif
{ "transport_name", vtype_stringptr, &transport_name },
{ "value", vtype_stringptr, &lookup_value },
{ "version_number", vtype_stringptr, &version_string },
int daemon_startup_retries = 9;
int daemon_startup_sleep = 30;
-#ifdef EXPERIMENTAL_DBL
-int dbl_defer_errno = 0;
-uschar *dbl_defer_errstr = NULL;
-uschar *dbl_delivery_ip = NULL;
-int dbl_delivery_port = 0;
-uschar *dbl_delivery_fqdn = NULL;
-uschar *dbl_delivery_local_part= NULL;
-uschar *dbl_delivery_domain = NULL;
-uschar *dbl_delivery_confirmation = NULL;
-#endif
-
#ifdef EXPERIMENTAL_DCC
BOOL dcc_direct_add_header = FALSE;
uschar *dcc_header = NULL;
int timeout_frozen_after = 0;
BOOL timestamps_utc = FALSE;
+#ifdef EXPERIMENTAL_TPDA
+int tpda_defer_errno = 0;
+uschar *tpda_defer_errstr = NULL;
+uschar *tpda_delivery_ip = NULL;
+int tpda_delivery_port = 0;
+uschar *tpda_delivery_fqdn = NULL;
+uschar *tpda_delivery_local_part= NULL;
+uschar *tpda_delivery_domain = NULL;
+uschar *tpda_delivery_confirmation = NULL;
+#endif
+
transport_instance *transports = NULL;
transport_instance transport_defaults = {
extern uschar *dccifd_options; /* options for the dccifd daemon */
#endif
-#ifdef EXPERIMENTAL_DBL
-extern int dbl_defer_errno; /* error number set when a remote delivery is deferred with a host error */
-extern uschar *dbl_defer_errstr; /* error string set when a remote delivery is deferred with a host error */
-extern uschar *dbl_delivery_ip; /* IP of host, which has accepted delivery */
-extern int dbl_delivery_port; /* port of host, which has accepted delivery */
-extern uschar *dbl_delivery_fqdn; /* FQDN of host, which has accepted delivery */
-extern uschar *dbl_delivery_local_part;/* local part of address being delivered */
-extern uschar *dbl_delivery_domain; /* domain part of address being delivered */
-extern uschar *dbl_delivery_confirmation; /* SMTP confirmation message */
-#endif
-
extern BOOL debug_daemon; /* Debug the daemon process only */
extern int debug_fd; /* The fd for debug_file */
extern FILE *debug_file; /* Where to write debugging info */
extern int thismessage_size_limit; /* Limit for this message */
extern int timeout_frozen_after; /* Max time to keep frozen messages */
extern BOOL timestamps_utc; /* Use UTC for all times */
+
+#ifdef EXPERIMENTAL_TPDA
+extern int tpda_defer_errno; /* error number set when a remote delivery is deferred with a host error */
+extern uschar *tpda_defer_errstr; /* error string set when a remote delivery is deferred with a host error */
+extern uschar *tpda_delivery_ip; /* IP of host, which has accepted delivery */
+extern int tpda_delivery_port; /* port of host, which has accepted delivery */
+extern uschar *tpda_delivery_fqdn; /* FQDN of host, which has accepted delivery */
+extern uschar *tpda_delivery_local_part;/* local part of address being delivered */
+extern uschar *tpda_delivery_domain; /* domain part of address being delivered */
+extern uschar *tpda_delivery_confirmation; /* SMTP confirmation message */
+#endif
+
extern uschar *transport_name; /* Name of transport last started */
extern int transport_count; /* Count of bytes transported */
extern int transport_newlines; /* Accurate count of number of newline chars transported */
BOOL log_fail_output;
BOOL log_defer_output;
BOOL retry_use_local_part; /* Defaults true for local, false for remote */
-#ifdef EXPERIMENTAL_DBL
- uschar *dbl_delivery_query; /* String to expand on success */
+#ifdef EXPERIMENTAL_TPDA
+ uschar *tpda_delivery_action; /* String to expand on success */
#endif
} transport_instance;
(void *)offsetof(transport_instance, body_only) },
{ "current_directory", opt_stringptr|opt_public,
(void *)offsetof(transport_instance, current_dir) },
-#ifdef EXPERIMENTAL_DBL
- { "dbl_delivery_query",opt_stringptr | opt_public,
- (void *)offsetof(transport_instance, dbl_delivery_query) },
-#endif
{ "debug_print", opt_stringptr | opt_public,
(void *)offsetof(transport_instance, debug_string) },
{ "delivery_date_add", opt_bool|opt_public,
(void *)offsetof(transport_instance, shadow_condition) },
{ "shadow_transport", opt_stringptr|opt_public,
(void *)offsetof(transport_instance, shadow) },
+#ifdef EXPERIMENTAL_TPDA
+ { "tpda_delivery_action",opt_stringptr | opt_public,
+ (void *)offsetof(transport_instance, tpda_delivery_action) },
+#endif
{ "transport_filter", opt_stringptr|opt_public,
(void *)offsetof(transport_instance, filter_command) },
{ "transport_filter_timeout", opt_time|opt_public,
(void *)offsetof(transport_instance, connection_max_messages) },
{ "data_timeout", opt_time,
(void *)offsetof(smtp_transport_options_block, data_timeout) },
-#ifdef EXPERIMENTAL_DBL
- { "dbl_host_defer_query", opt_stringptr,
- (void *)offsetof(smtp_transport_options_block, dbl_host_defer_query) },
-#endif
{ "delay_after_cutoff", opt_bool,
(void *)offsetof(smtp_transport_options_block, delay_after_cutoff) },
#ifndef DISABLE_DKIM
{ "tls_verify_certificates", opt_stringptr,
(void *)offsetof(smtp_transport_options_block, tls_verify_certificates) }
#endif
+#ifdef EXPERIMENTAL_TPDA
+ ,{ "tpda_host_defer_action", opt_stringptr,
+ (void *)offsetof(smtp_transport_options_block, tpda_host_defer_action) },
+#endif
};
/* Size of the options list. An extern variable has to be used so that its
NULL, /* dkim_sign_headers */
NULL /* dkim_strict */
#endif
-#ifdef EXPERIMENTAL_DBL
- ,NULL /* dbl_host_defer_query */
+#ifdef EXPERIMENTAL_TPDA
+ ,NULL /* tpda_host_defer_action */
#endif
};
-#ifdef EXPERIMENTAL_DBL
+#ifdef EXPERIMENTAL_TPDA
/*************************************************
-* Write error message to database log *
+* Post-defer action *
*************************************************/
/* This expands an arbitrary per-transport string.
It might, for example, be used to write to the database log.
Arguments:
- dbl_host_defer_query dbl_host_defer_query from the transport options block
+ ob transport options block
addr the address item containing error information
host the current host
*/
static void
-dbl_write_defer_log(uschar *dbl_host_defer_query, address_item *addr, host_item *host)
+tpda_deferred(smtp_transport_options_block *ob, address_item *addr, host_item *host)
{
-if (dbl_host_defer_query == NULL)
+uschar *action = ob->tpda_host_defer_action;
+if (!action)
return;
-dbl_delivery_ip = string_copy(host->address);
-dbl_delivery_port = (host->port == PORT_NONE)? 25 : host->port;
-dbl_delivery_fqdn = string_copy(host->name);
-dbl_delivery_local_part = string_copy(addr->local_part);
-dbl_delivery_domain = string_copy(addr->domain);
-dbl_defer_errno = addr->basic_errno;
-
-dbl_defer_errstr = (addr->message != NULL)
- ? (addr->basic_errno > 0)
- ? string_sprintf("%s: %s", addr->message, strerror(addr->basic_errno))
- : string_copy(addr->message)
- : (addr->basic_errno > 0)
- ? string_copy(strerror(addr->basic_errno))
- : NULL;
-
-DEBUG(D_transport) {
- debug_printf(" DBL(host defer): dbl_host_defer_query=|%s| dbl_delivery_IP=%s\n", dbl_host_defer_query, dbl_delivery_ip);
-}
+tpda_delivery_ip = string_copy(host->address);
+tpda_delivery_port = (host->port == PORT_NONE)? 25 : host->port;
+tpda_delivery_fqdn = string_copy(host->name);
+tpda_delivery_local_part = string_copy(addr->local_part);
+tpda_delivery_domain = string_copy(addr->domain);
+tpda_defer_errno = addr->basic_errno;
+
+tpda_defer_errstr = addr->message
+ ? addr->basic_errno > 0
+ ? string_sprintf("%s: %s", addr->message, strerror(addr->basic_errno))
+ : string_copy(addr->message)
+ : addr->basic_errno > 0
+ ? string_copy(strerror(addr->basic_errno))
+ : NULL;
+
+DEBUG(D_transport)
+ debug_printf(" TPDA(host defer): tpda_host_defer_action=|%s| tpda_delivery_IP=%s\n",
+ action, tpda_delivery_ip);
router_name = addr->router->name;
transport_name = addr->transport->name;
-expand_string(dbl_host_defer_query);
+expand_string(action);
router_name = transport_name = NULL;
}
#endif
/* Set up confirmation if needed - applies only to SMTP */
if (
- #ifndef EXPERIMENTAL_DBL
+ #ifndef EXPERIMENTAL_TPDA
(log_extra_selector & LX_smtp_confirmation) != 0 &&
#endif
!lmtp
first_addr->basic_errno != ERRNO_TLSFAILURE)
write_logs(first_addr, host);
- #ifdef EXPERIMENTAL_DBL
+ #ifdef EXPERIMENTAL_TPDA
if (rc == DEFER)
- dbl_write_defer_log(ob->dbl_host_defer_query, first_addr, host);
+ tpda_deferred(ob, first_addr, host);
#endif
/* If STARTTLS was accepted, but there was a failure in setting up the
expanded_hosts != NULL, &message_defer, TRUE);
if (rc == DEFER && first_addr->basic_errno != ERRNO_AUTHFAIL)
write_logs(first_addr, host);
- #ifdef EXPERIMENTAL_DBL
+ #ifdef EXPERIMENTAL_TPDA
if (rc == DEFER)
- dbl_write_defer_log(ob->dbl_host_defer_query, first_addr, host);
+ tpda_deferred(ob, first_addr, host);
#endif
}
#endif
uschar *dkim_sign_headers;
uschar *dkim_strict;
#endif
- #ifdef EXPERIMENTAL_DBL
- uschar *dbl_host_defer_query;
+ #ifdef EXPERIMENTAL_TPDA
+ uschar *tpda_host_defer_action;
#endif
} smtp_transport_options_block;
logger:
accept logwrite = \
$acl_arg1 \
- ip <$dbl_delivery_ip> \
- port <$dbl_delivery_port> \
- fqdn <$dbl_delivery_fqdn> \
- local_part <$dbl_delivery_local_part> \
- domain <$dbl_delivery_domain> \
- confirmation <$dbl_delivery_confirmation> \
- errno <$dbl_defer_errno> \
- errstr <$dbl_defer_errstr> \
+ ip <$tpda_delivery_ip> \
+ port <$tpda_delivery_port> \
+ fqdn <$tpda_delivery_fqdn> \
+ local_part <$tpda_delivery_local_part> \
+ domain <$tpda_delivery_domain> \
+ confirmation <$tpda_delivery_confirmation> \
+ errno <$tpda_defer_errno> \
+ errstr <$tpda_defer_errstr> \
router <$router_name> \
transport <$transport_name>
port = PORT_S
command_timeout = 1s
final_timeout = 1s
- dbl_delivery_query = ${acl {logger}{delivery}}
- dbl_host_defer_query = ${acl {logger}{deferral}}
+ tpda_delivery_action = ${acl {logger}{delivery}}
+ tpda_host_defer_action = ${acl {logger}{deferral}}
# End
+++ /dev/null
-# Arbtirary expansion after transport
-# (EXPERIMENTAL_BDL - database logging)
-#
-need_ipv4
-#
-exim -odq userx@domain1
-A deliverable message
-****
-server PORT_S
-220 ESMTP
-EHLO
-250-OK
-250 HELP
-MAIL
-250 OK
-RCPT
-250 OK
-DATA
-354 More...
-.
-250 OK
-QUIT
-220 OK
-****
-exim -qqf
-****
-#
-#
-#
-server PORT_S
-220 ESMTP
-EHLO
-*sleep 4
-****
-exim -odi userx@domain1.com
-A message which will hit a timeout
-.
-****
-
+++ /dev/null
-support Experimental_DBL
--- /dev/null
+# Arbtirary expansion after transport
+# (EXPERIMENTAL_BDL - database logging)
+#
+need_ipv4
+#
+exim -odq userx@domain1
+A deliverable message
+****
+server PORT_S
+220 ESMTP
+EHLO
+250-OK
+250 HELP
+MAIL
+250 OK
+RCPT
+250 OK
+DATA
+354 More...
+.
+250 OK
+QUIT
+220 OK
+****
+exim -qqf
+****
+#
+#
+#
+server PORT_S
+220 ESMTP
+EHLO
+*sleep 4
+****
+exim -odi userx@domain1.com
+A message which will hit a timeout
+.
+****
+
--- /dev/null
+support Experimental_TPDA
no_return_path_add
shadow_condition =
shadow_transport =
+tpda_delivery_action =
transport_filter =
transport_filter_timeout = 5m
user =
no_return_path_add
shadow_condition =
shadow_transport =
+tpda_delivery_action =
transport_filter =
transport_filter_timeout = 5m
user =