WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-]]--
+]] --
-- Common dmarc stuff
local rspamd_logger = require "rspamd_logger"
local ip = task:get_from_ip()
if not ip or not ip:is_valid() then
rspamd_logger.infox(task, 'cannot store dmarc report for %s: no valid source IP',
- data.domain)
+ data.domain)
return nil
end
if rspamd_lua_utils.is_rspamc_or_controller(task) and not settings.reporting.report_local_controller then
rspamd_logger.infox(task, 'cannot store dmarc report for %s from IP %s: has come from controller/rspamc',
- data.domain, ip)
+ data.domain, ip)
return
end
end
exports.gen_munging_callback = function(munging_opts, settings)
- local rspamd_util = require "rspamd_util"
local lua_mime = require "lua_mime"
return function(task)
if munging_opts.mitigate_allow_only then
if not task:has_symbol(settings.symbols.allow) then
lua_util.debugm(N, task, 'skip munging, no %s symbol',
- settings.symbols.allow)
+ settings.symbols.allow)
-- Excepted
return
end
if not has_dmarc then
lua_util.debugm(N, task, 'skip munging, no %s symbol',
- settings.symbols.allow)
+ settings.symbols.allow)
-- Excepted
return
end
if not seen_strict then
lua_util.debugm(N, task, 'skip munging, no strict policy found in %s',
- settings.symbols.allow)
+ settings.symbols.allow)
-- Excepted
return
end
local accepted, trace = munging_opts.munge_map_condition:process(task)
if not accepted then
lua_util.debugm(N, task, 'skip munging, maps condition not satisfied: (%s)',
- trace)
+ trace)
-- Excepted
return
end
via_name = string.format('%s via %s', from.name, via_user)
end
- local encoded_via_name = rspamd_util.mime_header_encode(via_name)
- local via_from_folded = rspamd_util.fold_header('From',
- string.format('%s <%s>', encoded_via_name, via_addr),
- task:get_newlines_type())
- local encoded_orig_name = rspamd_util.mime_header_encode(from.name or '')
- local orig_from_folded = rspamd_util.fold_header('X-Original-From',
- string.format('%s <%s>', encoded_orig_name, from.addr),
- task:get_newlines_type())
+ local via_from_folded = lua_util.fold_header_with_encoding(task, 'From',
+ string.format('%s <%s>', via_name, via_addr), { structured = true })
+ local orig_from_folded = lua_util.fold_header_with_encoding(task, 'X-Original-From',
+ string.format('%s <%s>', from.name or '', from.addr), { structured = true })
local add_hdrs = {
['From'] = { order = 1, value = via_from_folded },
['X-Original-From'] = { order = 0, value = orig_from_folded },
add = add_hdrs
})
lua_util.debugm(N, task, 'munged DMARC header for %s: %s -> %s',
- from.domain, via_from_folded, from.addr)
+ from.domain, via_from_folded, from.addr)
rspamd_logger.infox(task, 'munged DMARC header for %s', from.addr)
task:insert_result('DMARC_MUNGED', 1.0, from.addr)
end
local elts = dmarc_grammar:match(record)
lua_util.debugm(N, log_obj, "got DMARC record: %s, tld_flag=%s, processed=%s",
- record, is_tld, elts)
+ record, is_tld, elts)
if elts then
elts = dmarc_key_value_case(elts)
end
end
- header = lua_util.fold_header(task,
+ header = lua_util.fold_header_with_encoding(task,
'ARC-Message-Signature',
- header)
+ header,
+ { structured = true, encode = false })
cur_auth_results = string.format('i=%d; %s', cur_idx, cur_auth_results)
- cur_auth_results = lua_util.fold_header(task,
+ cur_auth_results = lua_util.fold_header_with_encoding(task,
'ARC-Authentication-Results',
- cur_auth_results, ';')
+ cur_auth_results,
+ { stop_chars = ';', structured = true, encode = false })
local s = dkim_canonicalize('ARC-Authentication-Results',
cur_auth_results)
['ARC-Message-Signature'] = { order = 1, value = header },
['ARC-Seal'] = {
order = 1,
- value = lua_util.fold_header(task,
- 'ARC-Seal', cur_arc_seal)
+ value = lua_util.fold_header_with_encoding(task,
+ 'ARC-Seal', cur_arc_seal,
+ { structured = true, encode = false })
}
},
-- RFC requires a strict order for these headers to be inserted
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-]]--
+]] --
local N = "bimi"
local lua_util = require "lua_util"
if policy ~= 'reject' and policy ~= 'quarantine' then
lua_util.debugm(N, task, "DMARC policy for domain %s is not strict: %s",
- dom, policy)
+ dom, policy)
return nil
end
if elts then
lua_util.debugm(N, task, "got BIMI record: %s, processed=%s",
- rec, elts)
+ rec, elts)
local res = {}
if type(elts.l) == 'string' then
local hdr_name = 'BIMI-Indicator'
-- Re-encode base64...
local content = rspamd_util.encode_base64(rspamd_util.decode_base64(bimi_content),
- 73, task:get_newlines_type())
+ 73, task:get_newlines_type())
lua_mime.modify_headers(task, {
remove = { [hdr_name] = 0 },
add = {
[hdr_name] = {
order = 0,
- value = rspamd_util.fold_header(hdr_name, content,
- task:get_newlines_type())
+ value = lua_util.fold_header_with_encoding(task, hdr_name, content, { encode = false })
}
}
})
if err then
rspamd_logger.errx(task, "cannot parse BIMI result from Redis for %s: %s",
- domain, err)
+ domain, err)
else
local d = parser:get_object()
if d.content then
insert_bimi_headers(task, domain, d.content)
elseif d.error then
lua_util.debugm(N, task, "invalid BIMI for %s: %s",
- domain, d.error)
+ domain, d.error)
end
end
end
local is_sync = settings.helper_sync
local helper_url = string.format('%s/v1/check', settings.helper_url)
local redis_key = string.format('%s%s', settings.redis_prefix,
- domain)
+ domain)
local function http_helper_callback(http_err, code, body, _)
if http_err then
rspamd_logger.warnx(task, 'got error reply from helper %s: code=%s; reply=%s',
- helper_url, code, http_err)
+ helper_url, code, http_err)
return
end
if code ~= 200 then
rspamd_logger.warnx(task, 'got non 200 reply from helper %s: code=%s; reply=%s',
- helper_url, code, http_err)
+ helper_url, code, http_err)
return
end
if is_sync then
if err then
rspamd_logger.errx(task, "cannot parse BIMI result from helper for %s: %s",
- domain, err)
+ domain, err)
else
local d = parser:get_object()
if d.content then
insert_bimi_headers(task, domain, d.content)
elseif d.error then
lua_util.debugm(N, task, "invalid BIMI for %s: %s",
- domain, d.error)
+ domain, d.error)
end
local ret, upstream
local function redis_set_cb(redis_err, _)
if redis_err then
rspamd_logger.warnx(task, 'cannot get reply from Redis when storing image %s: %s',
- upstream:get_addr():to_string(), redis_err)
+ upstream:get_addr():to_string(), redis_err)
upstream:fail()
else
lua_util.debugm(N, task, 'stored bimi image in Redis for domain %s; key=%s',
- domain, redis_key)
+ domain, redis_key)
end
end
ret, _, upstream = lua_redis.redis_make_request(task,
- redis_params, -- connect params
- redis_key, -- hash key
- true, -- is write
- redis_set_cb, --callback
- 'PSETEX', -- command
- { redis_key, tostring(settings.redis_min_expiry * 1000.0),
- ucl.to_format(d, "json-compact") })
+ redis_params, -- connect params
+ redis_key, -- hash key
+ true, -- is write
+ redis_set_cb, --callback
+ 'PSETEX', -- command
+ { redis_key, tostring(settings.redis_min_expiry * 1000.0),
+ ucl.to_format(d, "json-compact") })
if not ret then
rspamd_logger.warnx(task, 'cannot make request to Redis when storing image; domain %s',
- domain)
+ domain)
end
end
else
-- In async mode we skip request and use merely Redis to insert indicators
lua_util.debugm(N, task, "sent request to resolve %s to %s",
- domain, helper_url)
+ domain, helper_url)
end
end
local serialised = ucl.to_format(request_data, 'json-compact')
lua_util.debugm(N, task, "send request to BIMI helper: %s",
- serialised)
+ serialised)
rspamd_http.request({
task = task,
mime_type = 'application/json',
local function check_bimi_vmc(task, domain, record)
local redis_key = string.format('%s%s', settings.redis_prefix,
- domain)
+ domain)
local ret, _, upstream
local function redis_cached_cb(err, data)
if err then
rspamd_logger.warnx(task, 'cannot get reply from Redis %s: %s',
- upstream:get_addr():to_string(), err)
+ upstream:get_addr():to_string(), err)
upstream:fail()
else
if type(data) == 'string' then
-- We got a cached record, good stuff
lua_util.debugm(N, task, "got valid cached BIMI result for domain: %s",
- domain)
+ domain)
process_bimi_json(task, domain, data)
else
-- Get server addr + port
password = string.format(':%s@', redis_params.password)
end
local redis_server = string.format('redis://%s%s:%s%s',
- password,
- upstream:get_name(), upstream:get_port(),
- db)
+ password,
+ upstream:get_name(), upstream:get_port(),
+ db)
make_helper_request(task, domain, record, redis_server)
end
end
-- We first check Redis and then try to use helper
ret, _, upstream = lua_redis.redis_make_request(task,
- redis_params, -- connect params
- redis_key, -- hash key
- false, -- is write
- redis_cached_cb, --callback
- 'GET', -- command
- { redis_key })
+ redis_params, -- connect params
+ redis_key, -- hash key
+ false, -- is write
+ redis_cached_cb, --callback
+ 'GET', -- command
+ { redis_key })
if not ret then
rspamd_logger.warnx(task, 'cannot make request to Redis; domain %s', domain)
local dns_cb = function(_, _, results, err)
if err then
lua_util.debugm(N, task, "cannot resolve bimi for %s: %s",
- domain, err)
+ domain, err)
else
for _, rec in ipairs(results) do
local res = check_bimi_record(task, rec)
if res then
if settings.vmc_only and not res.a then
lua_util.debugm(N, task, "BIMI for domain %s has no VMC, skip it",
- domain)
+ domain)
return
end
elseif res.l then
-- TODO: add l check
lua_util.debugm(N, task, "l only BIMI for domain %s is not implemented yet",
- domain)
+ domain)
end
end
end
type = 'normal',
callback = bimi_callback,
augmentations = { string.format("timeout=%f", settings.helper_timeout or
- redis_params.timeout or 0.0) }
+ redis_params.timeout or 0.0) }
})
rspamd_config:register_symbol {
name = 'BIMI_VALID',
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-]]--
+]] --
-- Dmarc policy filter
end
lua_util.debugm(N, task,
- "validated dmarc policy for %s: %s; dkim_ok=%s, dkim_tempfail=%s, spf_ok=%s, spf_tempfail=%s",
- policy.domain, policy.dmarc_policy,
- dkim_ok, dkim_tmpfail,
- spf_ok, spf_tmpfail)
+ "validated dmarc policy for %s: %s; dkim_ok=%s, dkim_tempfail=%s, spf_ok=%s, spf_tempfail=%s",
+ policy.domain, policy.dmarc_policy,
+ dkim_ok, dkim_tmpfail,
+ spf_ok, spf_tmpfail)
local disposition = 'none'
local sampled_out = false
local function handle_dmarc_failure(what, reason_str)
if not policy.pct or policy.pct == 100 then
task:insert_result(settings.symbols[what], 1.0,
- policy.domain .. ' : ' .. reason_str, policy.dmarc_policy)
+ policy.domain .. ' : ' .. reason_str, policy.dmarc_policy)
disposition = what
else
local coin = math.random(100)
if (coin > policy.pct) then
if (not settings.no_sampling_domains or
- not settings.no_sampling_domains:get_key(policy.domain)) then
-
+ not settings.no_sampling_domains:get_key(policy.domain)) then
if what == 'reject' then
disposition = 'quarantine'
else
end
task:insert_result(settings.symbols[disposition], 1.0,
- policy.domain .. ' : ' .. reason_str, policy.dmarc_policy, "sampled_out")
+ policy.domain .. ' : ' .. reason_str, policy.dmarc_policy, "sampled_out")
sampled_out = true
lua_util.debugm(N, task,
- 'changed dmarc policy from %s to %s, sampled out: %s < %s',
- what, disposition, coin, policy.pct)
+ 'changed dmarc policy from %s to %s, sampled out: %s < %s',
+ what, disposition, coin, policy.pct)
else
task:insert_result(settings.symbols[what], 1.0,
- policy.domain .. ' : ' .. reason_str, policy.dmarc_policy, "local_policy")
+ policy.domain .. ' : ' .. reason_str, policy.dmarc_policy, "local_policy")
disposition = what
end
else
task:insert_result(settings.symbols[what], 1.0,
- policy.domain .. ' : ' .. reason_str, policy.dmarc_policy)
+ policy.domain .. ' : ' .. reason_str, policy.dmarc_policy)
disposition = what
end
end
DMARC evaluation can only yield a "pass" result after one of the
underlying authentication mechanisms passes for an aligned
identifier.
- ]]--
+ ]] --
task:insert_result(settings.symbols['allow'], 1.0, policy.domain,
- policy.dmarc_policy)
+ policy.dmarc_policy)
else
--[[
https://tools.ietf.org/html/rfc7489#section-6.6.2
temporary error, the Receiver evaluating the message is unable to
conclude that the DMARC mechanism had a permanent failure; they
therefore cannot apply the advertised DMARC policy.
- ]]--
+ ]] --
if spf_tmpfail or dkim_tmpfail then
task:insert_result(settings.symbols['dnsfail'], 1.0, policy.domain ..
- ' : ' .. 'SPF/DKIM temp error', policy.dmarc_policy)
+ ' : ' .. 'SPF/DKIM temp error', policy.dmarc_policy)
else
-- We can now check the failed policy and maybe send report data elt
local reason_str = table.concat(reason, ', ')
handle_dmarc_failure('reject', reason_str)
else
task:insert_result(settings.symbols['softfail'], 1.0,
- policy.domain .. ' : ' .. reason_str,
- policy.dmarc_policy)
+ policy.domain .. ' : ' .. reason_str,
+ policy.dmarc_policy)
end
end
end
if policy.rua and redis_params and settings.reporting.enabled then
if settings.reporting.only_domains then
if not (settings.reporting.only_domains:get_key(policy.domain) or
- settings.reporting.only_domains:get_key(rspamd_util.get_tld(policy.domain))) then
+ settings.reporting.only_domains:get_key(rspamd_util.get_tld(policy.domain))) then
rspamd_logger.info(task, 'DMARC reporting suppressed for sender domain %s', policy.domain)
return
end
local function dmarc_report_cb(err)
if not err then
rspamd_logger.infox(task, 'dmarc report saved for %s (rua = %s)',
- hdrfromdom, policy.rua)
+ hdrfromdom, policy.rua)
else
rspamd_logger.errx(task, 'dmarc report is not saved for %s: %s',
- hdrfromdom, err)
+ hdrfromdom, err)
end
end
-- Prepare and send redis report element
local period = os.date('%Y%m%d',
- task:get_date({ format = 'connect', gmt = false }))
+ task:get_date({ format = 'connect', gmt = false }))
-- Dmarc domain key must include dmarc domain, rua and period
local dmarc_domain_key = table.concat(
- { settings.reporting.redis_keys.report_prefix, policy.domain, policy.rua, period },
- settings.reporting.redis_keys.join_char)
+ { settings.reporting.redis_keys.report_prefix, policy.domain, policy.rua, period },
+ settings.reporting.redis_keys.join_char)
local report_data = dmarc_common.dmarc_report(task, settings, {
spf_ok = spf_ok and 'pass' or 'fail',
dkim_ok = dkim_ok and 'pass' or 'fail',
})
local idx_key = table.concat({ settings.reporting.redis_keys.index_prefix, period },
- settings.reporting.redis_keys.join_char)
+ settings.reporting.redis_keys.join_char)
if report_data then
lua_redis.exec_redis_script(take_report_id,
- { task = task, is_write = true },
- dmarc_report_cb,
- { idx_key, dmarc_domain_key,
- tostring(settings.reporting.max_entries), tostring(settings.reporting.keys_expire) },
- { hdrfromdom, report_data })
+ { task = task, is_write = true },
+ dmarc_report_cb,
+ { idx_key, dmarc_domain_key,
+ tostring(settings.reporting.max_entries), tostring(settings.reporting.keys_expire) },
+ { hdrfromdom, report_data })
end
end
end
local function process_dmarc_policy(policy, final)
lua_util.debugm(N, task, "validate DMARC policy (final=%s): %s",
- true, policy)
+ true, policy)
if policy.err and policy.symbol then
-- In case of fatal errors or final check for tld, we give up and
-- insert result
if err then
if (err ~= 'requested record is not found' and
- err ~= 'no records with this name') then
+ err ~= 'no records with this name') then
policy_target.err = lookup_domain .. ' : ' .. err
policy_target.symbol = settings.symbols['dnsfail']
else
settings = lua_util.override_defaults(settings, opts)
settings.auth_and_local_conf = lua_util.config_check_local_or_authed(rspamd_config, N,
- false, false)
+ false, false)
-- Legacy...
if settings.reporting and not settings.reporting.exclude_domains and settings.no_reporting_domains then
local munging_defaults = {
reply_goes_to_list = false,
- mitigate_allow_only = true, -- perform munging based on DMARC_POLICY_ALLOW only
+ mitigate_allow_only = true, -- perform munging based on DMARC_POLICY_ALLOW only
mitigate_strict_only = false, -- perform mugning merely for reject/quarantine policies
- munge_from = true, -- replace from with something like <orig name> via <rcpt user>
- list_map = nil, -- map of maillist domains
- munge_map_condition = nil, -- maps expression to enable munging
+ munge_from = true, -- replace from with something like <orig name> via <rcpt user>
+ list_map = nil, -- map of maillist domains
+ munge_map_condition = nil, -- maps expression to enable munging
}
local munging_opts = lua_util.override_defaults(munging_defaults, settings.munging)
end
munging_opts.list_map = lua_maps.map_add_from_ucl(munging_opts.list_map,
- 'set', 'DMARC munging map of the recipients addresses to munge')
+ 'set', 'DMARC munging map of the recipients addresses to munge')
if not munging_opts.list_map then
rspamd_logger.errx(rspamd_config, 'cannot enable DMARC munging with invalid list_map (invalid map)')
if munging_opts.munge_map_condition then
munging_opts.munge_map_condition = lua_maps_expressions.create(rspamd_config,
- munging_opts.munge_map_condition, N)
+ munging_opts.munge_map_condition, N)
end
rspamd_config:register_symbol({
end
end
if result.reason and settings.reason_header then
+ local v = lua_util.fold_header_with_encoding(task, settings.reason_header,
+ tostring(result.reason), { encode = 'auto' })
lua_mime.modify_headers(task,
- { add = { [settings.reason_header] = { value = tostring(result.reason), order = 1 } } })
+ { add = { [settings.reason_header] = { value = v, order = 1 } } })
end
if cache_context then
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-]]--
+]] --
if confighelp then
return
local HOSTNAME = rspamd_util.get_hostname()
local settings = {
- remove_upstream_spam_flag = true;
+ remove_upstream_spam_flag = true,
skip_local = true,
skip_authenticated = true,
skip_all = false,
local_headers = {},
authenticated_headers = {},
headers_modify_mode = 'compat', -- To avoid compatibility issues on upgrade
- default_headers_order = nil, -- Insert at the end (set 1 to insert just after the first received)
+ default_headers_order = nil, -- Insert at the end (set 1 to insert just after the first received)
routines = {
['remove-headers'] = {
headers = {},
local custom_routines = {}
local function milter_headers(task)
-
-- Used to override wanted stuff by means of settings
local settings_override = false
if r.addr and r.domain and r.user then
if settings.extended_headers_rcpt:get_key(r.addr) then
lua_util.debugm(N, task, 'found full addr in recipients for extended headers: %s',
- r.addr)
+ r.addr)
found = true
end
-- Try user as plain match
if not found and settings.extended_headers_rcpt:get_key(r.user) then
lua_util.debugm(N, task, 'found user in recipients for extended headers: %s (%s)',
- r.user, r.addr)
+ r.user, r.addr)
found = true
end
-- Try @domain to match domain
if not found and settings.extended_headers_rcpt:get_key('@' .. r.domain) then
lua_util.debugm(N, task, 'found domain in recipients for extended headers: @%s (%s)',
- r.domain, r.addr)
+ r.domain, r.addr)
found = true
end
end
end
return false
-
end
-- XXX: fix this crap one day
if not add[hname] then
add[hname] = {}
end
- local folded = lua_util.fold_header(task, hname, value, stop_chars)
- if rspamd_config:is_mime_utf8() then
- if not rspamd_util.is_valid_utf8(folded) then
- folded = rspamd_util.mime_header_encode(folded)
- end
- else
- folded = rspamd_util.mime_header_encode(folded)
- end
+ local folded = lua_util.fold_header_with_encoding(task, hname, value, {
+ stop_chars = stop_chars,
+ encode = 'auto'
+ })
table.insert(add[hname], {
order = (order or settings.default_headers_order or -1),
value = folded
local buf = {}
local verdict = string.format('default: %s [%.2f / %.2f]',
- --TODO: (common.metric_action == 'no action') and 'False' or 'True',
- (common.metric_action == 'reject') and 'True' or 'False',
- common.metric_score[1], common.metric_score[2])
+ --TODO: (common.metric_action == 'no action') and 'False' or 'True',
+ (common.metric_action == 'reject') and 'True' or 'False',
+ common.metric_score[1], common.metric_score[2])
table.insert(buf, verdict)
-- Deal with symbols
for _, s in ipairs(common.symbols) do
local sym_str = string.format('%s(%.2f)[%s]',
- s.name, s.score, table.concat(s.options or {}, ','))
+ s.name, s.score, table.concat(s.options or {}, ','))
table.insert(buf, sym_str)
end
add_header('x-spamd-result', table.concat(buf, '; '), ';')
add[local_mod.header] = action
end
- local function spam_header (class, name, value, remove_v)
+ local function spam_header(class, name, value, remove_v)
if skip_wanted(class) then
return
end
routines['spam-header'] = function()
spam_header('spam-header',
- settings.routines['spam-header'].header,
- settings.routines['spam-header'].value,
- settings.routines['spam-header'].remove)
+ settings.routines['spam-header'].header,
+ settings.routines['spam-header'].value,
+ settings.routines['spam-header'].remove)
end
routines['remove-spam-flag'] = function()
else
if local_mod.status_clean then
add_header('x-virus', string.format('%s(%s)',
- local_mod.status_fail, fail_reason))
+ local_mod.status_fail, fail_reason))
end
end
end
local local_mod = settings.routines['x-os-fingerprint']
local os_string, link_type, uptime_min, distance = task:get_mempool():get_variable('os_fingerprint',
- 'string, string, double, double');
+ 'string, string, double, double');
if not os_string then
return
end
local value = string.format('%s, (up: %i min), (distance %i, link: %s)',
- os_string, uptime_min, distance, link_type)
+ os_string, uptime_min, distance, link_type)
if local_mod.remove then
remove[local_mod.header] = local_mod.remove
end
local res = ar.gen_auth_results(task,
- lua_util.override_defaults(ar.default_settings,
- settings.routines['authentication-results']))
+ lua_util.override_defaults(ar.default_settings,
+ settings.routines['authentication-results']))
if res then
add_header('authentication-results', res, ';', 1)
if user_settings and type(user_settings.routines) == 'table' then
lua_util.debugm(N, task, 'override routines to %s from user settings',
- user_settings.routines)
+ user_settings.routines)
routines_enabled = user_settings.routines
settings_override = true
end
remove = nil
end
if add or remove then
-
lua_mime.modify_headers(task, {
add = add,
remove = remove
table.insert(active_routines, s)
if (opts.routines and opts.routines[s]) then
settings.routines[s] = lua_util.override_defaults(settings.routines[s],
- opts.routines[s])
+ opts.routines[s])
end
end
else
end
logger.infox(rspamd_config, 'active routines [%s]',
- table.concat(active_routines, ','))
+ table.concat(active_routines, ','))
if opts.extended_headers_rcpt then
settings.extended_headers_rcpt = lua_maps.rspamd_map_add_from_ucl(opts.extended_headers_rcpt,
- 'set', 'Extended headers recipients')
+ 'set', 'Extended headers recipients')
end
rspamd_config:register_symbol({