Hello everyone,
I am currently working on porting the Dovecot 2.4 configuration from the latest 2.3 version.
During this process, I encountered issues with the Sieve filters, particularly those related to SQL dict mappings.
The previous (2.3) configuration looked like this and worked:
|map { pattern = priv/sieve/name/$script_nametable = sieve_before username_field = username value_field = idfields { script_name = $script_name} } map { pattern = priv/sieve/data/$idtable = sieve_before username_field = username value_field = script_data fields { id= $id} } |
This resulted in the following SQL queries on the MySQL server:
|2025-08-1511:01:29.237511SELECTid FROMsieve_after WHEREscript_name ='active'ANDusername ='frittenjonas@derlinkman.de'2025-08-1511:01:29.236416SELECTid FROMsieve_before WHEREscript_name ='active'ANDusername ='frittenjonas@derlinkman.de'|
As you can see, there are SQL mappings for |sieve_before| and |sieve_after|, alongside a local file loaded prior to the SQL settings, as they are user-based.
In Dovecot 2.3, everything worked and the scripts were executed. In 2.4, however, they no longer run.
I adapted the configuration for dict SQL mapping for Sieve filters according to the documentation:
|dict_mappriv/sieve/name/$script_name{ sql_table= sieve_before username_field = username value_field id { } # The script name field in the table to querykey_fieldscript_name { value= $script_name} } dict_map priv/sieve/data/$id{ sql_table= sieve_before username_field = username value_field script_data { } key_fieldid { value= $id} } |
This also results in the dict proxy querying the database with the same pattern as before:
|2025-08-1511:11:47.175184SELECTid FROMsieve_after WHEREscript_name ='active'ANDusername ='frittenjonas@derlinkman.de'2025-08-1511:11:47.172952SELECTid FROMsieve_before WHEREscript_name ='active'ANDusername ='frittenjonas@derlinkman.de'2025-08-1511:11:47.155786SELECTid FROMsieve_after WHEREscript_name ='active'ANDusername ='frittenjonas@derlinkman.de'2025-08-1511:11:47.136030SELECTid FROMsieve_before WHEREscript_name ='active'ANDusername ='frittenjonas@derlinkman.de'|
However, unlike in 2.3, it now queries the DB twice.
In the Sieve debug logs, I see the following:
Notably:
|Aug 1512:22:2443664c142e0a dovecot: lmtp(frittenjonas@derlinkman.de)<2407><mPFNN2AKn2hnCQAAhwrv7A>: Debug: Localdelivery failed: Temporarily unable toaccessnecessary Sieve scripts |
This line concerns me.
Here are the current Sieve script declarations:
|sieve_script before{ type= beforedriver = file path= /var/vmail/sieve/global_sieve_before.sieve } sieve_script before2 { type= beforedriver = dict name= active dict proxy { name= sieve_before sieve_script_bin_path = /var/vmail/sieve_before_bindir } } sieve_script after{ type= afterdriver = file path= /var/vmail/sieve/global_sieve_after.sieve } sieve_script after2 { type= afterdriver = dict name= active dict proxy { name= sieve_after sieve_script_bin_path = /var/vmail/sieve_after_bindir } } # Personal scripts sieve_script personal { type= personal driver = file path= ~/sieve active_path = ~/.dovecot.sieve } |
The dict proxy configuration, pointing to the dict_map SQL query above, looks like this:
|dict sieve_after { driver = sql!include/etc/dovecot/sql/dovecot-dict-sql-sieve_after.conf } dict sieve_before { driver = sql!include/etc/dovecot/sql/dovecot-dict-sql-sieve_before.conf } |
Thanks for your guidance.
Kind regards
Niklas Meyer
Maintainer of the mailcow project
Hello everyone,
I am currently working on porting the Dovecot 2.4 configuration from the latest 2.3 version.
During this process, I encountered issues with the Sieve filters, particularly those related to SQL dict mappings.
The previous (2.3) configuration looked like this and worked:
map { pattern = priv/sieve/name/$script_name table = sieve_before username_field = username value_field = id fields { script_name = $script_name } }
map { pattern = priv/sieve/data/$id table = sieve_before username_field = username value_field = script_data fields { id = $id } }
This resulted in the following SQL queries on the MySQL server:
2025-08-15 11:01:29.237511 SELECT id FROM sieve_after WHERE script_name = 'active' AND username = '[1]frittenjonas@derlinkman.de' 2025-08-15 11:01:29.236416 SELECT id FROM sieve_before WHERE script_name = 'active' AND username = '[2]frittenjonas@derlinkman.de'
As you can see, there are SQL mappings for sieve_before and sieve_after, alongside a local file loaded prior to the SQL settings, as they are user-based.
In Dovecot 2.3, everything worked and the scripts were executed. In 2.4, however, they no longer run.
I adapted the configuration for dict SQL mapping for Sieve filters according to the documentation:
dict_map priv/sieve/name/$script_name { sql_table = sieve_before username_field = username value_field id { }
The script name field in the table to query
key_field script_name { value = $script_name } }
dict_map priv/sieve/data/$id { sql_table = sieve_before username_field = username value_field script_data { } key_field id { value = $id } }
This also results in the dict proxy querying the database with the same pattern as before:
2025-08-15 11:11:47.175184 SELECT id FROM sieve_after WHERE script_name = 'active' AND username = '[3]frittenjonas@derlinkman.de' 2025-08-15 11:11:47.172952 SELECT id FROM sieve_before WHERE script_name = 'active' AND username = '[4]frittenjonas@derlinkman.de' 2025-08-15 11:11:47.155786 SELECT id FROM sieve_after WHERE script_name = 'active' AND username = '[5]frittenjonas@derlinkman.de' 2025-08-15 11:11:47.136030 SELECT id FROM sieve_before WHERE script_name = 'active' AND username = '[6]frittenjonas@derlinkman.de'
However, unlike in 2.3, it now queries the DB twice.
In the Sieve debug logs, I see the following:
[7]https://pastebin.com/PTKkLsDQ
Notably:
Aug 15 12:22:24 43664c142e0a dovecot: lmtp([8]frittenjonas@derlinkman.de)<2407><mPFNN2AKn2hnCQAAhwrv7A>: Debug: Local delivery failed: Temporarily unable to access necessary Sieve scripts
This line concerns me.
Here are the current Sieve script declarations:
sieve_script before { type = before driver = file path = /var/vmail/sieve/global_sieve_before.sieve }
sieve_script before2 { type = before driver = dict name = active dict proxy { name = sieve_before sieve_script_bin_path = /var/vmail/sieve_before_bindir } }
sieve_script after { type = after driver = file path = /var/vmail/sieve/global_sieve_after.sieve }
sieve_script after2 { type = after driver = dict name = active dict proxy { name = sieve_after sieve_script_bin_path = /var/vmail/sieve_after_bindir } }
Personal scripts
sieve_script personal { type = personal driver = file path = ~/sieve active_path = ~/.dovecot.sieve }
The dict proxy configuration, pointing to the dict_map SQL query above, looks like this:
dict sieve_after { driver = sql !include /etc/dovecot/sql/dovecot-dict-sql-sieve_after.conf }
dict sieve_before { driver = sql !include /etc/dovecot/sql/dovecot-dict-sql-sieve_before.conf }
Thanks for your guidance.
Kind regards
Niklas Meyer
Maintainer of the mailcow project
References
Visible links
- mailto:frittenjonas@derlinkman.de
- mailto:frittenjonas@derlinkman.de
- mailto:frittenjonas@derlinkman.de
- mailto:frittenjonas@derlinkman.de
- mailto:frittenjonas@derlinkman.de
- mailto:frittenjonas@derlinkman.de
- https://pastebin.com/PTKkLsDQ
- mailto:frittenjonas@derlinkman.de
On 26/08/2025 10:30, niklas.meyer--- via dovecot wrote:
No one has a clue here? Did no one use Sieve Mysql Maps?
dovecot mailing list --dovecot@dovecot.org To unsubscribe send an email todovecot-leave@dovecot.org
Hi Niklas
I'm not using Sieve Mysql maps, but I did take a look at the output you posted.
In your debug log I can see two lookups for before2 and for after2, e.g.
Aug 15 12:22:24 43664c142e0a dovecot: lmtp(frittenjonas@derlinkman.de)<2407><mPFNN2AKn2hnCQAAhwrv7A>: Debug: sieve: storage before2: dict: dict(proxy): Looking up 'priv/sieve/name/active'
Aug 15 12:22:24 43664c142e0a dovecot: lmtp(frittenjonas@derlinkman.de)<2407><mPFNN2AKn2hnCQAAhwrv7A>: Debug: sieve: storage before2: dict: dict(proxy): Looking up (async) 'priv/sieve/name/active'
Not sure what governs async vs. non async or why there are two lookups. What I did notice is that the before2 lookups gave "found" each time, but after2 gave "not found" each time. I think that is the cause of the overall failure you then got on sieve.
- Aug 15 12:22:24 43664c142e0a dovecot: lmtp(frittenjonas@derlinkman.de)<2407><mPFNN2AKn2hnCQAAhwrv7A>: Debug: sieve: storage after2: dict: dict(proxy): Lookup finished for 'priv/sieve/name/active': not found
- Aug 15 12:22:24 43664c142e0a dovecot: lmtp(frittenjonas@derlinkman.de)<2407><mPFNN2AKn2hnCQAAhwrv7A>: Debug: sieve: storage after2: dict: dict(proxy): Lookup finished for 'priv/sieve/name/active': not found
- Aug 15 12:22:24 43664c142e0a dovecot: lmtp(frittenjonas@derlinkman.de)<2407><mPFNN2AKn2hnCQAAhwrv7A>: Debug: sieve: storage after2: dict: script 'active': Script 'active' not found at path priv/sieve/name/active
maybe the queries are not returning the expected data.
best regards
John
On 26/08/2025 10:30, niklas.meyer--- via dovecot wrote:
No one has a clue here? Did no one use Sieve Mysql Maps?
dovecot mailing list -- [1]dovecot@dovecot.org To unsubscribe send an email to [2]dovecot-leave@dovecot.org
Hi Niklas
I'm not using Sieve Mysql maps, but I did take a look at the output you posted.
In your debug log I can see two lookups for before2 and for after2, e.g.
1. Aug 15 12:22:24 43664c142e0a dovecot:
lmtp([3]frittenjonas@derlinkman.de)<2407><mPFNN2AKn2hnCQAAhwrv7A>:
Debug: sieve: storage before2: dict: dict(proxy): Looking up
'priv/sieve/name/active'
1. Aug 15 12:22:24 43664c142e0a dovecot:
lmtp([4]frittenjonas@derlinkman.de)<2407><mPFNN2AKn2hnCQAAhwrv7A>:
Debug: sieve: storage before2: dict: dict(proxy): Looking up (async)
'priv/sieve/name/active'
1.
Not sure what governs async vs. non async or why there are two lookups. What I did notice is that the before2 lookups gave "found" each time, but after2 gave "not found" each time. I think that is the cause of the overall failure you then got on sieve.
1. Aug 15 12:22:24 43664c142e0a dovecot:
lmtp([5]frittenjonas@derlinkman.de)<2407><mPFNN2AKn2hnCQAAhwrv7A>:
Debug: sieve: storage after2: dict: dict(proxy): Lookup finished for
'priv/sieve/name/active': not found
1. Aug 15 12:22:24 43664c142e0a dovecot:
lmtp([6]frittenjonas@derlinkman.de)<2407><mPFNN2AKn2hnCQAAhwrv7A>:
Debug: sieve: storage after2: dict: dict(proxy): Lookup finished for
'priv/sieve/name/active': not found
1. Aug 15 12:22:24 43664c142e0a dovecot:
lmtp([7]frittenjonas@derlinkman.de)<2407><mPFNN2AKn2hnCQAAhwrv7A>:
Debug: sieve: storage after2: dict: script 'active': Script 'active'
not found at path priv/sieve/name/active
maybe the queries are not returning the expected data.
best regards
John
References
Visible links
- mailto:dovecot@dovecot.org
- mailto:dovecot-leave@dovecot.org
- mailto:frittenjonas@derlinkman.de
- mailto:frittenjonas@derlinkman.de
- mailto:frittenjonas@derlinkman.de
- mailto:frittenjonas@derlinkman.de
- mailto:frittenjonas@derlinkman.de
Hi John,
thanks for your reply.
The person does not have an after2 script with the name active, that's why the output says: not found.
I can see dovecot compiling the script and creating the svbin file but it still says: Temporarily unable to locate sieve scripts.
John! You are the best and you were right.
I tried debugging it a bit deeper and look:
Dovecot now awaits a script there, if none is present it will stop the sieve processing in general, which is bad, as in our use case these scripts are optional and setup by the Admins via external UI.
The behavior of 2.3 was, that if it did not found another after or before script besides the global ones, it was only executing them, not stopping the complete Sieve filter process.
So therefore: Is there an option reactivating this old behaviour (such as skip_empty = yes) or is this a bug?
Maybe the devs can tell this?
On 28/08/2025 10:44, niklas.meyer--- via dovecot wrote:
John! You are the best and you were right.
I tried debugging it a bit deeper and look:
Dovecot now awaits a script there, if none is present it will stop the sieve processing in general, which is bad, as in our use case these scripts are optional and setup by the Admins via external UI.
The behavior of 2.3 was, that if it did not found another after or before script besides the global ones, it was only executing them, not stopping the complete Sieve filter process.
So therefore: Is there an option reactivating this old behaviour (such as skip_empty = yes) or is this a bug?
Maybe the devs can tell this?
dovecot mailing list -- dovecot@dovecot.org To unsubscribe send an email to dovecot-leave@dovecot.org
Hi Niklas
in the channgelog I can see that function lda_sieve_multiscript_get_scripts() was refactored and updates were done about error handling. It is possible that this behaviour was inadvertently introduced during that work, but I'll leave further comment to the developers.
John
This looks a lot like a bug. Will investigate..
Op 15-8-2025 om 12:29 schreef Niklas Meyer via dovecot:
Hello everyone, I am currently working on porting the Dovecot 2.4 configuration from the latest 2.3 version. During this process, I encountered issues with the Sieve filters, particularly those related to SQL dict mappings. The previous (2.3) configuration looked like this and worked:
map { pattern = priv/sieve/name/$script_name table = sieve_before username_field = username value_field = id fields { script_name = $script_name } }
map { pattern = priv/sieve/data/$id table = sieve_before username_field = username value_field = script_data fields { id = $id } }
This resulted in the following SQL queries on the MySQL server:
2025-08-15 11:01:29.237511 SELECT id FROM sieve_after WHERE script_name = 'active' AND username = '[1]frittenjonas@derlinkman.de' 2025-08-15 11:01:29.236416 SELECT id FROM sieve_before WHERE script_name = 'active' AND username = '[2]frittenjonas@derlinkman.de'
As you can see, there are SQL mappings for sieve_before and sieve_after, alongside a local file loaded prior to the SQL settings, as they are user-based. In Dovecot 2.3, everything worked and the scripts were executed. In 2.4, however, they no longer run. I adapted the configuration for dict SQL mapping for Sieve filters according to the documentation:
dict_map priv/sieve/name/$script_name { sql_table = sieve_before username_field = username value_field id { }
# The script name field in the table to query key_field script_name { value = $script_name }
}
dict_map priv/sieve/data/$id { sql_table = sieve_before username_field = username value_field script_data { } key_field id { value = $id } }
This also results in the dict proxy querying the database with the same pattern as before:
2025-08-15 11:11:47.175184 SELECT id FROM sieve_after WHERE script_name = 'active' AND username = '[3]frittenjonas@derlinkman.de' 2025-08-15 11:11:47.172952 SELECT id FROM sieve_before WHERE script_name = 'active' AND username = '[4]frittenjonas@derlinkman.de' 2025-08-15 11:11:47.155786 SELECT id FROM sieve_after WHERE script_name = 'active' AND username = '[5]frittenjonas@derlinkman.de' 2025-08-15 11:11:47.136030 SELECT id FROM sieve_before WHERE script_name = 'active' AND username = '[6]frittenjonas@derlinkman.de'
However, unlike in 2.3, it now queries the DB twice. In the Sieve debug logs, I see the following: [7]https://pastebin.com/PTKkLsDQ Notably:
Aug 15 12:22:24 43664c142e0a dovecot: lmtp([8]frittenjonas@derlinkman.de)<2407><mPFNN2AKn2hnCQAAhwrv7A>: Debug: Local delivery failed: Temporarily unable to access necessary Sieve scripts
This line concerns me. Here are the current Sieve script declarations:
sieve_script before { type = before driver = file path = /var/vmail/sieve/global_sieve_before.sieve }
sieve_script before2 { type = before driver = dict name = active dict proxy { name = sieve_before sieve_script_bin_path = /var/vmail/sieve_before_bindir } }
sieve_script after { type = after driver = file path = /var/vmail/sieve/global_sieve_after.sieve }
sieve_script after2 { type = after driver = dict name = active dict proxy { name = sieve_after sieve_script_bin_path = /var/vmail/sieve_after_bindir } }
Personal scripts
sieve_script personal { type = personal driver = file path = ~/sieve active_path = ~/.dovecot.sieve }
The dict proxy configuration, pointing to the dict_map SQL query above, looks like this:
dict sieve_after { driver = sql !include /etc/dovecot/sql/dovecot-dict-sql-sieve_after.conf }
dict sieve_before { driver = sql !include /etc/dovecot/sql/dovecot-dict-sql-sieve_before.conf }
Thanks for your guidance. Kind regards Niklas Meyer Maintainer of the mailcow project
References
Visible links 1. mailto:frittenjonas@derlinkman.de 2. mailto:frittenjonas@derlinkman.de 3. mailto:frittenjonas@derlinkman.de 4. mailto:frittenjonas@derlinkman.de 5. mailto:frittenjonas@derlinkman.de 6. mailto:frittenjonas@derlinkman.de 7. https://pastebin.com/PTKkLsDQ 8. mailto:frittenjonas@derlinkman.de
dovecot mailing list -- dovecot@dovecot.org To unsubscribe send an email to dovecot-leave@dovecot.org
participants (4)
-
John Fawcett
-
Niklas Meyer
-
niklas.meyer@tinc.gmbh
-
Stephan Bosch