Skip to main content
Version: 0.16

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. Default 4096.
  • maxNestedBlocks: maximum depth of nested if / elsif / else blocks. Default 15.
  • maxNestedTests: maximum depth of nested tests. Default 15.
  • maxNestedForEvery: maximum depth of nested foreverypart loops. Default 3.
  • maxMatchVars: maximum number of match and regex variables that can be captured. Default 30.
  • maxLocalVars: maximum number of local variables in scope at any point. Default 128.
  • maxHeaderSize: maximum length of an RFC 822 header value. Default 1024.
  • maxIncludes: maximum number of include instructions per script. Default 3.
  • maxNestedIncludes: maximum depth of nested include instructions. Default 3.
  • maxCpuCycles: maximum number of instructions a script can execute, counted across any included scripts. Default 5000.
  • maxVarNameLength: maximum length of a variable name. Default 32.
  • maxVarSize: maximum size of a variable; contents beyond this point are truncated. Default 4096.
  • maxRedirects: maximum number of message redirections per execution. Default 1.
  • maxReceivedHeaders: maximum number of Received headers before a message is treated as looping. Default 10.
  • maxOutMessages: maximum number of outgoing messages (including vacation responses, notifications, and redirects) a script can send. Default 3.
  • maxScriptNameLength: maximum length of a script name. Default 512.
  • maxScripts: default maximum number of Sieve scripts a single account may create. Default 100.

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": "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.