Inquiry on Email Delivery Issues and TransientFailure Retry Configuration

The documentation has a pretty good search engine

@faithful-ostrich @yearning-hyena need to clear this issue. please give me a solutions ?

Did you purge all queues as per the documentation link?

yes

Is the problem that it is still sending or that it is receiving? Are you trying to stop inbound mail or the outbound queues? Sorry, I am not really clear on what problem you are trying to solve. A full copy of your current config would be helpful

Agreed, the concern is not clear.

During the email sending process, a connection issue has been encountered, preventing the successful delivery of the email. The system logs highlight a “TransientFailure.”

At what point does the system classify the email as bounced? Is there a configuration option to specify the maximum number of retry attempts? I assume that after three unsuccessful attempts with a TransientFailure, the system should designate the email as bounced.

Messages expire based on age, not number of attempts.

local kumo = require ‘kumo’
local shaping = require ‘policy-extras.shaping’
local redis = require ‘redis’

local sources = require ‘policy-extras.sources’
sources:setup { ‘/opt/kumomta/etc/policy/sources.toml’ }
local queue_module = require ‘policy-extras.queue’
local queue_helper = queue_module:setup ({ ‘/opt/kumomta/etc/policy/queues.toml’ })

local client = kumo.amqp.build_client ‘amqp://mqadmin:Kpd.xadasdpk23sdasrwsCcd@10.0.0.1:5672’
local conn = redis.open { node = ‘redis://10.0.0.1/’ }
local rabitmqqueue = ‘transaction_email_events’
local sqlite = require ‘sqlite’
local db = sqlite.open ‘/opt/psql/mailercloud.db’

kumo.on(‘init’, function()
kumo.set_diagnostic_log_filter ‘kumod=debug’
kumo.start_esmtp_listener {
listen = ‘0:25’,
hostname = ‘kumo.domain.com’,
relay_hosts = {‘127.0.0.1’,‘10.0.0.1’},

}

kumo.start_esmtp_listener {
listen = ‘0.0.0.0:587’,
hostname = ‘kumo.domain.com’,
relay_hosts = { ‘10.0.0.1’ },
tls_certificate = ‘/opt/kumomta/etc/ssl/kumodomain-cert.pem’,
tls_private_key = ‘/opt/kumomta/etc/ssl/kumodomain-key.pem’,
max_recipients_per_message = 2
}
kumo.start_http_listener {
listen = ‘127.0.0.1:8000’,
hostname = ‘kumomta.domain.com’,
tls_certificate = ‘’,
tls_private_key = ‘/etc/letsencrypt/live/kumomta.domain.com/privkey.pem’,
use_tls = false
}

kumo.define_spool {
name = ‘data’,
path = ‘/var/spool/kumomta/data’,
}

kumo.define_spool {
name = ‘meta’,
path = ‘/var/spool/kumomta/meta’,
}

kumo.configure_local_logs {
log_dir = ‘/var/log/kumomta’,
headers = { ‘Subject’, ‘X-Tracking-Id’ },
meta = { ‘received_from’,‘tenant’,‘received’,‘domain’ },
}

kumo.configure_bounce_classifier {
files = {
‘/opt/kumomta/share/bounce_classifier/iana.toml’,
},
}

kumo.configure_log_hook {
name = ‘amqp’,
headers = { ‘Subject’, ‘X-Tracking-Id’ },
meta = { ‘received_from’,‘tenant’,‘received’,‘domain’,‘cid’,‘pool_id’,‘server_id’ ,‘email_domain’},
}

end)

kumo.on(‘make.amqp’, function(domain, tenant, campaign)
local connection = {}
function connection:send(message)
local confirm = client:publish {
routing_key = rabitmqqueue,
payload = message:get_data(),
exchange = ‘transaction_email_events_exchange’
}
local result = confirm:wait()

            if result.status == 'Ack' or result.status == 'NotRequested' then
                    return result.status
            end

            kumo.reject(500, kumo.json_encode(result))
    end

    return connection

end)

kumo.on(‘get_queue_config’, function(domain, tenant, campaign, routing_domain)
print (“enter get_queue_config”)

    if domain == 'amqp' then
            return kumo.make_queue_config {
                   max_age = '5 minutes',

                    protocol = {
                            custom_lua = {
                                    constructor = 'make.amqp',
                            },
                    },
            }
    end
    return kumo.make_queue_config {max_age = '5 minutes'}

end)

kumo.on(‘should_enqueue_log_record’, function(msg, hook_name)
if hook_name ~= ‘amqp’ then
return
end
local log_record = msg:get_meta ‘log_record’

    if log_record.reception_protocol == 'LogRecord' then
            return false
    end

    msg:set_meta('queue', 'amqp')
    return true

end)

kumo.on(‘http_message_generated’, function(msg)
local domain = msg:from_header().domain
local user = msg:get_first_named_header_value(“authz_id”)
local cid = “”
local poolid = “”
local pool = “”
local serverid = “”
local AUTH_DETAILS = conn:query(‘GET’, ‘trans_authdetails’)
local details = kumo.json_parse(AUTH_DETAILS)
if details[user] then
cid = details[user].cid
end
if details[user] then
serverid = details[user].server_id
end
if details[user] and details[user].valid_domain and details[user].valid_domain[domain] then
if details[user].valid_domain[domain].smtp_pool_id then
poolid = details[user].valid_domain[domain].smtp_pool_id
end
if details[user].valid_domain[domain].smtp_pool then
pool = details[user].valid_domain[domain].smtp_pool
end
end

local signer = kumo.dkim.rsa_sha256_signer {
domain = ‘domain.com’,
selector = ‘kmdk’,
headers = { ‘From’, ‘To’, ‘Subject’ },
key = ‘/opt/kumomta/etc/dkim/domain.com/kumo1.pem’,
}
msg:dkim_sign(signer)
print(“domain”)
print(‘/opt/kumomta/etc/dkim/’ .. string.gsub(msg:from_header().domain,‘kumo.’,‘’) .. ‘/kumo1.pem’)
local double_signer = kumo.dkim.rsa_sha256_signer {
domain = msg:from_header().domain,
selector = ‘kmdk’,
headers = { ‘From’, ‘To’, ‘Subject’ },
key = ‘/opt/kumomta/etc/dkim/’ .. string.gsub(msg:from_header().domain,‘kumo.’,‘’) .. ‘/kumo1.pem’,
}
msg:dkim_sign(double_signer)

if pool ~= “” then
msg:set_meta(‘tenant’, pool)
end
if poolid ~= “” then
msg:set_meta(‘pool_id’, poolid)
end

if serverid ~= “” then
msg:set_meta(‘server_id’, serverid)
end

msg:set_meta(‘cid’, cid)
msg:set_meta(‘domain’, msg:from_header().domain)
msg:set_meta(‘email_domain’, extractDomain(msg:recipient().email))
local ipAddress = msg:get_first_named_header_value(“received_from”)
msg:set_meta(‘received_from’, ipAddress)
queue_helper:apply(msg)

    local is_reinjected = msg:get_first_named_header_value("is_reinjected")
    if is_reinjected ~= "yes" then
            print("Processing the reinjected message")
    end

end)

kumo.on(‘smtp_server_message_received’, function(msg)

local AUTH_DETAILS = conn:query(‘GET’, ‘trans_authdetails’)

print(AUTH_DETAILS)
print(msg:get_meta(‘authz_id’))

local user = msg:get_meta(‘authz_id’)
local isAllow = true
local ipAddress = extractIPAddress(msg:get_meta(‘received_from’))
–local checkPermission = checkEmailAllowed(AUTH_DETAILS,user,msg:recipient().email)
local permission = allowPermissionToSend(AUTH_DETAILS,user ,msg:from_header().domain,ipAddress,msg:recipient().email)
if permission ~= “success” then

        local myData = {
                   id = msg:id(),
                   domain = msg:from_header().domain,
                   user = msg:get_meta('authz_id'),
                     reason = permission,
                        
                              
                            }

    addLog('kumomta-arun-queue', kumo.json_encode(myData))
    msg:set_meta('queue', 'null')
    isAllow = false
    kumo.reject(400, permission)

end

queue_helper:apply(msg)

msg:append_header(“X-Tracking-Id”, msg:id())
msg:prepend_header(“received_from”, msg:get_meta(‘received_from’))
msg:prepend_header(“authz_id”, msg:get_meta(‘authz_id’))

local trlink = getTrackingLink(AUTH_DETAILS,user ,msg:from_header().domain)
local unsubscribeLinkUrl = getUnsubscribeLink(trlink, msg:id())

msg:append_header(“List-Unsubscribe”, unsubscribeLinkUrl )
msg:append_header(“List-Unsubscribe-Post”, “List-Unsubscribe=One-Click”)

local is_reinjected = msg:get_first_named_header_value(“is_reinjected”)
if is_reinjected ~= “yes” and isAllow == true then
print (“Received a new message to process”)
local client = kumo.http.build_client {}
local msg_body = msg:get_data()
msg:prepend_header(“is_reinjected”,“yes”)
local htmllog = {
id = msg:id(),
html = msg_body,
}
addLog(‘transactional-html’, msg_body)

   print("trlink")
   print(trlink)
   if trlink ~= '' then
                msg_body = replaceClickLink(msg_body ,trlink, msg:id())
                 msg_body = addOpenLink(msg_body ,trlink, msg:id())
                 msg_body = addUnsubscribeLink(msg_body ,trlink, msg:id())
             
                
         end

print(msg_body)

    local msg_payload = kumo.json_encode {
            envelope_sender = msg:sender().email,
            content = msg_body,
            recipients = {
                    { email = msg:recipient().email },
            },
    }

    print ("NEW PAYLOAD: " .. msg_payload)
    local request = client:post 'http://127.0.0.1:8000/api/inject/v1'
    request:header('Content-Type', 'application/json')
    request:body(msg_payload)

    local response = request:send()
    print ("REsponse")
    print (response)
    if response:status_is_success() then
            print ("successful reinjection, deleting original")
            msg:set_meta('queue', 'null')
            return
    end

    local disposition = string.format(
    '%d %s %s',
    response:status_code(),
    response:status_reason(),
    response:text()
    )
    kumo.reject(400, disposition)

end

end)

local AUTH_CONFIG = kumo.json_load ‘/opt/kumomta/etc/auth_file.json’

kumo.on(‘smtp_server_auth_plain’, function(authz, authc, password)
local AUTH_DETAILS = conn:query(‘GET’, ‘trans_authdetails’)
details = kumo.json_parse(AUTH_DETAILS)
print(“auth details”)
print(details)
if password == ‘’ then
return false
end
return details[authc].password == password
end)

kumo.on(‘get_egress_path_config’,
shaping:setup { ‘/opt/kumomta/etc/shaping.json’ }
)