Si vous utilisez le MTA Exim avec une base PostgreSQL pour stocker les comptes email, vous avez peut être déjà rencontré cette erreur un matin au détour de votre paniclog :

2009-11-12 13:34:52 failed to expand "[requete de recherche utilisateur]" gave DEFER: PGSQL: query failed: ERREUR:  séquence d'octets invalide pour l'encodage « UTF8 » : 0xe76f69
HINT:  Cette erreur peut aussi survenir si la séquence d'octets ne correspond pas
au jeu de caractères attendu par le serveur, le jeu étant contrôlé par « client_encoding ».
 (PGRES_FATAL_ERROR) ([requete de recherche])

Cette erreur est due à un caractère non ASCII dans l'adresse (ce qui n'est pas formellement interdit mais qui vu la myriade de jeux de caractères existants n'est pas faisable en pratique). Généralement cela vient d'un utilisateur qui a un nom ou un prénom avec un accent ou une cédille, une adresse tirée de son nom/prénom et ne fait pas attention en la saisissant sur son site de jeux en ligne favori.

Le problème c'est que, comme la requête échoue, Exim renvoie une erreur temporaire au MTA source, qui va donc réessayer (et ça ne passera toujours pas). Conduisant le paniclog à se remplir (et personnellement j'aime pas avoir des journaux d'alerte remplis avec des trucs insignifiants vu que c'est prendre le risque de noyer des choses pertinentes dedans.

Pour éviter ça, une solution est d'indiquer à postgres le charset à utiliser lorsque l'on fait une requête. Par défaut, en tout cas sur les Debian récentes, En optant pour de l'ISO, on évite un certain nombre de problèmes (c'est pas la solution miracle mais ça évite pas mal de problèmes) :

alter user [utilisateur_sql_exim] set client_encoding = 'ISO-8859-1':

L'autre solution, qui cette fois élimine complètement le problème est d'ajouter une ACL qui va vérifier que l'adresse est bien une séquence utf8 valide. Comme l'ASCII forme un sous-ensemble d'UTF-8, on n'a pas de problème avec les adresse existantes, tout ce qui est A-Za-z.-_blablabla fonctionnera toujours. Simplement si on a un caractère non ASCII dans l'adresse, il faut qu'il soit en UTF-8. De cette façon, même si l'adresse sébastien@mondomaine.com n'existe pas, la requête SQL passera et renverra une liste de résultat vide, donc le mail sera refusé sans que le paniclog ne soit touché.

On procède en deux étapes. Tout d'abord, on crée un script qui vérifie si la chaine passée en paramètre est une chaine valide[1] :

sebastien@boiboite $ sudo cat /etc/exim4/isutf8.sh
#!/bin/bash
exec echo "$1" | /usr/bin/iconv -f UTF-8 -t UTF-8 >/dev/null 2>&1
sebastien@boiboite  $ sudo chmod +x /etc/exim4/isutf8.sh

Puis on indique à exim qu'il doit vérifier que l'adresse est bien en UTF-8. Sous Debian, avec une config exim découpée, on passe par /etc/exim4/conf.d/acl/30_exim4-config_check_rcpt et on ajoute :

  deny
    message = address is invalid UTF-8
    condition = ${run{/etc/exim4/isutf8.sh \"$local_part\"}{no}{yes}}

Avant toute ACL qui fait une requête SQL (vraissemblablemetn juste après le accept hosts = :). Toute tentative d'envoi de mail à une adresse formant une séquence UTF-8 invalide sera refusée avec le message « address is invalid UTF-8 » et le paniclog sera sauf.

Notes

[1] Merci à http://tomasz.sterna.tv/2009/03/exim4-postgresql-and-invalid-byte-sequence-for-encoding-utf8/