Untrusted Interpreter
The untrusted interpreter runs Sieve scripts created by end-users. Stalwart supports JMAP for Sieve Scripts and ManageSieve for uploading and managing user scripts.
Interpreter settings, resource limits, and the list of globally available scripts are configured through the SieveUserInterpreter singleton (found in the WebUI under Settings › Sieve › User Interpreter) and the SieveUserScript object (found in the WebUI under Settings › Sieve › User Scripts).
Limits
User scripts execute in a sandbox that bounds their use of server resources. The limits are expressed as fields on the SieveUserInterpreter singleton:
maxScriptSize: maximum size of a Sieve script. Default"100kb".maxStringLength: maximum size of a constant string. Default4096.maxNestedBlocks: maximum depth of nestedif/elsif/elseblocks. Default15.maxNestedTests: maximum depth of nested tests. Default15.maxNestedForEvery: maximum depth of nestedforeverypartloops. Default3.maxMatchVars: maximum number of match and regex variables that can be captured. Default30.maxLocalVars: maximum number of local variables in scope at any point. Default128.maxHeaderSize: maximum length of an RFC 822 header value. Default1024.maxIncludes: maximum number ofincludeinstructions per script. Default3.maxNestedIncludes: maximum depth of nestedincludeinstructions. Default3.maxCpuCycles: maximum number of instructions a script can execute, counted across any included scripts. Default5000.maxVarNameLength: maximum length of a variable name. Default32.maxVarSize: maximum size of a variable; contents beyond this point are truncated. Default4096.maxRedirects: maximum number of message redirections per execution. Default1.maxReceivedHeaders: maximum number ofReceivedheaders before a message is treated as looping. Default10.maxOutMessages: maximum number of outgoing messages (including vacation responses, notifications, and redirects) a script can send. Default3.maxScriptNameLength: maximum length of a script name. Default512.maxScripts: default maximum number of Sieve scripts a single account may create. Default100.
Example limits:
{
"maxScriptNameLength": 512,
"maxScriptSize": "100kb",
"maxStringLength": 4096,
"maxVarNameLength": 32,
"maxVarSize": 4096,
"maxNestedBlocks": 15,
"maxNestedTests": 15,
"maxNestedForEvery": 3,
"maxMatchVars": 30,
"maxLocalVars": 128,
"maxHeaderSize": 1024,
"maxIncludes": 3,
"maxNestedIncludes": 3,
"maxCpuCycles": 5000,
"maxRedirects": 1,
"maxReceivedHeaders": 10,
"maxOutMessages": 3
}
Extensions
Stalwart supports all registered Sieve extensions and enables them by default. Administrators often want to disable extensions that let a user send outgoing email from a script (for example enotify) or modify message content (for example editheader, replace, enclose).
Disabled extensions are listed in disableCapabilities on SieveUserInterpreter. The accepted values are documented on the SieveCapability enum.
{
"disableCapabilities": ["editheader", "replace", "enclose", "enotify"]
}
Notification URIs
The allowed URI schemes for the notify extension are configured through allowedNotifyUris. The default is ["mailto"].
{
"allowedNotifyUris": ["mailto"]
}
Protected Headers
Headers that cannot be added or removed by the editheader extension are listed in protectedHeaders. The default list is ["Original-Subject", "Original-From", "Received", "Auto-Submitted"].
{
"protectedHeaders": ["Original-Subject", "Original-From", "Received", "Auto-Submitted"]
}
Vacation defaults
Defaults for the vacation extension are exposed on SieveUserInterpreter through:
defaultSubject: default subject of vacation responses. Default"Automated reply".defaultSubjectPrefix: prefix prepended to vacation response subjects. Default"Auto: ".
{
"defaultSubject": "Automated reply",
"defaultSubjectPrefix": "Auto: "
}
Expiration defaults
The default lifetimes for identifiers stored by the vacation and duplicate extensions are controlled by:
defaultExpiryVacation: default expiration for vacation response tracking. Default"30d".defaultExpiryDuplicate: default expiration for identifiers stored by theduplicateextension. Default"7d".
{
"defaultExpiryVacation": "30d",
"defaultExpiryDuplicate": "7d"
}
Global Scripts
Global user scripts are published as SieveUserScript records. Each record carries a name, an optional description, an isActive flag, and the script body in contents. Users reference these scripts from their own scripts with include :global.
For example, a global script that rejects messages larger than 100 KB:
{
"name": "global_one",
"description": "Reject oversized messages",
"isActive": true,
"contents": "# Declare the extensions used by this script.\n#\nrequire [\"reject\"];\n\n# Messages bigger than 100K will be rejected with an error message\n#\nif size :over 100K {\n reject \"I'm sorry, I do not accept mail over 100kb in size. Please upload larger files to a server and send me a link. Thanks.\";\n}\n"
}
The contents field holds the full script text; loading the script body from an external file is not supported.