Previous: listserv_getsubscriptions, Up: Functions Reference

9.13 listserv_getsieve_scripts

— Function: char** listserv_getsieve_scripts (struct listserv *l, const char *listname, int unsigned extensions);

Returns a NULL-terminated array, containing Sieve scripts for proceeding the emails for listname. For each list, listserv_getsieve_scripts generates several scripts: for owner-listname@, listname-request@, listname@, listname-signoff-request@, listname-subscribe-request@, listname-server@, listname-search-request@, listname-unsunsubscribe-request@, listname-check-subscription@ . One of the mentioned script names, not containing the @-sign and the domain, is in the odd returned values. The actual scripts are in the even returned values. The last odd value is NULL.

The generated scripts are supposed to reject incoming emails during the SMTP dialog, rather than to deliver them to listserv and let it bounce them. In this way, bounces do not end in black lists and the server running listserv is not marked as spammer.

As a side effect, listserv does not send emails to non-existing addresses and does not post enormous amounts of delivery-reports to the postmasters. Th reduced amounts of delivery reports makes possible to check individually each of them and take actions.

Apart from rejecting emails, that will be anyway bounced by listserv, some more emails are rejected. Details are provided in the logic for the individual scripts.

extensions specifies the extensions that will be used by the generated scripts. It is binary ORed combination, of:

              1  extension/test envelope
              2  extension/action reject
              4  extension/action ereject
              8  extension extlists
             16  extension variables  /* for future use, not implemented */
             32  extension/test ihave /* for future use, not implemented */
           4096  without size

When both 2 = reject and 4 = ereject are available, the scripts contain only ereject.

If the provided extensions are not sufficient to build any script, listserv_getsieve_scripts returns an array with one value (NULL).

The logic for each generated script is:

The script for the mailing list address can be sptlit into parts:
  • test envelope
  • test size
  • test MIME headers
  • non-members case
  • Test envelope is inserted, only when extensions is odd and when the Send keyword does not contain Public. All email addresses that can post to the list are inserted in the envelope test. In particular:
    • list subscribers, when they are entitled to post to the list (Send = Private and do not have the NOPOST option)
    • all email addresses mentioned in the Send, Owner, Configuration-Owner, Moderator and Editor keywords
    • all email addresses mentioned as Sub-Lists of the current list, when Send contains Hold.

    When extlists in extensions is disabled, all mentioned senders' addresses are inserted in the envelope test. E.g. if

                        Owner = Owner(XYZ-L)
                        Editor = ABC-L

    then all email addresses subscribed to ABC-L and all addresses that can manage XYZ-L are inserted in the envelope test. The latter has the form:

                        if not envelope :is "from" ["", subscriber ...] {
                            reject "content of the mail template SIEVE_CANNOT_POST_ENVELOPE_MSG";

    The "" indicates, that bounces can be sent to the list. This is partially nonsense: the listname@ address is never used as sender for lists, where only a limited amount of subscribers can post. In turn there are no delivery-errors returned to the listname@ address and hence the incoming mails for the list shall never be bounces. However, the emails for AEGEE mailing lists go to an exim server, where greylisting and check-outs for the existence of the recipient addresses are perfomed. This check-outs use as sender for the initial grey-listing request the original sender. Subsequently they check one more time if the email can be delivered and then deliver the email. In this additional check the sender is set to "". So in order to receive emails for the list, the mailing lists server has to accept also bounces.

    When extlists is enabled, instead of the email addresses mentioned in the configuration of other lists, a reference to that lists is inserted. The above mentioned example will be modified to:

                        if not anyof (envelope :is "from" ["", subscribers ...],
                                      envelope :is :list "from" ["listserv:xyz-l", "listserv:abc-l|editor"]) {
                            reject "content of the mail template SIEVE_CANNOT_POST_ENVELOPE_MSG";

    When the scripts with extlists-support are later evaluated, the sieve interpreter checks at run-time if the sender is subscribed to the mentioned lists. This is slower, compared to the case, when all relevant email addresses are directly mentioned in the envelope test and no additional queries to listserv are needed to evaluate the script. The reader might think, that it would be better if all generated scripts do not use extlists, for faster evaluation.

    The most suitable time to generate a script for a list, is when the list is changed: somebody subscribes, signs off, or the list configuration is changed. With this information in mind, in AEGEE we generate the scripts by a list exit, that is fired by listserv. The list exit knows for which list the scripts shall be generated, but it does not know which lists depend on the current list (e.g. mention the subscribers of this list as editors for the other list). When a list script is uploaded, all other list scripts' that depend on this list, must be updated, too. This is currently not done. Apart from this, listserv does not fire list exits on changed list configuration or bulk operations, thus it is not possible to keep the lists up to date. The best option for the moment is to include references for the external lists.

    When Send = Editor, Hold with or without Confirm, then liblistserv modifies the interpretation of listserv. Orinally listserv will permit everybody to propose emails for distribution over the list. When Confirm is presented, then a lot of bounces are sent to the mail sender. When Confirm is absent, the editors receive a lot of spam, that is hard to proceed manually. liblistserv generates scipt, that reject emails for such lists, if the sender does not receive emails from the lists. The latter means, that the sender is not Editor/Moderator/Owner/Configuration-Owner of the list, is not subscribed to the list and is not a member of a sub-list.

  • Test size is inserted, only when extensions & 4096 == 0, the Attachment keyword does not have Filter as value and either the Language keyword does not have NOHTML as value or the Misc-Options does not have DISCARD_HTML as value . The test has the form
                        if size :over 512K {
                            reject "Your mail to ${} exceeds 512KBytes.  Upload the attachments
                        in internet and include a link to them in your email.";

    The value for the test (here 512K) is taken from the SizeLim keyword. If Sizelim is omitted, the default SizeLim is used.

    The idea to put the test size between envelope and MIME headers, is to evaluate it as early as possible — during the SMTP MAIL FROM: command, when it has SIZE=-parameter, or after DATA, otherwise.

  • Test MIME headers is inserted, when Send is not Public. It has the form
                        if not address :is ["From", "Sender", "Resent-From", "Resent-Sender"] [emails...] {
                            reject "put here the content of the SIEVE_CANNOT_POST_MIME_MSG mail template.";

    The emails are obtained as described with the envelope test, excluding the "" test. Bounces for a mailing list are rejected based on the unappropriatre MIME headers after DATA, not after envelope. The considerations about the external lists are valid here, too.

  • The CONTENT_FILTER rules are created from the CONTENT_FILTER template, if there is one for the list, or the site.

    Each rule has two parts: test and action. The test is either for a header-field, for all headers or for a string in the whole email. Tests for text in any header or tests for text contained in the email body are not mirrored in the Sieve scripts. Subsequent tests are also not mirrored.

    When the action is MODERATE, ALLOW or DISCARD, the email is passed to Listserv. When the action is REJECT, an ereject command is inserted in the Sieve script containing the reason for the rejection. The reason is preceed with the text "Your posting to the listname list has been rejected by the content filter.".

    E.g. the CONTENT_FILTER template,

                          X-Spam-Level:: ++
                          Action: ALLOW
                          X-Spam-Level:: +++
                          Action: MODERATE
                          X-Spam-Level: ++++
                          Action: REJECT This is spam.

    generates the script

                        if anyof( header :is "X-Spam-Level" "++",
                                  header :is "X-Spam-Level" "+++") {
                        if header :contains "X-Spam-Level" "++++" {
                            ereject "Your posting to the listname list has been rejected by the content filter.
                        This is spam.";
  • When Send has Non-Members as value, liblistserv modifies the intepreration of listserv. Originally an email is sent back to the sender asking her/him to confirm the message. This causes a lot of bounces and the purpose of liblistserv is to reduce the amount of bounces. If such an email is not rejected by the content filter and the sender is not subscribed to the list, liblistserv redirects the email to the Editors and Moderators of the list.

The script has the form:
                 require ["ereject"]; // or reject, if ereject is not available, and reject is
                 if header :contains "X-Spam-Level" "+++" {
                     ereject the content of the SPAM_REQUEST_MSG template;
                 } else {
                     redirect to the non-quiet listowners of the list

The incoming emails are not passed to listserv, and the principe of confirming the emails send to -request@ addresses, before sending them to the list owner is circumvented. In this way listserv sends less bounces.

The script has the form:
                   require ["envelope", "ereject"];
                   if not envelope :is "from" ["", the list subscribers] {
                     reject "not subscribed";
                   } else {

The purpose is to be able to create programs, that use the SMTP protocol to say if an address is subscribed to a list or not. See for such a client. The idea of envelope [""] is described for the script for listname@, test envelope. When extension/test envelope is not available, the script is not created (is "").

The script has the form:
                    require ["envelope", "ereject"];
                    if not envelope :is "from" ["", the list subscribers] {
                    ereject "BG - Ne ste abonat na listname.
               CA - No ets suscrit a la llista listname.
               DE - Sie sind kein Mitglied der Liste listname.
               EN - You, ${envelope.from} are not subscribed to listname.
               ES - No estas suscrito a la lista listname.
               FR - Vous n'etes pas inscrit sur la liste listname.
               IT - Non sei iscritto alla lista listname.
               LV - Tu neesi pierakstijies listei listname.
               PT - Nao esta inscrito na lista listname.
               SR - Niste pretplaceni na listname.";
                    if not address :is ["From", "Sender", "Resent-From", "Resent-Sender"] [the list subscribers] {
                      ereject the above message;

and listname is replaced with the name of the list.

The script is the same as for listname-unsubscribe-request@.
If Subscribe = Closed, the script has the form:
               require "ereject";
               ereject "${envelope.from} cannot subscribe to listname.  Contact the listowners as for clarification how to join the list.\r\n${advertisement}";

Otherwise the script has the form:

               require "ereject";
               if header :contains "X-Spam-Level" "+++++" {
                   reject "Your mail was evaluated as spam (see below for details). To join listname visit

The script is always "".
The script is always "".
The script has the form:
                   require ["ereject", "envelope"];
                   if not envelope :is "from" ["", the list subscribers] {
                     ereject "${evenlope.from} cannot post to ${}.";