how to configure imapsieve to be used per user

Paul Kudla paul at scom.ca
Thu Oct 27 11:54:16 UTC 2022


ok a few things about sieve

although it is a pain it is usually (on a per user basis) better to 
access the sieve scripting through thunderbird's plugin sieve or 
something similiar as it will sort out checksums, syntax etc.

see :

https://github.com/thsmi/sieve/

https://www.pair.com/support/kb/sieve-syntax-and-common-recipes/

https://wiki.dovecot.org/Pigeonhole/ManageSieve/Troubleshooting

also RFC

https://datatracker.ietf.org/doc/html/rfc5804#page-3



Next and all though way more complicated since you need to calculate 
checksums etc i use a telnet python script that generates forward's etc

again may (probably not) what you are looking for but it at least gives 
another example(s)

python2 code below:

last but not least there is an RFC avaliable for sieve scripting but 
again its at a programming level and may not be overally useful ? (note 
link above)

don't feel bad it took me a while to figure this out as well.

for any of this to work you need the sieve listener port running on the 
mail server

make sure you can telnet to mailserver:2000 (older) or port 4190 
(current) depending how you are configured for sieve before going any 
further.

_______________________________________________________________________

dovecot.conf

protocols = imap pop3 lmtp sieve

protocol lmtp {
   mail_plugins = $mail_plugins sieve
   postmaster_address = monitor at scom.ca
}


   sieve = file:~/sieve;active=~/sieve/.dovecot.sieve
   #sieve = ~/.dovecot.sieve
   sieve_duplicate_default_period = 1h
   sieve_duplicate_max_period = 1h
   sieve_extensions = +duplicate +notify +imapflags +vacation-seconds
   sieve_global_dir = /usr/local/etc/dovecot/sieve
   sieve_before = /usr/local/etc/dovecot/sieve/duplicates.sieve


service managesieve-login {
   process_limit = 1000
   vsz_limit = 1g
   inet_listener sieve {
     port = 4190
   }
}

protocol sieve {
   managesieve_implementation_string = Dovecot Pigeonhole
   managesieve_max_line_length = 65536
}


_______________________________________________________________________

above is my sieve conf alter accordingly if needed ....



below are examples of my sieve processing scripts for vacation notices 
and forward's, this data comes from my django project model but should 
be pretty clear what the code is doing.

note : you need to base64 the auth username & password to login to the 
users sieve account.

note : \r\n needs to be used as a line terminator and calculated 
accordingly. See count & count2 below. Basically \r\n = 1

you can expand on this ....

________________________________________________________________________

		if self.vacation_active == True and dontupdate != True:
			#debug = [debug,server,port,count,label,pid]
			debug = 'syslog,10.228.0.6,514,0,sieve,0'
			log_debug (debug, 'Sieve (Vacation) : Do Not Update Status for : %s' 
%dontupdate )
			import base64,telnetlib
			log_debug (debug, 'Enabling Sieve for : %s' %self.username )
			auth = '\0%s\0%s' %(self.username,self.password)
			log_debug (debug, 'Auth : %s' %auth)
			auth = base64.b64encode(auth)
			log_debug (debug, 'Auth Encoded : %s' %auth)
			from telnetlib import Telnet
			tn =  Telnet('10.220.0.18', 4190)
			connect = tn.read_until('OK',5)
			log_debug (debug, 'Connect : \n%s\n' %connect)
			authout = 'AUTHENTICATE "PLAIN" "%s"\n'%auth
			log_debug (debug, 'Authout : %s' %authout)
			tn.write(authout)
			status = tn.expect(['OK','NO'],5)
			log_debug (debug, 'Auth : %s' %str(status) )
			tn.write('LISTSCRIPTS\r\n')
			status = tn.expect(['OK','NO'],5)
			log_debug (debug, 'Current Scripts : %s' %str(status) )
			#Send a Script
			script = 'keep;\r\nredirect "vacationprocessing at scom.ca";\r\n'
			count = len(script)
			count2 = script.count('\r\n')
			log_debug (debug, 'Count : %s' %count)
			log_debug (debug, 'Count 2 : %s'  %count2)
			init = 'PUTSCRIPT "forward" {%s+}\r\n' %(count - count2)
			log_debug (debug, 'Init : %s' %init)
			tn.write ( init )
			log_debug (debug, 'Script Len : %s' %len(script) )
			log_debug (debug, 'Script : %s' %script)
			tn.write( script )
			status = tn.expect(['OK','NO'],5)
			log_debug (debug, 'Write Status : %s' %str(status) )
			log_debug (debug,  'Setting Active' )
			tn.write('SETACTIVE "forward"\r\n')
			status = tn.expect(['OK','NO'],5)
			log_debug (debug, 'Write Status : %s' %str(status) )
			#logout
			tn.write('LOGOUT')
			status = tn.expect(['OK','NO'],5)
			log_debug (debug,  'Logout Status : %s' %str(status) )
		
		if (self.vacation_active == False and self.sieve_forwards == '') and 
dontupdate != True : #Deactivate Seive
			#debug = [debug,server,port,count,label,pid]
			debug = 'syslog,10.228.0.6,514,0,sieve,0'
			log_debug (debug, 'Sieve (Disable) : Do Not Update Status for : %s' 
%dontupdate )
			import base64,telnetlib
			log_debug (debug, 'Disabling Sieve for : %s' %self.username)
			auth = '\0%s\0%s' %(self.username,self.password)
			log_debug (debug, 'Auth : %s' %auth)
			auth = base64.b64encode(auth)
			log_debug (debug, 'Auth Encoded : %s' %auth)
			from telnetlib import Telnet
			tn =  Telnet('10.220.0.18', 4190)
			connect = tn.read_until('OK',5)
			log_debug (debug, 'Connect : \n%s\n' %connect)
			authout = 'AUTHENTICATE "PLAIN" "%s"\n'%auth
			log_debug (debug, 'Authout : %s' %authout)
			tn.write(authout)
			status = tn.expect(['OK','NO'],5)
			log_debug (debug, 'Auth : %s' %str(status) )
			tn.write('LISTSCRIPTS\r\n')
			status = tn.expect(['OK','NO'],5)
			log_debug (debug, 'Current Scripts : %s' %str(status) )
			log_debug (debug, 'Setting Disabled' )
			tn.write('SETACTIVE ""\r\n')
			status = tn.expect(['OK','NO'],5)
			log_debug (debug, 'Write Status : %s' %str(status) )
			#logout
			tn.write('LOGOUT')
			status = tn.expect(['OK','NO'],5)
			log_debug (debug,  'Logout Status : %s' %str(status) )

		#Check to see if forward is active
		if (self.sieve_forwards != '' and self.vacation_active == False ) and 
dontupdate != True:
			#debug = [debug,server,port,count,label,pid]
			debug = 'syslog,10.228.0.6,514,0,sieve,0'
			log_debug (debug, 'Do Not Update Status for : %s' %dontupdate )
			import base64,telnetlib
			log_debug (debug, 'Enabling Sieve Forwards for : %s' %self.username )
			auth = '\0%s\0%s' %(self.username,self.password)
			log_debug (debug, 'Auth : %s' %auth)
			auth = base64.b64encode(auth)
			log_debug (debug, 'Auth Encoded : %s' %auth)
			from telnetlib import Telnet
			tn =  Telnet('10.220.0.18', 4190)
			connect = tn.read_until('OK',5)
			log_debug (debug, 'Connect : \n%s\n' %connect)
			authout = 'AUTHENTICATE "PLAIN" "%s"\n'%auth
			log_debug (debug, 'Authout : %s' %authout)
			tn.write(authout)
			status = tn.expect(['OK','NO'],5)
			log_debug (debug, 'Auth : %s' %str(status) )
			tn.write('LISTSCRIPTS\r\n')
			status = tn.expect(['OK','NO'],5)
			log_debug (debug, 'Current Scripts : %s' %str(status) )
			#Send Script
			script = 'keep;\r\n'
			forwards = self.sieve_forwards.split(',')
			for nnn in range (0,len(forwards)) :
				script = script + 'redirect "%s";\r\n' %str(forwards[nnn])
			count = len(script)
			count2 = script.count('\r\n')
			log_debug (debug, 'Count : %s' %count)
			log_debug (debug, 'Count 2 : %s'  %count2)
			init = 'PUTSCRIPT "forward" {%s+}\r\n' %(count - count2 + 
len(forwards) - 1 )
			log_debug (debug, 'Init : %s' %init)
			tn.write ( init )
			log_debug (debug, 'Script Len : %s' %len(script) )
			log_debug (debug, 'Script : %s' %script)
			tn.write( script )
			status = tn.expect(['OK','NO'],5)
			log_debug (debug, 'Write Status : %s' %str(status) )
			log_debug (debug,  'Setting Active' )
			tn.write('SETACTIVE "forward"\r\n')
			status = tn.expect(['OK','NO'],5)
			log_debug (debug, 'Write Status : %s' %str(status) )
			#logout
			tn.write('LOGOUT')
			status = tn.expect(['OK','NO'],5)
			log_debug (debug,  'Logout Status : %s' %str(status) )
_______________________________________________________________________________




Happy Thursday !!!
Thanks - paul

Paul Kudla


Scom.ca Internet Services <http://www.scom.ca>
004-1009 Byron Street South
Whitby, Ontario - Canada
L1N 4S3

Toronto 416.642.7266
Main 1.866.411.7266
Fax 1.888.892.7266
Email paul at scom.ca

On 10/26/2022 9:28 PM, Stephan Bosch wrote:
> 
> 
> 
> On 24-10-2022 12:00, Sebastian Bachmann wrote:
>> according to the documentation, this has to be added to the IMAP 
>> METADATA dict per mailbox 
>> (https://doc.dovecot.org/configuration_manual/imap_metadata/):
>>
>> https://doc.dovecot.org/configuration_manual/sieve/plugins/imapsieve/ 
>> says:
>>> The basic IMAPSIEVE capability allows attaching a Sieve script to a 
>>> mailbox for any mailbox by setting a special IMAP METADATA entry. 
>>> This way, users can configure Sieve scripts that are run for IMAP 
>>> events in their mailboxes.
>> But I can not find any example how this should work, neither which 
>> client supports setting those things.
>> My guess is that these keys are used: 
>> https://www.iana.org/assignments/imap-metadata/imap-metadata.xhtml#imap-metadata-2
>>
>> I would also be interested to know if and how that works, especially 
>> if you can add a rule when moving mails (from anywhere) to a certain 
>> mailbox for a single user.
> 
> The basic capability works according to the specification: 
> https://www.rfc-editor.org/rfc/rfc6785
> This allows the users to configure these scripts.
> 
> If you want to arrange this solely at the administrator's discretion, 
> you can use the _before/_after settings documented in 
> https://doc.dovecot.org/configuration_manual/sieve/plugins/imapsieve
> 
>>
>> Best,
>> Sebastian
>>
>> On 17.10.2022 12:46, Marc wrote:
>>>
>>> I only see configurations that are active for all users, how to 
>>> configure this in the user sieve rules. I only need this for specific 
>>> users.
>>>
> 
> 


More information about the dovecot mailing list