diff --git a/data/Dockerfiles/rmilter/Dockerfile b/data/Dockerfiles/rmilter/Dockerfile deleted file mode 100644 index abe286f6..00000000 --- a/data/Dockerfiles/rmilter/Dockerfile +++ /dev/null @@ -1,26 +0,0 @@ -FROM debian:jessie-slim -LABEL maintainer "Andre Peters " - -ARG DEBIAN_FRONTEND=noninteractive -ENV LC_ALL C - -RUN apt-key adv --fetch-keys http://rspamd.com/apt-stable/gpg.key \ - && echo "deb http://rspamd.com/apt-stable/ jessie main" > /etc/apt/sources.list.d/rspamd.list \ - && apt-get update && apt-get install -y --force-yes --no-install-recommends \ - cron \ - rmilter \ - supervisor \ - syslog-ng \ - syslog-ng-core \ - && rm -rf /var/lib/apt/lists/* - -COPY supervisord.conf /etc/supervisor/supervisord.conf - -EXPOSE 9000 - -RUN sed -i -E 's/^(\s*)system\(\);/\1unix-stream("\/dev\/log");/' /etc/syslog-ng/syslog-ng.conf -RUN touch /var/log/mail.log && chmod 640 /var/log/mail.log && chown root:adm /var/log/mail.log - -CMD exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf - -RUN rm -rf /tmp/* /var/tmp/* diff --git a/data/Dockerfiles/rmilter/supervisord.conf b/data/Dockerfiles/rmilter/supervisord.conf deleted file mode 100644 index 41e1328f..00000000 --- a/data/Dockerfiles/rmilter/supervisord.conf +++ /dev/null @@ -1,18 +0,0 @@ -[supervisord] -nodaemon=true - -[program:syslog-ng] -command=/usr/sbin/syslog-ng --foreground --no-caps -redirect_stderr=true -autostart=true -stdout_syslog=true - -[program:rmilter] -command=/usr/sbin/rmilter -n -c /etc/rmilter.conf.d/rmilter.conf -user=_rmilter -autorestart=true - -[program:rmilter-syslog] -command=/usr/bin/tail -f /var/log/mail.log -stdout_logfile=/dev/fd/1 -stdout_logfile_maxbytes=0 diff --git a/data/Dockerfiles/rspamd/Dockerfile b/data/Dockerfiles/rspamd/Dockerfile index 42f2afc2..7ebd1a54 100644 --- a/data/Dockerfiles/rspamd/Dockerfile +++ b/data/Dockerfiles/rspamd/Dockerfile @@ -4,8 +4,8 @@ LABEL maintainer "Andre Peters " ARG DEBIAN_FRONTEND=noninteractive ENV LC_ALL C -RUN apt-key adv --fetch-keys http://rspamd.com/apt-stable/gpg.key \ - && echo "deb http://rspamd.com/apt-stable/ jessie main" > /etc/apt/sources.list.d/rspamd.list \ +RUN apt-key adv --fetch-keys http://rspamd.com/apt/gpg.key \ + && echo "deb http://rspamd.com/apt/ jessie main" > /etc/apt/sources.list.d/rspamd.list \ && apt-get update && apt-get install -y \ ca-certificates \ rspamd \ @@ -15,7 +15,7 @@ RUN echo '.include $LOCAL_CONFDIR/local.d/rspamd.conf.local' > /etc/rspamd/rspam COPY settings.conf /etc/rspamd/modules.d/settings.conf COPY antivirus.conf /etc/rspamd/modules.d/antivirus.conf -COPY dkim_signing.lua /usr/share/rspamd/lua/dkim_signing.lua +COPY milter_headers.lua /usr/share/rspamd/lua/milter_headers.lua RUN apt-get autoremove --purge \ && apt-get clean diff --git a/data/Dockerfiles/rspamd/dkim_signing.lua b/data/Dockerfiles/rspamd/dkim_signing.lua deleted file mode 100644 index b76a73ac..00000000 --- a/data/Dockerfiles/rspamd/dkim_signing.lua +++ /dev/null @@ -1,286 +0,0 @@ ---[[ -Copyright (c) 2016, Andrew Lewis -Copyright (c) 2016, Vsevolod Stakhov - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -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 rspamd_logger = require "rspamd_logger" -local rspamd_util = require "rspamd_util" - -if confighelp then - return -end - -local settings = { - allow_envfrom_empty = true, - allow_hdrfrom_mismatch = false, - allow_hdrfrom_mismatch_local = false, - allow_hdrfrom_mismatch_sign_networks = false, - allow_hdrfrom_multiple = false, - allow_username_mismatch = false, - auth_only = true, - domain = {}, - path = string.format('%s/%s/%s', rspamd_paths['DBDIR'], 'dkim', '$domain.$selector.key'), - sign_local = true, - selector = 'dkim', - symbol = 'DKIM_SIGNED', - try_fallback = true, - use_domain = 'header', - use_esld = true, - use_redis = false, - key_prefix = 'dkim_keys', -- default hash name -} - -local E = {} -local N = 'dkim_signing' -local redis_params - -local function simple_template(tmpl, keys) - local lpeg = require "lpeg" - - local var_lit = lpeg.P { lpeg.R("az") + lpeg.R("AZ") + lpeg.R("09") + "_" } - local var = lpeg.P { (lpeg.P("$") / "") * ((var_lit^1) / keys) } - local var_braced = lpeg.P { (lpeg.P("${") / "") * ((var_lit^1) / keys) * (lpeg.P("}") / "") } - - local template_grammar = lpeg.Cs((var + var_braced + 1)^0) - - return lpeg.match(template_grammar, tmpl) -end - -local function dkim_signing_cb(task) - local is_local, is_sign_networks - local auser = task:get_user() - local ip = task:get_from_ip() - if ip and ip:is_local() then - is_local = true - end - if settings.auth_only and not auser then - if (settings.sign_networks and settings.sign_networks:get_key(ip)) then - is_sign_networks = true - rspamd_logger.debugm(N, task, 'mail is from address in sign_networks') - elseif settings.sign_local and is_local then - rspamd_logger.debugm(N, task, 'mail is from local address') - else - rspamd_logger.debugm(N, task, 'ignoring unauthenticated mail') - return - end - end - local efrom = task:get_from('smtp') - if not settings.allow_envfrom_empty and - #(((efrom or E)[1] or E).addr or '') == 0 then - rspamd_logger.debugm(N, task, 'empty envelope from not allowed') - return false - end - local hfrom = task:get_from('mime') - if not settings.allow_hdrfrom_multiple and (hfrom or E)[2] then - rspamd_logger.debugm(N, task, 'multiple header from not allowed') - return false - end - local dkim_domain - local hdom = ((hfrom or E)[1] or E).domain - local edom = ((efrom or E)[1] or E).domain - if hdom then - hdom = hdom:lower() - end - if edom then - edom = edom:lower() - end - if settings.use_domain_sign_networks and is_sign_networks then - if settings.use_domain_sign_networks == 'header' then - dkim_domain = hdom - else - dkim_domain = edom - end - elseif settings.use_domain_local and is_local then - if settings.use_domain_local == 'header' then - dkim_domain = hdom - else - dkim_domain = edom - end - else - if settings.use_domain == 'header' then - dkim_domain = hdom - else - dkim_domain = edom - end - end - if not dkim_domain then - rspamd_logger.debugm(N, task, 'could not extract dkim domain') - return false - end - if settings.use_esld then - dkim_domain = rspamd_util.get_tld(dkim_domain) - if settings.use_domain == 'envelope' and hdom then - hdom = rspamd_util.get_tld(hdom) - elseif settings.use_domain == 'header' and edom then - edom = rspamd_util.get_tld(edom) - end - end - if edom and hdom and not settings.allow_hdrfrom_mismatch and hdom ~= edom then - if settings.allow_hdrfrom_mismatch_local and is_local then - rspamd_logger.debugm(N, task, 'domain mismatch allowed for local IP: %1 != %2', hdom, edom) - elseif settings.allow_hdrfrom_mismatch_sign_networks and is_sign_networks then - rspamd_logger.debugm(N, task, 'domain mismatch allowed for sign_networks: %1 != %2', hdom, edom) - else - rspamd_logger.debugm(N, task, 'domain mismatch not allowed: %1 != %2', hdom, edom) - return false - end - end - if auser and not settings.allow_username_mismatch then - local udom = string.match(auser, '.*@(.*)') - if not udom then - rspamd_logger.debugm(N, task, 'couldnt find domain in username') - return false - end - if settings.use_esld then - udom = rspamd_util.get_tld(udom) - end - if udom ~= dkim_domain then - rspamd_logger.debugm(N, task, 'user domain mismatch') - return false - end - end - local p = {} - if settings.domain[dkim_domain] then - p.selector = settings.domain[dkim_domain].selector - p.key = settings.domain[dkim_domain].path - end - if not (p.key and p.selector) and not - (settings.try_fallback or settings.use_redis or settings.selector_map or settings.path_map) then - rspamd_logger.debugm(N, task, 'dkim unconfigured and fallback disabled') - return false - end - if not p.key then - if not settings.use_redis then - p.key = settings.path - end - end - if not p.selector then - p.selector = settings.selector - end - p.domain = dkim_domain - - if settings.selector_map then - local data = settings.selector_map:get_key(dkim_domain) - if data then - p.selector = data - end - end - if settings.path_map then - local data = settings.path_map:get_key(dkim_domain) - if data then - p.key = data - end - end - - if settings.use_redis then - local function try_redis_key(selector) - p.key = nil - p.selector = selector - local rk = string.format('%s.%s', p.selector, p.domain) - local function redis_key_cb(err, data) - if err or type(data) ~= 'string' then - rspamd_logger.infox(rspamd_config, "cannot make request to load DKIM key for %s: %s", - rk, err) - else - p.rawkey = data - if rspamd_plugins.dkim.sign(task, p) then - task:insert_result(settings.symbol, 1.0) - end - end - end - local ret = rspamd_redis_make_request(task, - redis_params, -- connect params - rk, -- hash key - false, -- is write - redis_key_cb, --callback - 'HGET', -- command - {settings.key_prefix, rk} -- arguments - ) - if not ret then - rspamd_logger.infox(rspamd_config, "cannot make request to load DKIM key for %s", rk) - end - end - if settings.selector_prefix then - rspamd_logger.infox(rspamd_config, "Using selector prefix %s for domain %s", settings.selector_prefix, p.domain); - local function redis_selector_cb(err, data) - if err or type(data) ~= 'string' then - rspamd_logger.infox(rspamd_config, "cannot make request to load DKIM selector for domain %s: %s", p.domain, err) - else - try_redis_key(data) - end - end - local ret = rspamd_redis_make_request(task, - redis_params, -- connect params - p.domain, -- hash key - false, -- is write - redis_selector_cb, --callback - 'HGET', -- command - {settings.selector_prefix, p.domain} -- arguments - ) - if not ret then - rspamd_logger.infox(rspamd_config, "cannot make request to load DKIM selector for %s", p.domain) - end - else - if not p.selector then - rspamd_logger.errx(task, 'No selector specified') - return false - end - try_redis_key(p.selector) - end - else - if (p.key and p.selector) then - p.key = simple_template(p.key, {domain = p.domain, selector = p.selector}) - return rspamd_plugins.dkim.sign(task, p) - else - rspamd_logger.infox(task, 'key path or dkim selector unconfigured; no signing') - return false - end - end -end - -local opts = rspamd_config:get_all_opt('dkim_signing') -if not opts then return end -for k,v in pairs(opts) do - if k == 'sign_networks' then - settings[k] = rspamd_map_add(N, k, 'radix', 'DKIM signing networks') - elseif k == 'path_map' then - settings[k] = rspamd_map_add(N, k, 'map', 'Paths to DKIM signing keys') - elseif k == 'selector_map' then - settings[k] = rspamd_map_add(N, k, 'map', 'DKIM selectors') - else - settings[k] = v - end -end -if not (settings.use_redis or settings.path or settings.domain or settings.path_map or settings.selector_map) then - rspamd_logger.infox(rspamd_config, 'mandatory parameters missing, disable dkim signing') - return -end -if settings.use_redis then - redis_params = rspamd_parse_redis_server('dkim_signing') - - if not redis_params then - rspamd_logger.errx(rspamd_config, 'no servers are specified, but module is configured to load keys from redis, disable dkim signing') - return - end -end -if settings.use_domain ~= 'header' and settings.use_domain ~= 'envelope' then - rspamd_logger.errx(rspamd_config, "Value for 'use_domain' is invalid") - settings.use_domain = 'header' -end - -rspamd_config:register_symbol({ - name = settings['symbol'], - callback = dkim_signing_cb -}) diff --git a/data/Dockerfiles/rspamd/milter_headers.lua b/data/Dockerfiles/rspamd/milter_headers.lua new file mode 100644 index 00000000..6ad7957a --- /dev/null +++ b/data/Dockerfiles/rspamd/milter_headers.lua @@ -0,0 +1,387 @@ +--[[ +Copyright (c) 2016, Andrew Lewis +Copyright (c) 2016, Vsevolod Stakhov + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +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 +end + +-- A plugin that provides common header manipulations + +local logger = require "rspamd_logger" +local util = require "rspamd_util" +local N = 'milter_headers' +local E = {} + +local HOSTNAME = util.get_hostname() + +local settings = { + skip_local = false, + skip_authenticated = false, + routines = { + ['x-spamd-result'] = { + header = 'X-Spamd-Result', + remove = 1, + }, + ['x-rspamd-server'] = { + header = 'X-Rspamd-Server', + remove = 1, + }, + ['x-rspamd-queue-id'] = { + header = 'X-Rspamd-Queue-Id', + remove = 1, + }, + ['spam-header'] = { + header = 'Deliver-To', + value = 'Junk', + remove = 1, + }, + ['x-virus'] = { + header = 'X-Virus', + remove = 1, + symbols = {}, -- needs config + }, + ['x-spamd-bar'] = { + header = 'X-Spamd-Bar', + positive = '+', + negative = '-', + neutral = '/', + remove = 1, + }, + ['x-spam-level'] = { + header = 'X-Spam-Level', + char = '*', + remove = 1, + }, + ['x-spam-status'] = { + header = 'X-Spam-Status', + remove = 1, + }, + ['authentication-results'] = { + header = 'Authentication-Results', + remove = 1, + spf_symbols = { + pass = 'R_SPF_ALLOW', + fail = 'R_SPF_FAIL', + softfail = 'R_SPF_SOFTFAIL', + neutral = 'R_SPF_NEUTRAL', + temperror = 'R_SPF_DNSFAIL', + none = 'R_SPF_NA', + permerror = 'R_SPF_PERMFAIL', + }, + dkim_symbols = { + pass = 'R_DKIM_ALLOW', + fail = 'R_DKIM_REJECT', + temperror = 'R_DKIM_TEMPFAIL', + none = 'R_DKIM_NA', + permerror = 'R_DKIM_PERMFAIL', + }, + dmarc_symbols = { + pass = 'DMARC_POLICY_ALLOW', + permerror = 'DMARC_BAD_POLICY', + temperror = 'DMARC_DNSFAIL', + none = 'DMARC_NA', + reject = 'DMARC_POLICY_REJECT', + softfail = 'DMARC_POLICY_SOFTFAIL', + quarantine = 'DMARC_POLICY_QUARANTINE', + }, + }, + }, +} + +local active_routines = {} +local custom_routines = {} + +local function milter_headers(task) + + if settings.skip_local then + local ip = task:get_ip() + if (ip and ip:is_local()) then return end + end + + if settings.skip_authenticated then + if task:get_user() ~= nil then return end + end + + local routines, common, add, remove = {}, {}, {}, {} + + routines['x-spamd-result'] = function() + if not common.symbols then + common.symbols = task:get_symbols_all() + common['metric_score'] = task:get_metric_score('default') + common['metric_action'] = task:get_metric_action('default') + end + if settings.routines['x-spamd-result'].remove then + remove[settings.routines['x-spamd-result'].header] = settings.routines['x-spamd-result'].remove + end + local buf = {} + table.insert(buf, table.concat({ + 'default: ', (common['metric_action'] == 'reject') and 'True' or 'False', ' [', + common['metric_score'][1], ' / ', common['metric_score'][2], ']' + })) + for _, s in ipairs(common.symbols) do + if not s.options then s.options = {} end + table.insert(buf, table.concat({ + ' ', s.name, ' (', s.score, ') [', table.concat(s.options, ','), ']', + })) + end + add[settings.routines['x-spamd-result'].header] = table.concat(buf, '\n') + end + + routines['x-rspamd-queue-id'] = function() + if common.queue_id ~= false then + common.queue_id = task:get_queue_id() + if not common.queue_id then + common.queue_id = false + end + end + if settings.routines['x-rspamd-queue-id'].remove then + remove[settings.routines['x-rspamd-queue-id'].header] = settings.routines['x-rspamd-queue-id'].remove + end + if common.queue_id then + add[settings.routines['x-rspamd-queue-id'].header] = common.queue_id + end + end + + routines['x-rspamd-server'] = function() + if settings.routines['x-rspamd-server'].remove then + remove[settings.routines['x-rspamd-server'].header] = settings.routines['x-rspamd-server'].remove + end + add[settings.routines['x-rspamd-server'].header] = HOSTNAME + end + + routines['x-spamd-bar'] = function() + if not common['metric_score'] then + common['metric_score'] = task:get_metric_score('default') + end + local score = common['metric_score'][1] + local spambar + if score <= -1 then + spambar = string.rep(settings.routines['x-spamd-bar'].negative, score*-1) + elseif score >= 1 then + spambar = string.rep(settings.routines['x-spamd-bar'].positive, score) + else + spambar = settings.routines['x-spamd-bar'].neutral + end + if settings.routines['x-spamd-bar'].remove then + remove[settings.routines['x-spamd-bar'].header] = settings.routines['x-spamd-bar'].remove + end + if spambar ~= '' then + add[settings.routines['x-spamd-bar'].header] = spambar + end + end + + routines['x-spam-level'] = function() + if not common['metric_score'] then + common['metric_score'] = task:get_metric_score('default') + end + local score = common['metric_score'][1] + if score < 1 then + return nil, {}, {} + end + if settings.routines['x-spam-level'].remove then + remove[settings.routines['x-spam-level'].header] = settings.routines['x-spam-level'].remove + end + add[settings.routines['x-spam-level'].header] = string.rep(settings.routines['x-spam-level'].char, score) + end + + routines['spam-header'] = function() + if not common['metric_action'] then + common['metric_action'] = task:get_metric_action('default') + end + if settings.routines['spam-header'].remove then + remove[settings.routines['spam-header'].header] = settings.routines['spam-header'].remove + end + local action = common['metric_action'] + if action ~= 'no action' and action ~= 'greylist' then + add[settings.routines['spam-header'].header] = settings.routines['spam-header'].value + end + end + + routines['x-virus'] = function() + if not common.symbols then + common.symbols = {} + end + if settings.routines['x-virus'].remove then + remove[settings.routines['x-virus'].header] = settings.routines['x-virus'].remove + end + local virii = {} + for _, sym in ipairs(settings.routines['x-virus'].symbols) do + if not (common.symbols[sym] == false) then + local s = task:get_symbol(sym) + if not s then + common.symbols[sym] = false + else + common.symbols[sym] = s + if (((s or E)[1] or E).options or E)[1] then + table.insert(virii, s[1].options[1]) + else + table.insert(virii, 'unknown') + end + end + end + end + if #virii > 0 then + add[settings.routines['x-virus'].header] = table.concat(virii, ',') + end + end + + routines['x-spam-status'] = function() + if not common['metric_score'] then + common['metric_score'] = task:get_metric_score('default') + end + if not common['metric_action'] then + common['metric_action'] = task:get_metric_action('default') + end + local score = common['metric_score'][1] + local action = common['metric_action'] + local is_spam + local spamstatus + if action ~= 'no action' and action ~= 'greylist' then + is_spam = 'Yes' + else + is_spam = 'No' + end + spamstatus = is_spam .. ', score=' .. string.format('%.2f', score) + if settings.routines['x-spam-status'].remove then + remove[settings.routines['x-spam-status'].header] = settings.routines['x-spam-status'].remove + end + add[settings.routines['x-spam-status'].header] = spamstatus + end + + routines['authentication-results'] = function() + local ar = require "auth_results" + + if settings.routines['authentication-results'].remove then + remove[settings.routines['authentication-results'].header] = + settings.routines['authentication-results'].remove + end + + local res = ar.gen_auth_results(task, + settings.routines['authentication-results']) + + if res then + add[settings.routines['authentication-results'].header] = res + end + end + + for _, n in ipairs(active_routines) do + local ok, err + if custom_routines[n] then + local to_add, to_remove, common_in + ok, err, to_add, to_remove, common_in = pcall(custom_routines[n], task, common) + if ok then + for k, v in pairs(to_add) do + add[k] = v + end + for k, v in pairs(to_remove) do + add[k] = v + end + for k, v in pairs(common_in) do + if type(v) == 'table' then + if not common[k] then + common[k] = {} + end + for kk, vv in pairs(v) do + common[k][kk] = vv + end + else + common[k] = v + end + end + end + else + ok, err = pcall(routines[n]) + end + if not ok then + logger.errx(task, 'call to %s failed: %s', n, err) + end + end + + if not next(add) then add = nil end + if not next(remove) then remove = nil end + if add or remove then + task:set_milter_reply({ + add_headers = add, + remove_headers = remove + }) + end +end + +local opts = rspamd_config:get_all_opt(N) or rspamd_config:get_all_opt('rmilter_headers') +if not opts then return end + +if type(opts['use']) == 'string' then + opts['use'] = {opts['use']} +elseif (type(opts['use']) == 'table' and not opts['use'][1]) then + logger.debugm(N, rspamd_config, 'no functions are enabled') + return +end +if type(opts['use']) ~= 'table' then + logger.errx(rspamd_config, 'unexpected type for "use" option: %s', type(opts['use'])) + return +end +if type(opts['custom']) == 'table' then + for k, v in pairs(opts['custom']) do + local f, err = load(v) + if not f then + logger.errx(rspamd_config, 'could not load "%s": %s', k, err) + else + custom_routines[k] = f() + end + end +end +local have_routine = {} +local function activate_routine(s) + if settings.routines[s] or custom_routines[s] then + have_routine[s] = true + table.insert(active_routines, s) + if (opts.routines and opts.routines[s]) then + for k, v in pairs(opts.routines[s]) do + settings.routines[s][k] = v + end + end + else + logger.errx(rspamd_config, 'routine "%s" does not exist', s) + end +end +if opts['extended_spam_headers'] then + activate_routine('x-spamd-result') + activate_routine('x-rspamd-server') + activate_routine('x-rspamd-queue-id') +end +if opts['skip_local'] then + settings.skip_local = true +end +if opts['skip_authenticated'] then + settings.skip_authenticated = true +end +for _, s in ipairs(opts['use']) do + if not have_routine[s] then + activate_routine(s) + end +end +if (#active_routines < 1) then + logger.errx(rspamd_config, 'no active routines') + return +end +logger.infox(rspamd_config, 'active routines [%s]', table.concat(active_routines, ',')) +rspamd_config:register_symbol({ + name = 'MILTER_HEADERS', + type = 'postfilter', + callback = milter_headers, + priority = 10 +}) diff --git a/data/conf/rmilter/rmilter.conf b/data/conf/rmilter/rmilter.conf deleted file mode 100644 index d957935c..00000000 --- a/data/conf/rmilter/rmilter.conf +++ /dev/null @@ -1,41 +0,0 @@ -bind_socket = inet:9900; -spamd { - servers = r:rspamd:11333; - connect_timeout = 1s; - results_timeout = 20s; - error_time = 10; - dead_time = 300; - maxerrors = 10; - reject_message = "Spam or virus message rejected due to high detection score"; - whitelist = 127.0.0.1/32, [::1]/128; - spamd_soft_fail = yes; - rspamd_metric = "default"; - extended_spam_headers = yes; - spam_header = "X-Spam-Flag"; - spam_header_value = "YES"; -}; -redis { - servers_grey = redis:6379; - servers_limits = redis:6379; - servers_id = redis:6379; - id_prefix = "message_id."; - grey_prefix = "grey."; - white_prefix = "white."; - connect_timeout = 1s; - error_time = 10; - dead_time = 300; - maxerrors = 10; -}; -tempdir = /tmp; -tempfiles_mode = 00600; -strict_auth = yes; -use_dcc = no; -limits { - enable = false; -}; -greylisting { - enable = false; -} -dkim { - enable = false; -};