Sieve scripts don't work in 0.16.3

Issue Description

I’ve followed the upgrade guide carefully and recreated all missed configuration in the loop. I’ve many redirect rules and sieves script but they don’t seem to work anymore.

Redirect are done in the RCPT_TO stage and they work (I can see in the log that they are handled). However, I couldn’t get the sieve script to work as they used to do before 0.16

The sieve script are listed in the account interface “Sieve Script” section, as “a.sieve” (the name they had before migration). They contains:

require ["variables", "envelope", "regex", "fileinto", "mailboxid", "mailbox", "copy", "subaddress"];

if envelope :regex "to" "^([^+]+)\\+([^+]+)@(.+)$" {
   set :upperfirst "folder" "${2}";
   fileinto :copy :create "Alias";
   fileinto :create "Alias/${folder}";
   redirect "[email protected]";
   stop;
}

Its “Active” checkbox is on

I’ve tried modifying it and re-saving it, but it doesn’t work either.

The mail are delivered to the expected mailbox but the script is not run (no mention of the script in the log, even in debug log mode). The same script used to work in 0.15.5

Expected Behavior

The user sieve scripts should execute

Actual Behavior

Either the script isn’t executing, or there’s an error but no trace in the logs.

Reproduction Steps

  1. Set a redirect rule like this: IF is_local_domain(rcpt_domain) & matches('^fwd\.([^.]+)@(.+)$', rcpt), THEN 'user+' + $1 + '@' + $2
  2. Try to use the provided sieve script above
  3. Send yourself a mail to [email protected]

Relevant Log Output

2026-05-09T17:52:43Z DEBUG SMTP connection started (smtp.connection-start) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaInboundThrottle with id iqbxxgiwabab", key = "match", result = "Integer(1)"
2026-05-09T17:52:43Z TRACE Write batch operation (store.data-write) elapsed = 15ms, total = 2
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaInboundSession with id singleton", key = "transferLimit", result = "Integer(262144000)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaInboundSession with id singleton", key = "maxDuration", result = "Integer(600000)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaInboundSession with id singleton", key = "timeout", result = "Integer(300000)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "SenderAuth with id singleton", key = "spfEhloVerify", result = "Constant(Disable)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "SenderAuth with id singleton", key = "spfFromVerify", result = "Constant(Disable)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "SenderAuth with id singleton", key = "reverseIpVerify", result = "Constant(Disable)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaStageEhlo with id singleton", key = "require", result = "Integer(1)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaStageEhlo with id singleton", key = "rejectNonFqdn", result = "Integer(0)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaStageAuth with id singleton", key = "require", result = "Integer(1)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaStageAuth with id singleton", key = "maxFailures", result = "Integer(3)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaStageAuth with id singleton", key = "waitOnFail", result = "Integer(5000)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaExtensions with id singleton", key = "expn", result = "Integer(0)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaExtensions with id singleton", key = "vrfy", result = "Integer(0)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaStageConnect with id singleton", key = "script", result = "Integer(0)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaStageConnect with id singleton", key = "script", result = ""
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaStageConnect with id singleton", key = "hostname", result = "String(Borrowed("mail.a.com"))"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaStageConnect with id singleton", key = "smtpGreeting", result = "String(Owned("mail.a.com Stewart ESMTP at your service"))"
2026-05-09T17:52:43Z TRACE Raw SMTP output sent (smtp.raw-output) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, size = 47, contents = "220 mail.a.com Stewart ESMTP at your service\r\n"
2026-05-09T17:52:43Z TRACE Raw SMTP input received (smtp.raw-input) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, size = 20, contents = "EHLO gaia.localnet\r\n"
2026-05-09T17:52:43Z INFO SMTP EHLO command (smtp.ehlo) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, domain = "gaia.localnet"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaStageEhlo with id singleton", key = "script", result = "Integer(0)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaStageEhlo with id singleton", key = "script", result = ""
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaExtensions with id singleton", key = "pipelining", result = "Integer(1)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaExtensions with id singleton", key = "chunking", result = "Integer(1)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaExtensions with id singleton", key = "expn", result = "Integer(0)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaExtensions with id singleton", key = "vrfy", result = "Integer(0)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaExtensions with id singleton", key = "requireTls", result = "Integer(1)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaExtensions with id singleton", key = "dsn", result = "Integer(0)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaStageAuth with id singleton", key = "saslMechanisms", result = "Array([Constant(Plain), Constant(Login), Constant(Oauthbearer), Constant(Xoauth2)])"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaExtensions with id singleton", key = "futureRelease", result = "Integer(0)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaExtensions with id singleton", key = "futureRelease", result = ""
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaExtensions with id singleton", key = "deliverBy", result = "Integer(0)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaExtensions with id singleton", key = "deliverBy", result = ""
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaExtensions with id singleton", key = "mtPriority", result = "Integer(0)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaExtensions with id singleton", key = "mtPriority", result = ""
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaStageData with id singleton", key = "maxMessageSize", result = "Integer(104857600)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaExtensions with id singleton", key = "noSoliciting", result = "String(Borrowed(""))"
2026-05-09T17:52:43Z TRACE Raw SMTP output sent (smtp.raw-output) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, size = 232, contents = "250-mail.a.com you had me at EHLO\r\n250-SMTPUTF8\r\n250-SIZE 104857600\r\n250-REQUIRETLS\r\n250-PIPELINING\r\n250-NO-SOLICITING\r\n250-ENHANCEDSTATUSCODES\r\n250-CHUNKING\r\n250-BINARYMIME\r\n250-AUTH PLAIN LOGIN XOAUTH2 OAUTHBEARER\r\n250 8BITMIME\r\n"
2026-05-09T17:52:43Z TRACE Raw SMTP input received (smtp.raw-input) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, size = 45, contents = "AUTH PLAIN AGN5cmlsQGtnaS5ieQBiZW5zM3BzeA==\r\n"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaStageAuth with id singleton", key = "saslMechanisms", result = "Array([Constant(Plain), Constant(Login), Constant(Oauthbearer), Constant(Xoauth2)])"
2026-05-09T17:52:43Z DEBUG Cache hit (store.cache-hit) key = "a.com", collection = "domainName"
2026-05-09T17:52:43Z DEBUG Cache hit (store.cache-hit) key = 1, collection = "domainId"
2026-05-09T17:52:43Z DEBUG Cache hit (store.cache-hit) key = "user", domain = 1, collection = "email"
2026-05-09T17:52:43Z DEBUG Cache hit (store.cache-hit) key = 101, collection = "accessToken"
2026-05-09T17:52:43Z INFO Authentication successful (auth.success) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, accountName = "[email protected]", accountId = 101
2026-05-09T17:52:43Z DEBUG Cache hit (store.cache-hit) key = 101, collection = "account"
2026-05-09T17:52:43Z DEBUG Cache hit (store.cache-hit) key = 1, collection = "domainId"
2026-05-09T17:52:43Z DEBUG Cache hit (store.cache-hit) key = 1, collection = "domainId"
2026-05-09T17:52:43Z DEBUG Cache hit (store.cache-hit) key = 1, collection = "domainId"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaExtensions with id singleton", key = "expn", result = "Integer(1)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaExtensions with id singleton", key = "vrfy", result = "Integer(1)"
2026-05-09T17:52:43Z TRACE Raw SMTP output sent (smtp.raw-output) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, size = 37, contents = "235 2.7.0 Authentication succeeded.\r\n"
2026-05-09T17:52:43Z TRACE Raw SMTP input received (smtp.raw-input) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, size = 26, contents = "MAIL FROM:<[email protected]>\r\n"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaStageMail with id singleton", key = "isSenderAllowed", result = "Integer(1)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaStageMail with id singleton", key = "script", result = "Integer(0)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaStageMail with id singleton", key = "script", result = ""
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaStageMail with id singleton", key = "rewrite", result = "Integer(0)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaStageMail with id singleton", key = "rewrite", result = ""
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaStageAuth with id singleton", key = "mustMatchSender", result = "Integer(1)"
2026-05-09T17:52:43Z INFO SMTP MAIL FROM command (smtp.mail-from) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, from = "[email protected]"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaStageRcpt with id singleton", key = "maxFailures", result = "Integer(5)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaStageRcpt with id singleton", key = "waitOnFail", result = "Integer(5000)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaStageRcpt with id singleton", key = "maxRecipients", result = "Integer(100)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaExtensions with id singleton", key = "dsn", result = "Integer(1)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaStageData with id singleton", key = "maxMessageSize", result = "Integer(104857600)"
2026-05-09T17:52:43Z TRACE Raw SMTP output sent (smtp.raw-output) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, size = 14, contents = "250 2.1.0 OK\r\n"
2026-05-09T17:52:43Z TRACE Raw SMTP input received (smtp.raw-input) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, size = 27, contents = "RCPT TO:<[email protected]>\r\n"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaStageRcpt with id singleton", key = "script", result = "Integer(0)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaStageRcpt with id singleton", key = "script", result = ""
2026-05-09T17:52:43Z DEBUG Cache hit (store.cache-hit) key = "b.com", collection = "domainName"
2026-05-09T17:52:43Z DEBUG Cache hit (store.cache-hit) key = 2, collection = "domainId"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaStageRcpt with id singleton", key = "rewrite", result = "String(Owned("[email protected]"))"
2026-05-09T17:52:43Z DEBUG RCPT TO address rewritten (smtp.rcpt-to-rewritten) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, details = "[email protected]", to = "[email protected]"
2026-05-09T17:52:43Z DEBUG Cache hit (store.cache-hit) key = "b.com", collection = "domainName"
2026-05-09T17:52:43Z DEBUG Cache hit (store.cache-hit) key = 2, collection = "domainId"
2026-05-09T17:52:43Z DEBUG Cache hit (store.cache-hit) key = "user", domain = 2, collection = "email"
2026-05-09T17:52:43Z DEBUG Cache hit (store.cache-hit) key = 95, collection = "account"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaInboundThrottle with id iqbxxgjaabqb", key = "match", result = "Integer(1)"
2026-05-09T17:52:43Z TRACE Write batch operation (store.data-write) elapsed = 6ms, total = 2
2026-05-09T17:52:43Z INFO SMTP RCPT TO command (smtp.rcpt-to) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, to = "[email protected]"
2026-05-09T17:52:43Z TRACE Raw SMTP output sent (smtp.raw-output) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, size = 14, contents = "250 2.1.5 OK\r\n"
2026-05-09T17:52:43Z TRACE Raw SMTP input received (smtp.raw-input) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, size = 6, contents = "DATA\r\n"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaStageData with id singleton", key = "maxMessages", result = "Integer(10)"
2026-05-09T17:52:43Z TRACE Raw SMTP output sent (smtp.raw-output) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, size = 46, contents = "354 Start mail input; end with <CRLF>.<CRLF>\r\n"
2026-05-09T17:52:43Z TRACE Raw SMTP input received (smtp.raw-input) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, size = 278, contents = "From: Cyril <[email protected]>\r\nTo: [email protected]\r\nSubject: Test\r\nDate: Sat, 09 May 2026 19:52:43 +0200\r\nMessage-ID: <[email protected]>\r\nMIME-Version: 1.0\r\nContent-Transfer-Encoding: 7Bit\r\nContent-Type: text/plain; charset="utf-8"\r\n\r\nTest\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n.\r\n"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaStageData with id singleton", key = "maxReceivedHeaders", result = "Integer(50)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "SenderAuth with id singleton", key = "dkimVerify", result = "Constant(Relaxed)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "SenderAuth with id singleton", key = "dmarcVerify", result = "Constant(Disable)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "DkimReportSettings with id singleton", key = "sendFrequency", result = "Array([Integer(1), Integer(86400000)])"
2026-05-09T17:52:43Z INFO DKIM verification failed (smtp.dkim-fail) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, strict = false, result = [], elapsed = 0ms
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "SenderAuth with id singleton", key = "arcVerify", result = "Constant(Disable)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaStageData with id singleton", key = "addReceivedHeader", result = "Integer(0)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaStageData with id singleton", key = "addAuthResultsHeader", result = "Integer(0)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaStageData with id singleton", key = "enableSpamFilter", result = "Integer(0)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaStageData with id singleton", key = "script", result = "Integer(0)"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaStageData with id singleton", key = "script", result = ""
2026-05-09T17:52:43Z DEBUG Cache hit (store.cache-hit) key = "b.com", collection = "domainName"
2026-05-09T17:52:43Z DEBUG Cache hit (store.cache-hit) key = 2, collection = "domainId"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaOutboundStrategy with id singleton", key = "schedule", result = "String(Borrowed("local"))"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "MtaStageData with id singleton", key = "addReturnPathHeader", result = "Integer(0)"
2026-05-09T17:52:43Z DEBUG Cache hit (store.cache-hit) key = "a.com", collection = "domainName"
2026-05-09T17:52:43Z DEBUG Cache hit (store.cache-hit) key = 1, collection = "domainId"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, id = "SenderAuth with id singleton", key = "dkimSignDomain", result = "String(Borrowed("a.com"))"
2026-05-09T17:52:43Z DEBUG Cache hit (store.cache-hit) key = "a.com", collection = "domainName"
2026-05-09T17:52:43Z DEBUG Cache hit (store.cache-hit) key = 1, collection = "domainId"
2026-05-09T17:52:43Z DEBUG Cache hit (store.cache-hit) key = 1, collection = "dkimSigners"
2026-05-09T17:52:43Z TRACE Write batch operation (store.data-write) elapsed = 4ms, total = 1
2026-05-09T17:52:43Z TRACE Blob write operation (store.blob-write) key = base64:gvfOCtQF35ZeLW1VAWoW3wfFolq/WAiUjxsZRdvJCvI=, elapsed = 0ms, size = 898
2026-05-09T17:52:43Z INFO Queued message submission for delivery (queue.authenticated-message-queued) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, queueId = 306329238508670976, from = "[email protected]", to = ["[email protected]"], size = 1100, nextRetry = 2026-05-09T17:52:43Z, nextDsn = 2026-05-10T17:52:43Z, expires = 2026-05-12T17:52:43Z
2026-05-09T17:52:43Z TRACE Write batch operation (store.data-write) elapsed = 7ms, total = 5
2026-05-09T17:52:43Z TRACE Raw SMTP output sent (smtp.raw-output) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, size = 51, contents = "250 2.0.0 Message queued with id 4404cd1c5a01000.\r\n"
2026-05-09T17:52:43Z TRACE Data store iteration operation (store.data-iterate) elapsed = 0ms
2026-05-09T17:52:43Z TRACE Write batch operation (store.data-write) elapsed = 7ms, total = 2
2026-05-09T17:52:43Z INFO Delivery attempt started (delivery.attempt-start) queueId = 306329238508670976, queueName = "local", from = "[email protected]", to = ["[email protected]"], size = 1100, total = 1
2026-05-09T17:52:43Z DEBUG Cache hit (store.cache-hit) key = "b.com", collection = "domainName"
2026-05-09T17:52:43Z DEBUG Cache hit (store.cache-hit) key = 2, collection = "domainId"
2026-05-09T17:52:43Z TRACE Expression evaluation result (eval.result) queueId = 306329238508670976, queueName = "local", from = "[email protected]", to = ["[email protected]"], size = 1100, total = 1, id = "MtaOutboundStrategy with id singleton", key = "route", result = "String(Borrowed("local"))"
2026-05-09T17:52:43Z INFO New delivery attempt for domain (delivery.domain-delivery-start) queueId = 306329238508670976, queueName = "local", from = "[email protected]", to = ["[email protected]"], size = 1100, total = 1, domain = "b.com"
2026-05-09T17:52:43Z TRACE Blob read operation (store.blob-read) key = base64:gvfOCtQF35ZeLW1VAWoW3wfFolq/WAiUjxsZRdvJCvI=, elapsed = 0ms, size = 898
2026-05-09T17:52:43Z DEBUG Cache hit (store.cache-hit) key = "b.com", collection = "domainName"
2026-05-09T17:52:43Z DEBUG Cache hit (store.cache-hit) key = 2, collection = "domainId"
2026-05-09T17:52:43Z DEBUG Cache hit (store.cache-hit) key = "user", domain = 2, collection = "email"
2026-05-09T17:52:43Z DEBUG Cache hit (store.cache-hit) key = 95, collection = "accessToken"
2026-05-09T17:52:43Z TRACE Blob read operation (store.blob-read) key = base64:VZMFv39U0j2h7CgsbC8q8R4cQRjMSCzQUh/cSXytmS4=, elapsed = 0ms, size = 577
2026-05-09T17:52:43Z TRACE Data store iteration operation (store.data-iterate) elapsed = 0ms
2026-05-09T17:52:43Z DEBUG Cache update (store.cache-update) accountId = 95, collection = "email", changeId = 1462, details = [1, 0], total = [2887, 135], elapsed = 0ms
2026-05-09T17:52:43Z DEBUG Cache hit (store.cache-hit) key = 95, collection = "account"
2026-05-09T17:52:43Z DEBUG Cache hit (store.cache-hit) key = 95, collection = "account"
2026-05-09T17:52:43Z TRACE Data store iteration operation (store.data-iterate) elapsed = 0ms
2026-05-09T17:52:43Z DEBUG Cache hit (store.cache-hit) key = 2, collection = "domainId"
2026-05-09T17:52:43Z TRACE Raw SMTP input received (smtp.raw-input) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, size = 6, contents = "QUIT\r\n"
2026-05-09T17:52:43Z DEBUG SMTP QUIT command (smtp.quit) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846
2026-05-09T17:52:43Z TRACE Raw SMTP output sent (smtp.raw-output) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, size = 16, contents = "221 2.0.0 Bye.\r\n"
2026-05-09T17:52:43Z DEBUG SMTP connection ended (smtp.connection-end) listenerId = "submissions", localPort = 465, remoteIp = 1.1.1.1, remotePort = 49846, elapsed = 177ms
2026-05-09T17:52:43Z TRACE Write batch operation (store.data-write) elapsed = 15ms, total = 6
2026-05-09T17:52:43Z TRACE Write batch operation (store.data-write) elapsed = 8ms, total = 14
2026-05-09T17:52:43Z INFO Message ingested (message-ingest.ham) queueId = 306329238508670976, queueName = "local", from = "[email protected]", to = ["[email protected]"], size = 1100, total = 1, accountId = 95, documentId = 2981, mailboxId = [0], blobId = "82f7ce0ad405df965e2d6d55016a16df07c5a25abf5808948f1b1945dbc90af2", changeId = 1463, messageId = "[email protected]", size = 1100, elapsed = 23ms
2026-05-09T17:52:43Z INFO DSN success notification (delivery.dsn-success) queueId = 306329238508670976, queueName = "local", from = "[email protected]", to = ["[email protected]"], size = 1100, total = 1, to = "[email protected]", hostname = "localhost", code = 250, details = "OK"
2026-05-09T17:52:43Z INFO Delivery completed (delivery.completed) queueId = 306329238508670976, queueName = "local", from = "[email protected]", to = ["[email protected]"], size = 1100, total = 1, elapsed = 0ms
2026-05-09T17:52:43Z TRACE Data store iteration operation (store.data-iterate) elapsed = 0ms
2026-05-09T17:52:43Z DEBUG Task acquired from queue (task-manager.task-acquired) total = 1, details = 1
2026-05-09T17:52:43Z TRACE Write batch operation (store.data-write) elapsed = 6ms, total = 3
2026-05-09T17:52:43Z INFO Delivery attempt ended (delivery.attempt-end) queueId = 306329238508670976, queueName = "local", from = "[email protected]", to = ["[email protected]"], size = 1100, total = 1, elapsed = 31ms
2026-05-09T17:52:43Z TRACE Write batch operation (store.data-write) elapsed = 15ms, total = 2
2026-05-09T17:52:43Z TRACE Blob read operation (store.blob-read) key = base64:gvfOCtQF35ZeLW1VAWoW3wfFolq/WAiUjxsZRdvJCvI=, elapsed = 0ms, size = 898
2026-05-09T17:52:43Z TRACE Write batch operation (store.data-write) elapsed = 16ms, total = 1
2026-05-09T17:52:43Z TRACE Data store iteration operation (store.data-iterate) elapsed = 0ms
2026-05-09T17:52:43Z TRACE Write batch operation (store.data-write) elapsed = 8ms, total = 2
2026-05-09T17:52:43Z TRACE Write batch operation (store.data-write) elapsed = 8ms, total = 1
2026-05-09T17:52:43Z TRACE Data store iteration operation (store.data-iterate) elapsed = 0ms

Stalwart Version

v0.16.x

Installation Method

Binary (Linux)

Database Backend

PostgreSQL

Blob Storage

Filesystem

Search Engine

Internal

Directory Backend

Internal

Additional Context

Nothing special for this installation. The HTTP server is under nginx proxy (but obviously this things works)

I have reviewed the documentation and FAQ and confirm that my issue is NOT addressed there.

on

I have searched this support forum (open and closed topics) and confirm this is not a duplicate.

on

I understand that topics in this category are triaged by a bot first but a human reply will follow up. If I’d prefer a human-only reply, I’ll add the no-ai tag to my topic.

on

Based on the log and the issue description, there’s a clear and important clue: Sieve scripts are not being executed during local delivery. Looking at the log, the message goes through the local queue and is ingested directly as a ham message (message-ingest.ham) with no mention of any Sieve script evaluation between the delivery attempt and ingestion.

This is almost certainly a pipeline configuration issue: the Sieve script execution step for local delivery is not wired up in the current configuration. Here are the key things to check:


1. Check that the Delivery Sieve pipeline is configured

In current Stalwart, Sieve scripts for local delivery (the per-user scripts managed via ManageSieve/JMAP for Sieve) are executed as part of the local delivery pipeline, not the SMTP DATA stage. After the migration from 0.15, this pipeline configuration may not have been carried over automatically.

In the WebUI, go to Settings → SMTP → Inbound → Data (or the equivalent pipeline/filter section) and verify that the Sieve filter or local delivery script step is enabled. The fact that the log shows:

id = "MtaStageData with id singleton", key = "script", result = ""

…confirms no DATA-stage script is configured. But more importantly, look for a local delivery or message ingestion stage where user Sieve scripts should be invoked.

2. Per-user Sieve scripts run at ingestion, not at the SMTP DATA stage

The per-user scripts (those visible in the account’s “Sieve Script” section) are executed when the message is ingested into the mailbox, not during SMTP. If the ingestion pipeline doesn’t have Sieve evaluation enabled, the scripts are silently skipped — which matches exactly what you’re seeing (message-ingest.ham with no Sieve log entries).

3. Check the upgrade guide for pipeline changes

The migration from 0.15 to 0.16 involved significant restructuring. Please re-read the upgrade guide carefully, specifically any section about Sieve/filtering pipeline changes, to ensure the local delivery Sieve execution step is present in your configuration.


In summary: the scripts and the “Active” checkbox are fine — the problem is that the Sieve execution step is missing from your local delivery/ingestion pipeline configuration. Re-check your pipeline settings in the WebUI for the local delivery stage and ensure per-user Sieve evaluation is enabled there.

This isn’t something the bot can resolve with full certainty from the docs alone — a staff member or experienced community member who has gone through the 0.15→0.16 migration should be able to point to the exact setting name. Please tag this thread for human follow-up.

This is an automated reply from the Stalwart Help Bot. Other community members may follow up if this answer is incomplete or wrong. If you found it useful, mention @helpbot in any reply to ask follow-up questions and the bot will respond again.

@helpbot While your answer seem logical, it doesn’t apply to the current software. There’s no option for “ingestion”.

I’ve tried to set a script in the DATA stage, but it’s a system script, not a user script (so it doesn’t work: I get a warning with script not found). Also, even if it worked, the name of the user script is user defined, not something I can set in stone in the settings.

Tried to create a tracer with only Sieve related events, and it’s completely empty (the file is created but it’s empty, so for me, it’s not being run).

This is what I’ve also tried:

  1. Using sieve-connect tool, connected via ManageSieve protocol on an account and listed the sieves script (it’s listing both the system “User script” I’ve set for template, as active and the account’s script)
  2. Tried to activate the account script => (activation worked, but the issue remain, not working)
  3. Deactivated the account’s script, downloaded, deleted and uploaded, activated again => still not working

This is very painful for me, since some scripts are used to forward the aliased mails to some external mailbox and while it’s being fixed, it’s not working (mail aren’t lost, but they are on a “local” account that’s not opened usually).

Are you trying to use a User script or a System script? If it is a System script is needs to be created in the WebUI and then referenced from one of the SMTP stages.
If it is a user script, you need to upload it using a ManageSieve or JMAP for Sieve client.

I have tried to reproduce but the mail cannot be delivered. It seems this code lacks rewrite to the correct account, it fails at local delivery mailbox cannot be found:

// Obtain external directory, if configured
let directory = self
.get_directory_for_cached_domain(&domain)
.filter(|directory| directory.can_lookup_recipients());
if let Some(directory) = directory {
let address = if local_part.as_ref() == local_part_orig {
Cow::Borrowed(rcpt)
} else {
Cow::Owned(format!(“{local_part}@{domain_part}”))
};
match directory.recipient(address.as_ref()).await? {
Recipient::Account(account) => {
Box::pin(self.synchronize_account(account)).await?;
return Ok(RcptResolution::Accept);
}
Recipient::Group(group) => {
Box::pin(self.synchronize_group(group)).await?;
return Ok(RcptResolution::Accept);
}
Recipient::Invalid => {}
}
}

Because with registry there is a test like this:

return if local_part.as_ref() == local_part_orig {
Ok(RcptResolution::Accept)
} else {
Ok(RcptResolution::Rewrite(format!(
“{local_part}@{domain_part}”
)))
};

This might be related to your issue.

Can you try the rewrite fonction from a sieve script called at rcpt stage?

@X-Ryl669 Do you have more than one script enabled? If so try disabeling the other script(s) and check if your script ist executed then.

They are account’s script (run by the user interpreter). I’m not using system script for now.

I’ve tried removing them so that there’s only one left, but no change. So I made another script b.sieve that I activated via ManageSieve containing:

require ["variables", "envelope", "regex", "fileinto", "mailboxid", "mailbox", "copy", "subaddress", "enotify"];

notify :message "An email was not processed." "mailto:[email protected]";
stop;

And I do get a message in the other mail, so the script is actually running, but the initial script doesn’t perform what it used to do.

Let’s now figure out what’s wrong with the initial script:

require ["variables", "envelope", "regex", "fileinto", "mailboxid", "mailbox", "copy", "subaddress"];

if envelope :user :is "to" "postmaster" {
   fileinto :create "Admin";
   stop;
}

if envelope :regex "to" "^([^+]+)\\+([^+]+)@(.+)$" {
   set :upperfirst "folder" "${2}";
   fileinto :copy :create "Alias";
   fileinto :create "Alias/${folder}";
   stop; 
}

Typically, the previous (0.15.x) behavior was when sending a mail to “[email protected]”, the address was rewritten in RCPT_TO stage to “[email protected]”, then the user’s script will match the regex and create a folder “Alias/Something”, store the mail in both Alias and Alias/Something folder.

This seems not to work in 0.16.4 anymore

How can I capture the envelope’s to variable so I can notify myself the value (or, at least have it output in the log?). I think the to variable is likely “[email protected]”, so the regex doesn’t match anymore.

@dvex1091 : I was able to get a simple script to run, and I can confirm that have 2 scripts in the account works, I just need to activate the one I want.

@DorianCoding : I’ll try the system script at RCPT_TO stage and let you know.

I’ve just tried with a system script in RCPT_TO stage and it worked the same, the rewrite worked (I’ve received the mail in the user’s account), but the user script didn’t.

Ok, I’ve found the culprit.

In the sieve script, they had:

if envelope :regex "to" "^([^+]+)\\+([^+]+)@(.+)$" {

The regex should match [email protected] but the regex is wrong, the double \\+ doesn’t match the single +. I’ve replaced the regex to \+ and it worked.

I don’t understand why such script used to work with 0.15.x.

Also, if it’s possible, it would be a good idea to add a trace in the log saying that the user script “a.sieve” has run

Well, small rejoice indeed.

Seems like the sieve interpreter is different in 0.16.x vs 0.15.x

This script:

require ["variables", "envelope", "regex", "fileinto", "mailboxid", "mailbox", "copy", "subaddress", "enotify"];

if envelope :regex "to" "^([^+]+)\+([^+]+)@(.+)$" {
   set :upperfirst "folder" "${2}";
   set "envto" "${0}";
   fileinto :copy :create "Alias";
   fileinto :create "Alias/${folder}";
   notify :message "Alias/${folder}/${envto}" "mailto:[email protected]";
   stop;
}


I’ve added the notify line to send an email with the variables the sieve script is getting

I’m sending a fwd.something@domain mail, that’s rewritten as user+something@domain in the RPCT_TO stage (this works since the user’s script is run).

I’ve tried with sending a mail directly to user+something@domain and it fails the same, so it’s not an issue with the rewrite stage here.

However, in the email I’m receiving from the notification line, I get “Alias/L/user@domain” meaning that:

  1. The regex is matching but it’s not extracting the expected value in the sieve part (typically, I would expect to capture user+something@domain in ${0} but I don’t, and something in ${2}). I got complete trash in ${2} : L (that’s not even in the initial email)
  2. Something is strange in the regex match. I wonder if the “envelope::to” part is already rewritten to the final email user@domain here and the regex match is working on trashed data, since it can’t find a L nowhere in the given mail. Notice that it’s consistent, so another mail to the same address gives the same L value. In fact any value will put a L here.

Checked envelope.to in the sieve script and it’s user@domain, so the alias part isn’t here at all. There is definitively an issue here.

Notice that the regex shouldn’t match in that case, but the if branch is followed anyway since it’s notifying me.

The Sieve interpreter has not changed since v0.11 or more. What changed in v0.16 is how rewriting is done and when it is done. You might need to look at the original rcpt rather than the current rcpt. Also, since Sieve does not support debugging, you can try using reject or writing to a temporary header the result before and after applying the regex.

For debugging, I’m using notify :message and it works well (I think it should be added to the documentation as a tip). You can’t write to a temporary header at RCPT_TO stage (there’s no message and no headers yet, they are simply trashed at end of script run). With this debugging we were able to spot the issues with the current implementation of Sieve’s script. I’m not saying the interpreter changed, I’m saying the input data to the script don’t contain anymore what they used to, breaking the scripts that depended on said data. Similarly, some outputs of the scripts are ignored while there weren’t before (like the rewritten address in envelope.to in a RCPT_TO’s script isn’t used to check for the account, only the initial address is used, meaning it’s now impossible to rewrite an address with a sieve script).

There’s another issue titled “sub-addressing” that summarize the problems I’ve found and the workarounds/hacks I was able to implement.

The thread I’m referring to is here and here with the former describing the implementation issue and the latter describing a possible “use uninitialized” issue.