Mise en place de Sieve dans une plate-forme de courrier électronique basée sur Exim4, Dovecot et Roundcube sous Debian🔗

Posted by Médéric Ribreux 🗓 In blog/ Debian/

#auto-hébergement #debian

Introduction

Ah, le courrier électronique, son utilisation est simple et quasi-universelle mais il existe tellement d'options et de fonctionnalités à ajouter à ce monument d'Internet qu'on oublie à quel point que faire fonctionner une plate-forme de courrier électronique requière de sérieuses compétences.

Aujourd'hui, nous allons mettre en place une technologie de filtrage au niveau du serveur pour filtrer les courriers en amont, en fonction des besoins de chaque utilisateur. Mission pas facile mais que nous allons néanmoins relever grâce à la technologie Sieve.

Récapitulatif de ce qu'il faut mettre en place

Exim4 propose la gestion de Sieve mais à un niveau assez bas: un fichier de filtre doit être déposé dans le répertoire de l'utilisateur pour qu'Exim le gère correctement. Mais, je pense que cette fonctionnalité n'est pas assez user-friendly.

On peut également implémenter Sieve du côté du serveur IMAP mais cela implique d'utiliser un service de délivrance de courrier et que ce service soit assuré par le serveur IMAP lui même. Dans le monde du courrier électronique, il existe deux grands types de service de délivrance de courrier "IMAP": LDA et LMTP. Nous retiendrons LMTP qui est plus "moderne" et surtout mieux implémenté dans Dovecot que LDA (qui repose sur un binaire externe).

Bien entendu, il faut dire au MTA qu'il doit utiliser ce service LMTP, il faudra donc modifier la configuration d'Exim4.

Une fois LMTP activé, on pourra mettre en place la gestion de Sieve dans Dovecot. Néanmoins, le problème sera identique à celui d'Exim: il reste à fabriquer les fichiers de filtres et à les déposer sur le serveur…

Heureusement, il existe un service dédié à ça: ManageSieve. Il en existe une implémentation dans Dovecot que nous allons installer et configurer.

Enfin, si on souhaite que les filtres soient personnalisés, il reste à offrir une interface permettant de les déposer depuis le Webmail. C'est ce qui est permis par l'extensions ManageSieve de Roundcube et que nous allons également mettre en place.

On le voit, il y a du boulot en perspective… Commençons dès à présent et pas à pas !

Installation de LMTP pour Dovecot

Avant de commencer, il nous faut un serveur LMTP. Il existe une extension Dovecot qui fait très bien ce travail.

Installation

Sous Debian, c'est assez simple:

# apt install dovecot-lmtpd

Le paquet fait moins d'1Mo, pas de problème sur un PlugComputer.

Configuration

Pour configurer correctement ce mode de transport du courrier électronique, il ne faut pas oublier quelle est notre cible. En effet, nous voulons qu'Exim utilise le service LMTP pour transmettre les courriers électroniques qui seront ensuite gérés par Dovecot, lequel appliquera alors les filtres Sieve.

L'activation du protocole LMTP se fait dans le fichier maître de configuration, à savoir /etc/dovecot/conf.d/10-master.conf:

# Configuration du service LMTP
service lmtp {
  # On active le protocole LMTP sur une socket UNIX
  unix_listener lmtp {
    #mode = 0666
  }

  # On désactive le protocole LMTP par TCP
  #inet_listener lmtp {
    # Avoid making LMTP visible for the entire internet
    #address =
    #port = 
  #}

  # On va réserver 2 processus pour LMTP
  process_min_avail = 2

  # On veut que LMTP loggue les erreurs
  executable = lmtp -L
}

La configuration fine du protocole LMTP se fait dans le fichier /etc/dovecot/conf.d/20-ltmtp.conf:

##
## Configuration LMTP
##

# Pas de proxy LMTP
lmtp_proxy = no

# Pour les alias délimités, on va poser les courriels dans la 
# boîte finale et non dans la boîte aliasée.
lmtp_save_to_detail_mailbox = no

# Pas de vérification de quota
lmtp_rcpt_check_quota = no

# Toujours écrire dans la boîte aux lettres finale
# et non dans la boîte aliasée.
lmtp_hdr_delivery_address = final

protocol lmtp {
  # Les extensions gérées par lmtp
  mail_plugins = $mail_plugins
  # Le fichier de log spécifique
  info_log_path = /var/log/dovecot/dovecot-lmtp.log
  # Il faut enlever la partie du domaine pour nommer nos utilisateurs
  auth_username_format = %n
}

Intégration de LMTP dans Exim4

Maintenant que nous disposons d'un service LMTP, il reste à le faire utiliser par Exim. Par défaut, au moins, dans ma configuration simple d'Exim, j'utilise un mode de délivrance de courrier assez basique: Exim pose le message sous forme de fichier dans une arborescence Maildir. Il s'agit du transport maldir_home.

Pour mettre en place LMTP dans Exim, vous devrez configurer un router dédié ainsi qu'un transport vers le service. Nous allons placer ce transport dans le fichier /etc/exim4/conf.d/tranport/30_exim4-config_dovecot_lmtp:

dovecot_lmtp:
	driver = lmtp
	socket = /var/run/dovecot/lmtp
	#maximum number of deliveries per batch, default 1
	batch_max = 200
	# on supprime les suffixes/préfixes
	rcpt_include_affixes = false

Il reste ensuite à utiliser ce transport. Le moyen le plus simple consiste à utiliser le fichier de macros fourni par Debian: /etc/exim4/update-exim4.conf.conf et de modifier la variable dc_localdelivery qui permet d'indiquer le transport servant à la délivrance locale des courriels. Donc mon cas, j'ai juste modifié la valeur à :

dc_localdelivery='dovecot_lmtp'

Ensuite, vous pouvez redémarrer Exim (via systemctl bien-sûr) et faire un test d'adresse (via l'option -bt) pour lire le transport qui sera utilisé.

Mise en place de Sieve dans Dovecot

Installation

Ok, LMTP est en place et fonctionnel, il nous reste à nous occuper de la configuration de Sieve dans Dovecot. Il faut juste installer le paquet dovecot-sieve et son pendant administratif dovecot-managesieved:

# apt install dovecot-sieve dovecot-managesieved

Configuration

La configuration est assez simple. Il faut juste activer le module dans le transport adapté (ce sera LMTP pour nous) et configurer le fichier de l'extension.

Vous devrez d'abord activer le module sieve de LMTP. L'action se trouve dans la conf de LMTP, /etc/dovecot/conf.d/20-lmtp.conf:

protocol lmtp {
  mail_plugins = $mail_plugins sieve
  …
}

Ensuite, l'action se déroule dans /etc/dovecot/conf.d/90-sieve.conf. Je dirais que la configuration par défaut fait très bien le job dans la majorité des cas. La ligne la plus importante étant sans doute celle qui indique l'emplacement du répertoire de filtre et le fichier par défaut:

sieve = file:~/sieve;active=~/.dovecot.sieve

Cette ligne indique que le répertoire des filtres sieve sera ~/sieve et que le filtre par défaut à utiliser sera le lien symbolique ~/.dovecot.sieve.

A ce stade, la configuration est totalement compatible avec celle de l'interface ManageSieve de Roundcube donc, pour 90% des cas, ça ne sert à rien d'aller plus loin.

Pour plus d'informations, je vous invite à lire la page de référence.

Mise en place de ManageSieve dans Dovecot

Il reste maintenant à configurer ManageSieve dans Dovecot. Nous souhaitons activer le service uniquement sur localhost car l'accès à la configuration se fera via Roundcube qui est sur la même machine, donc pas besoin de présenter un port sur une IP publique.

Vous devez simplement renseigner le fichier de configuration /etc/dovecot/conf.d/20-managesieve.conf avec le contenu suivant:

##
## Configuration ManageSieve pour Dovecot
##

# Nous activons ManageSieve
protocols = $protocols sieve

# Configuration de la connection au service
service managesieve-login {
  inet_listener sieve {
    address = ::1, 127.0.0.1
    port = 4190
  }

  #inet_listener sieve_deprecated {
  #  port = 2000
  #}

  # Number of connections to handle before starting a new process. Typically
  # the only useful values are 0 (unlimited) or 1. 1 is more secure, but 0
  # is faster. <doc/wiki/LoginProcess.txt>
  #service_count = 1

  # Number of processes to always keep waiting for more connections.
  #process_min_avail = 0

  # If you set service_count=0, you probably need to grow this.
  #vsz_limit = 64M
}

#service managesieve {
  # Max. number of ManageSieve processes (connections)
  #process_limit = 1024
#}

# Service configuration
protocol sieve {
  # Maximum ManageSieve command line length in bytes. ManageSieve usually does
  # not involve overly long command lines, so this setting will not normally
  # need adjustment
  #managesieve_max_line_length = 65536

  # Maximum number of ManageSieve connections allowed for a user from each IP
  # address.
  # NOTE: The username is compared case-sensitively.
  #mail_max_userip_connections = 10

  # Space separated list of plugins to load (none known to be useful so far).
  # Do NOT try to load IMAP plugins here.
  #mail_plugins =

  # MANAGESIEVE logout format string:
  #  %i - total number of bytes read from client
  #  %o - total number of bytes sent to client
  #managesieve_logout_format = bytes=%i/%o

  # To fool ManageSieve clients that are focused on CMU's timesieved you can
  # specify the IMPLEMENTATION capability that Dovecot reports to clients.
  # For example: 'Cyrus timsieved v2.2.13'
  #managesieve_implementation_string = Dovecot Pigeonhole

  # Explicitly specify the SIEVE and NOTIFY capability reported by the server
  # before login. If left unassigned these will be reported dynamically
  # according to what the Sieve interpreter supports by default (after login
  # this may differ depending on the user).
  #managesieve_sieve_capability =
  #managesieve_notify_capability =

  # The maximum number of compile errors that are returned to the client upon
  # script upload or script verification.
  #managesieve_max_compile_errors = 5

  # Refer to 90-sieve.conf for script quota configuration and configuration of
  # Sieve execution limits.
}

Mise en place de ManageSieve dans Roundcube

Maintenant que nous avons configuré l'infrastructure de bas niveau, il reste à configurer Roundcube. Ce dernier propose une extension bien nommée puisqu'elle s'appelle ManageSieve.

Installation

Vous devez vous assurer que vous disposez du paquet roundcube-plugins pour disposer de cette fonctionnalité:

# apt install roundcube-plugins

Mise en œuvre

Vous devez activer l'extension en vous assurant qu'elle soit dans les extensions autorisées de Roundcube. Pour cela, allez modifier le fichier /etc/roundcube/config.inc.php:

// List of active plugins (in plugins/ directory)
$config['plugins'] = array(
  'archive',
  'calendar',
  'carddav',
  'emoticons',
  'managesieve',
  'zipdownload',
  'enigma'
);

Il reste ensuite à paramétrer finement l'extension. On peut le faire en ajoutant le fichier /etc/roundcube/plugins/managesieve/config.inc.php avec le contenu suivant:

<?php
// Le port managesieve utilisé. Ce sera 4190, le port réservé.
$config['managesieve_port'] = 4190;

// L'emplacement du serveur. Dans notre configuration, ce sera
// localhost car Roundcube est sur la même bécane.
$config['managesieve_host'] = 'localhost';

// Méthode d'authentification utilisée.
// Nous n'en employons aucune car nous sommes sur la même bécane.
$config['managesieve_auth_type'] = null;

// Option pour utiliser un compte alternatif pour l\'authentification.
// Ici, nous n'utilisons pas cette option.
$config['managesieve_auth_cid'] = null;
$config['managesieve_auth_pw'] = null;

// On s'en fout d'utiliser TLS pour se connecter.
$config['managesieve_usetls'] = false;
$config['managesieve_conn_options'] = null;

// default contents of filters script (eg. default spam filter)
$config['managesieve_default'] = '/etc/dovecot/sieve/global';

// Nom du script utilisé lorsque l'utilisateur n'a rien configuré.
$config['managesieve_script_name'] = 'managesieve';

// On est en 2018, UTF-8 est partout !
$config['managesieve_mbox_encoding'] = 'UTF-8';

// Option pour Dovecot.
$config['managesieve_replace_delimiter'] = '';

// Ici, on peut désactiver des plugins Sieve.
// Ce ne sera pas le cas sur notre configuration.
$config['managesieve_disabled_extensions'] = array();

// Nous ne sommes pas en mode Debug.
$config['managesieve_debug'] = false;

// Nous désactivons les options spécifiques de Kolab.
$config['managesieve_kolab_master'] = false;

// Extension des fichiers Sieve. Ce sera .sieve pour se conformer à
// Dovecot.
$config['managesieve_filename_extension'] = '.sieve';

// Une liste de noms de scripts Sieve non présentés à l\'utilisateur.
// Dans notre cas, nous n'en avons aucun.
$config['managesieve_filename_exceptions'] = array();

// Une liste de domaine fermée pour contraindre les redirections.
// Vers d'autres domaines de courriel.
$config['managesieve_domains'] = array();

// Options pour la gestion des absences.
// Nous activons l'interface de gestion d'absences.
$config['managesieve_vacation'] = 1;

// Durée par défaut de l'absence en jours.
$config['managesieve_vacation_interval'] = 7;

// Pré-remplissage de l'adresse utilisée pour la réponse.
$config['managesieve_vacation_addresses_init'] = true;

// Méthodes utilisées pour renvoyer le message d'absence.
$config['managesieve_notify_methods'] = array('mailto');
?>

Un exemple de filtre

Ce script permet de détecter ce qui vient d'une mailing-list et de le balancer dans une boîte dédiée.

# rule:[QGIS developper mailing list]
if anyof (header :contains "from" "qgis-developer@lists.osgeo.org", header :contains "return-path" "qgis-developer@lists.osgeo.org")
{
  fileinto "QGis-dev";
}

Mais, le plus simple est d'utiliser l'interface de Rouncube, c'est plus user-friendly !

Conclusions

Bon, c'était un poil complexe quand même ! Il y en a de partout et nous avons bien travaillé quand même. Faisons le bilan:

Pas simple effectivement pour une fonctionnalité qui peut sembler assez basique. Mais c'est ainsi: le courrier électronique applique à fond le principe UNIX: une fonctionnalité = un outil dédié. C'est comme ça et ça démontre qu'il sera toujours complexe d'administrer une plate-forme de courrier électronique. Le niveau de compétences à avoir est quasi identique pour une plate-forme mono-utilisateur que pour une plate-forme d'entreprise.

Voilà de quoi ajouter à votre CV qui ne pourra que satisfaire vos futurs recruteurs…