This documentation is for Dovecot v2.x, see wiki1 for v1.x documentation.

Pigeonhole Sieve Extprograms Plugin

The "sieve_extprograms" plugin provides an extension to the Sieve filtering language adding new action commands for invoking a predefined set of external programs. Messages can be piped to or filtered through those programs and string data can be input to and retrieved from those programs. To mitigate the security concerns, the external programs cannot be chosen arbitrarily; the available programs are restricted through administrator configuration.

This plugin is only available for Pigeonhole v0.3 and higher (available for Dovecot v2.1). For Pigeonhole v0.4 this plugin is part of the release. This an evolution of the Pipe plugin for Pigeonhole v0.2 and now provides the "filter" and "execute" commands (and corresponding extensions) in addition to the "pipe" command that was provided earlier by the Pipe plugin.

Getting the sources

Starting with Pigeonhole v0.4 for Dovecot v2.2, the plugin is included in the release and therefore it is implicitly compiled and installed with Pigeonhole itself.

For Pigeonhole v0.3, the plugin was never released, but you can get the sources from its Mercurial repository:

hg clone

Compiling for Pigeonhole v0.3

If you downloaded the sources of this plugin using Mercurial, you will need to execute ./ first to build the automake structure in your source tree. This process requires autotools and libtool to be installed.

If you installed Dovecot from sources, the plugin's configure script should be able to find the installed dovecot-config automatically, along with the Pigeonhole development headers:

sudo make install

If this doesn't work, you can use --with-dovecot=<path> configure option, where the path points to a directory containing dovecot-config file. This can point to an installed file:

./configure --with-dovecot=/usr/local/lib/dovecot
sudo make install

The above example should also find the necessary Pigeonhole development headers implicitly. You can also compile by pointing to compiled Dovecot and Pigeonhole source trees:

./configure --with-dovecot=../dovecot-2.1.0/ --with-pigeonhole=../dovecot-2.1-pigeonhole-0.3.0
sudo make install


The plugin is activated by adding it to the sieve_plugins setting:

sieve_plugins = sieve_extprograms

This plugin registers the vnd.dovecot.pipe, vnd.dovecot.filter and vnd.dovecot.execute extensions with the Sieve interpreter. However, these extensions are not enabled by default and thus need to be enabled explicitly. It is recommended to restrict the use of these extensions to global context by adding these to the sieve_global_extensions setting. If personal user scripts also need to directly access external programs, the extensions need to be added to the sieve_extensions setting.

The commands introduced by the Sieve language extensions in this plugin can directly pipe a message or string data to an external program (typically a shell script) by forking a new process. Alternatively, these can connect to a unix socket behind which a Dovecot script service is listening to start the external program, e.g. to execute as a different user or for added security.

The program name specified for the new Sieve pipe, filter and execute commands is used to find the program or socket in a configured directory. Separate directories are specified for the sockets and the directly executed binaries. The socket directory is searched first. Since the use of "/" in program names is prohibited, it is not possible to build a hierarchical structure.

Directly forked programs are executed with a limited set of environment variables: HOME, USER, SENDER, RECIPIENT and ORIG_RECIPIENT. Programs executed through the script-pipe socket service currently have no environment set at all.

If a shell script is expected to read a message or string data, it must fully read the provided input until the data ends with EOF, otherwise the Sieve action invoking the program will fail. The action will also fail when the shell script returns a nonzero exit code. Standard output is available for returning a message (for the filter command) or string data (for the execute command) to the Sieve interpreter. Standard error is written to the LDA log file.

The three extensions introduced by this plugin - vnd.dovecot.pipe, vnd.dovecot.filter and vnd.dovecot.execute - each have separate but similar configuration. The following configuration settings are used, for which "<extension>" in the setting name is replaced by either pipe, filter or execute depending on which extension is being configured:

sieve_<extension>_socket_dir =
Points to a directory relative to the Dovecot base_dir where the plugin looks for script service sockets.
sieve_<extension>_bin_dir =
Points to a directory where the plugin looks for programs (shell scripts) to execute directly and pipe messages to.
sieve_<extension>_exec_timeout = 10s
Configures the maximum execution time after which the program is forcibly terminated.
sieve_<extension>_input_eol = crlf
Determines the end-of-line character sequence used for the data piped to external programs. The default is currently "crlf", which represents a sequence of the carriage return (CR) and line feed (LF) characters. This matches the Internet Message Format (RFC5322) and what Sieve itself uses as a line ending. Set this setting to "lf" to use a single LF character instead.

Configuration Example 1: socket service for "pipe" and "execute"

plugin {
  sieve = ~/.dovecot.sieve

  sieve_plugins = sieve_extprograms
  sieve_global_extensions = +vnd.dovecot.pipe +vnd.dovecot.execute

  # pipe sockets in /var/run/dovecot/sieve-pipe
  sieve_pipe_socket_dir = sieve-pipe

  # execute sockets in /var/run/dovecot/sieve-execute
  sieve_execute_socket_dir = sieve-execute

service sieve-pipe-script {
  # This script is executed for each service connection
  executable = script /usr/lib/dovecot/sieve-extprograms/

  # use some unprivileged user for execution
  user = dovenull

  # socket name is program-name in Sieve (without sieve-pipe/ prefix)
  unix_listener sieve-pipe/sieve-pipe-script {

service sieve-execute-action {
  # This script is executed for each service connection
  executable = script /usr/lib/dovecot/sieve-extprograms/

  # use some unprivileged user for execution
  user = dovenull

  # socket name is program-name in Sieve (without sieve-execute/ prefix)
  unix_listener sieve-execute/sieve-execute-action {

Configuration Example 2: direct execution for "pipe" and "filter"

plugin {
  sieve = ~/.dovecot.sieve

  sieve_plugins = sieve_extprograms
  sieve_global_extensions = +vnd.dovecot.pipe +vnd.dovecot.filter

  # This directory contains the scripts that are available for the pipe command.
  sieve_pipe_bin_dir = /usr/lib/dovecot/sieve-pipe

  # This directory contains the scripts that are available for the filter
  # command.
  sieve_filter_bin_dir = /usr/lib/dovecot/sieve-filter


Read the specification (v0.3 plugin/v0.4+) for detailed information on how to use the new language extensions.

Full Examples

Example 1

This example shows how to use the "vnd.dovecot.execute" extension for querying/updating a MySQL database. This is used to redirect messages only once every 300s for a particular sender. Note that this particular use case could also be implemented using the Sieve "duplicate" extension

Relevant configuration:

plugin {
 sieve_extensions = +vnd.dovecot.execute

 sieve_plugins = sieve_extprograms
 sieve_execute_bin_dir = /usr/lib/dovecot/sieve-execute

The sieve script:

require ["variables", "copy", "envelope", "vnd.dovecot.execute"];

# put the envelope-from address in a variable
if envelope :matches "from" "*" { set "from" "${1}"; }

# execute the program and redirect the message based on its exit code
if execute :output "vacation_message" "" ["${from}","300"]
      :copy "";

At the location /usr/lib/dovecot/sieve-execute, create the executable script In this example, the script needs two parameters: the sender address and a time interval specified in seconds. The time interval is used to specify the minimum amount of time that needs to have passed since the sender was last seen. If the script returns exit code 0, then message is redirected in the Sieve script shown above.


#CREATE TABLE `sieve_count` (
#  `from_addres` varchar(254) NOT NULL,
#  `date` datetime NOT NULL
#ALTER TABLE `sieve_count`
#  ADD KEY `from_addres` (`from_addres`);

MAILS=$(mysql -u$USER -p$PASS $DATABASE --batch --silent -e "SELECT count(*) as ile FROM sieve_count WHERE from_addres='$1' AND DATE_SUB(now(),INTERVAL $2 SECOND) < date;")
ADDRESULT=$(mysql -u$USER -p$PASS $DATABASE --batch --silent -e "INSERT INTO sieve_count (from_addres, date) VALUES ('$1', NOW());")

# uncoment below to debug
# echo Uset $1 sent $MAILS in last $2 s >> /usr/lib/dovecot/sieve-pipe/output.txt
# echo Add result : $ADDRESULT >> /usr/lib/dovecot/sieve-pipe/output.txt
# echo $MAILS

if [ "$MAILS" = "0" ]
exit 0

exit 1

Pigeonhole/Sieve/Plugins/Extprograms (last edited 2017-05-08 08:34:46 by klara)