В словарях есть (к сожалению, пока недокументированная) возможность задавать составные ключи. Ключом в таком случае является кортеж (tuple) из полей произвольных типов. Если сконфигурировать ключ из одного поля типа String, получится как раз то, что нужно.
Подробнее, в вашем случае:
Задаём layout=complex_key_hashed (другой вариант complex_key_cache, по смыслу они аналогичны hashed и cache):
<layout>
<complex_key_hashed/>
</layout>
Ключ задаём не в элементе <id>, а в элементе <key>. Поля ключа задаются в таком же формате, как атрибуты словаря. В вашем случае получается:
<structure>
<key>
<attribute>
<name>_id</name>
<type>String</type>
</attribute>
</key>
...
Далее, в dictGet* в качестве ключа указываете tuple от строки:
SELECT dictGetString('my_dict', 'email', tuple('key'))