====== Filtering with Sieve ====== The **Debian 11 Bullseye** GNU/Linux installs the **Dovecot** mail suite version **2.3.13**, including the **Pigeonhole Sieve** extension **v0.5.13** (via the **dovecot-sieve** package). The [[https://doc.dovecot.org/configuration_manual/sieve/pigeonhole_sieve_interpreter/|Pigeonhole Sieve Interpreter]] provides the //pipe//, //filter// and //execute// commands, where the //pipe// was the older one implemented (starting from v0.2). Currently the more modern //execute// command can be used instead of the //pipe// one. The following recipes were tested into a **$HOME/.dovecot.sieve** file, i.e. the users's Sieve filter applied by the Dovecot Local Delivery Agent. FIXME Document the timeout options. ===== Sender ===== Storing messages in different folder upon (envelope) sender: require ["fileinto", "envelope"]; if envelope "from" "user1@rigacci.org" { fileinto "FromUser1"; } Discard a message by sender: if address :is "from" "MAILER-DAEMON@mail.rigacci.org" { discard; stop; } Same result, but use the generic //header// command instead of //address//: if header :contains "From" "MAILER-DAEMON@mail.rigacci.org" { discard; stop; } ===== Recipient ===== Storing messages in different folder upon destination address: require ["fileinto"]; if address :is "to" "MyAlias1@rigacci.org" { fileinto "ToAlias1"; } ===== Body ===== Storing messages in different folder upon body content (this requires the [[https://datatracker.ietf.org/doc/html/rfc5173.html|Sieve Body Extension]], which is supported by the Dovecot Pigeonhole Sieve Interpreter): require ["fileinto", "body"]; if body :contains "Address Verification Required" { fileinto "Spam"; } ===== Forward and keep a local copy ===== The **redirect** built-in //action// can be modified by the **:copy** //tag// (which is a built-in extension, but it must enabled using the **require** statement). The '':copy'' tag means that the message is not completed by the ''redirect'' action; eventually the ''keep'' action will be finally executed. require ["copy"]; # Forward the messages unconditionally and continue processing. redirect :copy "niccolo@texnet.it"; ===== Forward with From rewrite (to pass SPF check) ===== Rewrite the **From** header before forwarding, to ensure to pass the SPF checks at destination. **This hack alone does not work**, beacuse it rewrites only the From header, not the envelope sender (which is generally reported as //Return-Path//). require ["editheader"]; deleteheader "from"; addheader "From" "user1@forwarding.domain"; redirect "user2@forward.destination.domain"; **NOTICE**: To use the //editheader// plugin you must enable it into Dovecot configuration file (in Debian edit **/etc/dovecot/conf.d/90-sieve.conf**), adding it into the **sieve_extensions** list: plugin { ... sieve_extensions = +vnd.dovecot.filter +editheader ... } **NOTICE**: The **envelope sender** is reported as a **Return-Path** header on the recipient side, but changing the Return-Path header with a Dovecot Sieve rule is not equivalent to changing the envelope sender. One noticeable recipient that checks the **envelope sender** is Gmail, so it is not sufficient to change the **From** header to bypass the SPF check and get the message delivered to a Gmail account. Fortunately Dovecot Sieve allows you to change the envelope sender: you have to do it into the system configuration file. In Debian you can add it into the **/etc/dovecot/conf.d/90-sieve.conf** configuration file: plugin { ... sieve_extensions = +vnd.dovecot.filter +vnd.dovecot.execute +editheader ... # Header fields must not exceed one kilobyte sieve_editheader_max_header_size = 4k # Specifies what envelope sender address is used for redirected messages. sieve_redirect_envelope_from = orig_recipient ... } The **sieve_redirect_envelope_from** option accepts several values, see the [[https://doc.dovecot.org/settings/pigeonhole/#pigeonhole_setting-sieve_redirect_envelope_from|pigeonhole manual]]: ^ sender | The sender address is used (default). | ^ recipient | The final recipient address is used. | ^ orig_recipient | The original recipient is used. | ^ user_email | The user’s primary address is used. This is configured with the **sieve_user_email** setting. If that setting is not configured, ''user_email'' is equal to ''sender''. | ^ postmaster | The **postmaster_address** configured for LDA/LMTP. | ^ | Redirected messages are always sent from ''user@domain''. The angle brackets are mandatory. The null ''%%<>%%'' address is also supported. | It seems that Goole requires a SPF valid **envelope from**, but it is happier if you modify also the **From** header: if anyof ( header :contains "Subject" "Invio Bolletta Conto Contrattuale", address :is "to" "user@rigacci.org" ) { deleteheader "From"; addheader :last "From" "Forward "; redirect "user.name@gmail.com"; keep; } ===== Pipe a message to an external program ===== To enable the **execute** Sieve command using **Debian 11** you have to edit some configuration files contained into the **/etc/dovecot/conf.d/** directory. Set the **sieve_extension** option editing the file **90-sieve.conf**; in this example both the //filter// and //execute// extensions are loaded: plugin { ... sieve_extensions = +vnd.dovecot.filter +vnd.dovecot.execute ... } Then you have to edit the **90-sieve-extprograms.conf** configuration file and define the **sieve_execute_socket_dir** and **sieve_execute_bin_dir** options: plugin { ... sieve_execute_socket_dir = sieve-execute sieve_execute_bin_dir = /usr/local/lib/dovecot/sieve-execute ... } Only the executables contained into //sieve_execute_bin_dir// can be used as //execute// commands in sieve scripts. The following example is used to pipe a received message to an external program, which acts as a gateway from the mail system to the SMS mobile network. Only messages originating from some addresses and containing a properly formatted subject are piped to the external program: require ["vnd.dovecot.execute"]; # Specially crafted messages are piped to an SMS gateway. if allof ( anyof ( address :is "from" "user1@rigacci.org", address :is "from" "user2@rigacci.org"), header :contains "Subject" "SMS" ) { execute :pipe "sms-gateway"; } Here the **execute** //command// is called with the **:pipe** //tag//, this causes the execution of the external program much like the older ''pipe'' command. The **execute** command is not considered a final action (which "consumes" the message), so the **keep** action is eventually taken, saving the message into the INBOX. * **[[https://doc.dovecot.org/configuration_manual/sieve/plugins/extprograms/|Pigeonhole Sieve: Extprograms Plugin]]** * **[[https://mailutils.org/manual/html_chapter/Sieve-Language.html|GNU Mailutils Sieve]]** ===== Selection Criteria ===== ^ %%header :contains "subject" "string"%% | The string is contained somewhere in the Subject header. Wildcards (e.g. **''%%*%%''** or **''%%?%%''** are not allowed). | ^ %%header :matches "subject" "string"%% | The string must match exactly the Subject header, you can use wildcards to extend the match, eg. **''%%*%%''** matches any sequence of characters, **''%%?%%''** matches only one character. | ^ %%exists "X-Spam-Report"%% | Check the existence of the specified header. | * **[[https://en.wikipedia.org/wiki/Sieve_%28mail_filtering_language%29#Example|Sieve (mail filtering language) Example]]** * **[[https://doc.dovecot.org/2.3/configuration_manual/sieve/examples/|Sieve Examples]]** * **[[https://p5r.uk/blog/2011/sieve-tutorial.html|Sieve Tutorial]]**