kumo.configure_log_disposition_hook
Since: Version 2025.10.06-5ec871ab
The functionality described in this section requires version 2025.10.06-5ec871ab of KumoMTA, or a more recent version.
Registers a synchronous logging hook. When a matching log event is generated,
the log_disposition_NAME event is triggered, where NAME is the value of the
name field passed to this function. The registered event handler is called
with the originating Message and the
JsonLogRecord that describes the event.
kumo.on('init', function()
kumo.configure_log_disposition_hook {
name = 'ndr_generator',
}
end)
kumo.on('log_disposition_ndr_generator', function(msg, log_record)
local bounce_msg = kumo.generate_rfc3464_message({
include_original_message = 'FullContent',
enable_bounce = true,
reporting_mta = {
mta_type = 'dns',
name = 'mta1.example.com',
},
}, msg, log_record)
if bounce_msg then
kumo.inject_message(bounce_msg)
end
end)
Unlike kumo.configure_log_hook, which queues a copy of the log record for asynchronous delivery through the normal queueing machinery, the disposition hook runs synchronously as part of processing the disposition of the message. The event handler is invoked before control returns to the caller that produced the log event.
This synchronous behavior guarantees that the message is still present in the spool when the hook runs, which matters because a terminal disposition such as a permanent failure removes the message from the spool once the disposition completes. A hook that needs to read the originating message, such as to generate a bounce report from its content, must use this synchronous form: an asynchronous hook does not run until after the disposition has completed, by which point that removal may have already taken the message out of the spool.
The primary use case is generating RFC 3464 delivery status notifications in response to delivery failures. See kumo.generate_rfc3464_message.
Messages generated by kumo.configure_log_hook are never passed to the disposition hook.
name
Required string naming the hook.
The log_disposition_NAME event, where NAME is this value, is triggered when
a matching log event is generated. The name must be unique across all
configured logging hooks.
per_record
Optional map that controls which record types are passed to the hook. This has
the same shape as record type, although
only the enable boolean is used by the disposition hook. Set enable to
false to exclude that record type from the hook.
When per_record is omitted, every record type is enabled.
The following restricts the hook to Bounce records, which is typical for a
hook that only generates bounce reports:
kumo.on('init', function()
kumo.configure_log_disposition_hook {
name = 'ndr_generator',
per_record = {
Any = {
enable = false,
},
Bounce = {
enable = true,
},
},
}
end)
Using the log_hooks helper
The policy-extras.log_hooks module provides a new_disposition_hook helper
that makes it a little more convenient to set up a disposition hook.
local log_hooks = require 'policy-extras.log_hooks'
log_hooks:new_disposition_hook {
name = 'ndr_generator',
-- Optionally filter/restrict which log records will trigger
-- and call your `hook` function below.
-- (*Since: Dev Builds Only*)
log_parameters = {
per_record = {
Any = { enable = false },
Bounce = { enable = true },
},
},
-- The hook callback, receives the message and log record as
-- described in the configure_log_disposition_hook documentation above.
hook = function(msg, log_record)
local bounce_msg = kumo.generate_rfc3464_message({
include_original_message = 'FullContent',
enable_bounce = true,
reporting_mta = {
mta_type = 'dns',
name = 'mta1.example.com',
},
}, msg, log_record)
if bounce_msg then
kumo.inject_message(bounce_msg)
end
end,
}