sievelib
Client-side Sieve and Managesieve library written in Python.
Sieve : An Email Filtering Language (RFC 5228)
ManageSieve : A Protocol for Remotely Managing Sieve Scripts (RFC 5804)
Installation
To install sievelib from PyPI:
pip install sievelib
To install sievelib from git:
git clone git@github.com:tonioo/sievelib.git cd sievelib python ./setup.py install
Sieve tools
What is supported
Currently, the provided parser supports most of the functionalities described in the RFC. The only exception concerns section 2.4.2.4. Encoding Characters Using “encoded-character” which is not supported.
The following extensions are also supported:
Copying Without Side Effects (RFC 3894)
Body (RFC 5173)
Vacation (RFC 5230)
Seconds parameter for Vacation (RFC 6131)
Relational (RFC 5231)
Imap4flags (RFC 5232)
Regular expression (Draft)
Notifications (RFC 5435)
Environment (RFC 5183)
The following extensions are partially supported:
Extending the parser
It is possible to extend the parser by adding new supported commands. For example:
import sievelib
class MyCommand(sievelib.commands.ActionCommand):
args_definition = [
{"name": "testtag",
"type": ["tag"],
"values": [":testtag"],
"extra_arg": {"type": "number",
"required": False},
"required": False},
{"name": "recipients",
"type": ["string", "stringlist"],
"required": True}
]
sievelib.commands.add_commands(MyCommand)
Basic usage
The parser can either be used from the command-line:
$ cd sievelib $ python parser.py test.sieve Syntax OK $
Or can be used from a python environment (or script/module):
>>> from sievelib.parser import Parser
>>> p = Parser()
>>> p.parse('require ["fileinto"];')
True
>>> p.dump()
require (type: control)
["fileinto"]
>>>
>>> p.parse('require ["fileinto"]')
False
>>> p.error
'line 1: parsing error: end of script reached while semicolon expected'
>>>
Simple filters creation
Some high-level classes are provided with the factory module, they make the generation of Sieve rules easier:
>>> from sievelib.factory import FiltersSet
>>> fs = FiltersSet("test")
>>> fs.addfilter("rule1",
... [("Sender", ":is", "toto@toto.com"),],
... [("fileinto", "Toto"),])
>>> fs.tosieve()
require ["fileinto"];
# Filter: rule1
if anyof (header :is "Sender" "toto@toto.com") {
fileinto "Toto";
}
>>>
Updating existing filters
An existing script can be loaded into a FiltersSet from a parser result. Rules preceded by a # Filter: <name> comment keep that name. The other rules are named after their position in the script: Unnamed rule 1, Unnamed rule 2, and so on. Use these names to update a rule:
>>> from sievelib.parser import Parser
>>> from sievelib.factory import FiltersSet
>>> p = Parser()
>>> p.parse('''require ["fileinto"];
... if header :contains "Subject" "a" { fileinto "A"; }
... if header :contains "Subject" "b" { fileinto "B"; }
... ''')
True
>>> fs = FiltersSet("test")
>>> fs.from_parser_result(p)
>>> [f["name"] for f in fs.filters]
['Unnamed rule 1', 'Unnamed rule 2']
>>> fs.updatefilter("Unnamed rule 2", "Unnamed rule 2",
... [("Subject", ":contains", "b"),
... ("Subject", ":contains", "c")],
... [("fileinto", "B")])
True
Keep in mind that:
the generated names are computed when the script is loaded. They are not renumbered when filters are added or removed later,
tosieve() writes a # Filter: comment before each rule, so generated names become real names in the produced script,
filters are also available by position via the fs.filters list.
Using another naming convention
The comment prefixes used for filter names and descriptions can be changed with the filter_name_pretext and filter_desc_pretext arguments of FiltersSet. For example, to read and write scripts generated by the Roundcube managesieve plugin, which marks each rule with a # rule:[name] comment:
>>> from sievelib.parser import Parser
>>> from sievelib.factory import FiltersSet
>>> p = Parser()
>>> p.parse('''require ["fileinto"];
... # rule:[job]
... if header :contains "from" "noreply@domain.tld" { fileinto "Job"; }
... ''')
True
>>> fs = FiltersSet("roundcube", filter_name_pretext="# rule:")
>>> fs.from_parser_result(p)
>>> [f["name"] for f in fs.filters]
['[job]']
>>> fs.getfilter("[job]") is not None
True
Since only a prefix can be configured, the brackets are part of the filter name. tosieve() writes the # rule:[job] comment back as it was. Other comments of the original script are not kept.
Additional documentation is available within source code.
ManageSieve tools
What is supported
All mandatory commands are supported. The RENAME extension is supported, with a simulated behaviour for server that do not support it.
For the AUTHENTICATE command, supported mechanisms are PLAIN, LOGIN, OAUTHBEARER and XOAUTH2.
Both explicit TLS via STARTTLS and implicit TLS are supported.
Basic usage
The ManageSieve client is intended to be used from another python application (there isn’t any shell provided):
>>> from sievelib.managesieve import Client
>>> c = Client("server.example.com")
>>> c.connect("user", "password", starttls=True, authmech="PLAIN")
True
>>> c.listscripts()
("active_script", ["script1", "script2"])
>>> c.setactive("script1")
True
>>> c.havespace("script3", 45)
True
>>>
Additional documentation is available with source code.
Metadata
Release files for sievelib 1.6.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| sievelib-1.6.0.tar.gz | 46.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sievelib-1.6.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 91.4 kB
Release files / sievelib-1.6.0.tar.gz
| Download URL | sievelib-1.6.0.tar.gz |
|---|---|
| Size | 46.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
55c11ad3f404aac5ff0f4ec9e0ae354e1d803aed72c44524598d25deac86b0b8
|
|
BLAKE2b-256 checksum How to use checksums |
2e73416647b12960620b3d61946c23fd2598eee59f64a9c4d5dfdd65a0b09c61
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.
Transparency logRelease files / sievelib-1.6.0-py3-none-any.whl
| Download URL | sievelib-1.6.0-py3-none-any.whl |
|---|---|
| Size | 45.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6c6f82843db8128b50585c119b3912b0b09c5dc97b3074b251685c3ee4850287
|
|
BLAKE2b-256 checksum How to use checksums |
3e069d1ef10ee73ba5041f01bbdbdb07c5bddfbc7b1aec71f5dd264c1549b86a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.
Transparency log