Intéressé par des cours d'informatique en ligne ?
Visitez mon nouveau site https://www.yesik.it !

Apache James est un serveur de courrier électronique écrit en Java. Mais c'est aussi un container de mailet. Qu'est-ce que ça veut dire? Simplement que James peut charger des classes Java que vous avez écrites pour associer un traitement personnalisé à la réception d'un courrier électronique. Autrement dit, une mailet est l'équivalent pour le mail d'une servlet pour les requêtes web. Tout un monde de possibilités s'ouvre à nous, non? Dans cet article, nous allons voir comment créer une mailet et configurer Apache James pour l'utiliser.

Les bases

Dans le principe, ajouter une nouvelle mailet à James se fait en 3 étapes:

  1. Tout d'abord, il faut coder et compiler la mailet;
  2. Ensuite, il faut la déployer pour que James puisse la trouver;
  3. Enfin il faut configurer James pour qu'il sache quand et sur quel mail l'invoquer.

Codage

Concrètement, une mailet pour Apache James est simplement une classe qui met en oeuvre l'interface org.apache.mailet.Mailet. Celle-ci contient un certain nombre de méthodes détaillées dans la documentation de James (voir javadoc). Dans l'exemple ci-dessous, je me contente du strict minimum en ne mettant réellement en oeuvre que la méthode service. Et encore, de manière triviale! Les autres méthodes ne sont définies que pour se conformer à l'interface – mais dans cet exemple, elles ne font rien:

package fr.chicoree.mailets;
 
import javax.mail.MessagingException;
 
import org.apache.mailet.Mail;
import org.apache.mailet.Mailet;
import org.apache.mailet.MailetConfig;
 
public class MyMailet implements Mailet {
    @Override
    public void destroy() {
    }
 
    @Override
    public MailetConfig getMailetConfig() {
        return null;
    }
 
    @Override
    public String getMailetInfo() {
        return null;
    }
 
    @Override
    public void init(MailetConfig config) throws MessagingException {
    }
 
    @Override
    public void service(Mail mail) throws MessagingException {
        System.err.println("reveiced " + mail.getMessage().getSubject());
    }
}

Pour compiler cette classe, vous aurez besoin des bibliothèques mailet-api-x.y.jar et mail-x.y.z.jar correspondant à la version de James que vous avez installée. Celles-ci sont fournies avec James dans le fichier /path/to/james/apps/james.sar. Il faudra donc les extraire et les placer dans votre CLASSPATH pour pouvoir compiler votre mailet:

sh$ jar xvf /path/to/james-2.3.1/apps/james.sar SAR-INF/lib
  created: SAR-INF/lib/
 inflated: SAR-INF/lib/james-2.3.1.jar
 inflated: SAR-INF/lib/mailet-2.3.jar
 inflated: SAR-INF/lib/mailet-api-2.3.jar
 inflated: SAR-INF/lib/activation-1.1.1.jar
 inflated: SAR-INF/lib/bcmail-jdk14-129-workaround.jar
...
 inflated: SAR-INF/lib/jakarta-oro-2.0.8.jar
 inflated: SAR-INF/lib/mail-1.4.1.jar
sh$ javac -cp .:SAR-INF/lib/mailet-api-2.3.jar:SAR-INF/lib/mail-1.4.1.jar \
          fr/chicoree/mailets/MyMailet.java
sh$ jar cf MyMailet.jar fr/chicoree/mailets/MyMailet.class
Les mailets empaquetées dans un JAR doivent être déployées en les copiant dans le répertoire SAR-INF/lib. Vous pouvez aussi plus simplement déployer les classes compilées (fichiers .class) en les copiant dans SAR-INF/classes.

Déploiement

Si coder et compiler la mailet est la première étape. La seconde est de la déployer en copiant la mailet compilée dans le répertoire adéquat:

sh$ cd /path/to/james-2.3.1/apps/james
sh$ mkdir SAR-INF/lib # Si nécessaire
sh$ cp /path/to/mymailet.jar SAR-INF/lib

Configuration

Enfin, il faut configurer James pour qu'il sache où trouver notre mailet et à quel moment l'invoquer. Cela se fait dans le fichier de configuration SAR-INF/config.xml. Vous devrez y localiser les éléments suivants:

mailetpackages
Qui indique à James les packages Java qui contient les mailets utilisées par cette configuration de James
spoolmanager
qui définit l'ordre et la nature des traitements appliqués par James aux courriers entrants. C'est en quelque sorte là que se code la logique de votre serveur de courrier. Pour faciliter l'organisation des traitements, ceux-ci sont groupés en processeurs (processor). C'est un peu l'équivalent dans James d'une fonction ou d'une procédure dans un langage structuré. Plus formellement, les processeurs sont les états dans l'automate état-transition qui représente les étapes par lesquelles peut passer un message entrant. Le point de départ de ce graphe est le processeur nommé root (<processor name='root'><!-- ... ---></processor>).

Ainsi, pour exécuter notre mailet sur tous les courriers entrants, nous pouvons utiliser la configuration suivante:

   <!-- Set the Java packages from which to load mailets and matchers -->
   <mailetpackages>
      <mailetpackage>org.apache.james.transport.mailets</mailetpackage>
      <mailetpackage>org.apache.james.transport.mailets.smime</mailetpackage>
      <mailetpackage>fr.chicoree.mailets</mailetpackage>
   </mailetpackages>
   <!-- The James Spool Manager block  -->
   <!-- -->
   <!-- This block is responsible for processing messages on the spool. -->
   <spoolmanager>
      
      <!-- ... --->
      
      <processor name="root">
         <mailet match="All" class="MyMailet" />

         <!-- This mailet redirects mail for the user 'postmaster' at any local domain to -->
         <!-- the postmaster address specified for the server. The postmaster address -->
         <!-- is required by rfc822. Do not remove this mailet unless you are meeting -->
         <!-- this requirement through other means (e.g. a XML/JDBCVirtualUserTable mailet) -->
         <mailet match="All" class="PostmasterAlias"/>

Comme après chaque modification de la configuration, reste à (re)lancer James:

sh$ sudo JAVA_HOME=$JAVA_HOME bin/run.sh
Using PHOENIX_HOME:   /home/sylvain/james-2.3.1
Using PHOENIX_TMPDIR: /home/sylvain/james-2.3.1/temp
Using JAVA_HOME:      /usr/lib/jvm/java-6-sun-1.6.0.12
Running Phoenix: 

Phoenix 4.2

James Mail Server 2.3.1
Remote Manager Service started plain:4555
POP3 Service started plain:110
SMTP Service started plain:25
NNTP Service started plain:119
FetchMail Disabled

Et pour tester, il suffit d'envoyer un mail via notre serveur de messagerie. Par exemple, si vous envoyez un message avec Hello mailet en sujet en utilisant James comme MTA (Mail Transfert Agent – Logiciel de transfert de courrier électronique
(plus))
vous devriez voir apparaître le message généré par notre mailet sur la console de James:

James Mail Server 2.3.1
Remote Manager Service started plain:4555
POP3 Service started plain:110
SMTP Service started plain:25
NNTP Service started plain:119
FetchMail Disabled
reveiced Hello mailet

Mailet, matchers et processors

Quand un message arrive sur Apache James, celui-ci est pris en charge par les différentes mailets du processeur root dont le matcher correspond. La maillet ToProcessor permet de transférer certains mails vers un autre processeur.

Dans la configuration actuelle, pour activer notre mailet, il suffit d'envoyer un mail via James. Il n'est absolument pas nécessaire que James gère le compte mail du destinataire. Autrement dit, tout mail passant par notre serveur de messagerie sera traité par notre mailet.

La raison pour laquelle James se compte ainsi, c'est que nous avons configuré notre mailet dans le processeur root et avec le matcher All:

<!-- ... -->
      <processor name="root">
         <mailet match="All" class="MyMailet" />

Nous l'avons déjà dit, le processeur dans James est simplement un groupe de mailets à activer quand un message arrive. Le matcher quand à lui permet de filtrer les mails auxquels s'appliquent chaque mailet. Comme son nom l'indique, le matcher All permet d'appliquer une mailet à tous les mails traités par le processeur actuel.

Remarque:

Tout comme pour la maillet, le matcher est désigné par un nom de classe Java. Vous pouvez donc si vous le désirez créer vos propres matchers pour filtrer certains messages spécifiques à votre domaine.

La mailet ToProcesseur est importante à connaître, puisque c'est elle qui permet de propager un message d'un processeur à l'autre. Autrement dit, c'est grâce à cette mailet que le message navigue dans le graphe des processeurs définis par la configuration de James.

A titre d'illustration, nous pourrions appliquer notre mailet uniquement aux messages destinés à un utilisateur local en remplaçant le matcher dans la configuration par RecipientIsLocal:

      <processor name="root">
         <mailet match="RecipientIsLocal" class="MyMailet" />

De la même manière, selon l'utilisation de notre mailet, il serait sans doute également plus intéressant de ne l'appliquer qu'aux messages qui ont déjà été filtrés contre le spam et les virus. En suivant la configuration de James, vous constaterez que les messages bon à transporter se retrouvent traités pas le processeur transport. On pourrait donc déplacer l'activation de notre mailet dans ce processeur:

      <processor name="transport">
         <mailet match="RecipientIsLocal" class="MyMailet" />

Conclusion

A l'issue de cet article, vous devriez vous être rendu compte, qu'il n'est pas très compliqué de modifier James pour traiter les messages entrant de manière automatisée. Nous n'avons bien sûr pas fait le tour en détail des possibilités de James. Mais au moins devriez-vous avoir une vue d'ensemble suffisante pour pouvoir vous lancer confiant dans l'écriture de votre première mailet utile!

Ressources