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

Dans cet article, nous allons voir comment envoyer un courrier électronique à partir d'un programme Java SE en utilisant l'API JavaMail.

JavaMail

JavaMail est une extension standard de Java SE. C'est à dire que les spécifications de l'API (Application Programming Interface – L'ensemble des spécifications de classes, méthodes, fonctions, constantes, etc. qui permettent d'utiliser une technologie dans un programme.) sont définies, mais elle n'est pas fournie avec le JRE, ce qui offre la possibilité pour de tierces parties de fournir leur propre implémentation. Ceci dit, Sun fournit aussi une mise en oeuvre de référence de JavaMail, qu'il est possible de télécharger à partir de l'adresse http://java.sun.com/products/javamail. C'est cette version que je vais utiliser.

Après avoir téléchargé – et décompressé l'archive de JavaMail, il convient de copier le JAR (Java ARchive – Un format d'archive utilisé dans le monde Java pour regrouper des fichiers (classes compilées, méta-données, etc.).) mail.jar à l'emplacement de votre choix (l'idéal étant de ne pas le perdre...). Pour ma part, je vais installer le tout dans /usr/local/lib:

sh# cd /usr/local/lib
sh# unzip /path/to/javamail-1.4.2.zip
sh# ln -s javamail-1.4.2 javamail

Java 1.4 et Java 5.0

Si vous utilisez une version de Java antérieure à la version 6, vous aurez aussi besoin d'une autre extension appelée JavaBeans™ Activation Framework. Ici encore, Sun fournit une mise en oeuvre de référence, disponible à l'adresse http://java.sun.com/beans/glasgow/jaf.html. Vous devrez l'installer de manière similaire à JavaMail:

sh# cd /usr/local/lib
sh# unzip /media/disk/jaf-1_1_1.zip 
sh# ln -s jaf-1_1_1.zip jaf

Premier message

Envoyer un message avec JavaMail n'est pas très compliqué. Néanmoins, il est nécessaire de comprendre un certain nombre de concepts clés. Nous allons donc détailler au fur et à mesure le code.

Session

Tout d'abord, toute application utilisant l'API JavaMail doit commencer par ouvrir une session. Dans JavaMail, la session gére les informations de configuration (nom d'utilisateur, mot de passe, hôte) nécessaires pour utiliser les fonctionnalités de JavaMail. Il ne s'agit pas d'une session au sens de connexion avec un serveur!

/* ... */
	    Properties		props	    = new Properties();
	    Session		session	    = Session.getInstance(props);

Remarque:

Les propriétés passées en argument (props) contiennent les informations nécessaires à l'API pour fonctionner. Ici, je laisse les valeurs par défaut. Notamment, cela veut dire:

  • Que le serveur de courrier (propriété mail.host) sera localhost;
  • Que le nom d'utilisateur pour accéder au serveur (propriété mail.user) sera l'utilisateur courant
  • que l'adresse de l'expéditeur (propriété mail.from) sera mail.user@mail.host.

Vous pouvez bien sûr changer ces valeurs. Par exemple, pour modifier l'adresse de l'émetteur du message, il faudrait modifier le code ainsi:

/* ... */
	    Properties		props	    = new Properties();
	    props.setProperty("mail.from", "contact@chicoree.fr");
 
	    Session		session	    = Session.getInstance(props);

Message

Dans ce premier exemple, le message contiendra uniquement du texte.

La seconde étape va être de créer le message. Ici encore, il s'agit d'un objet passif essentiellement chargé d'encapsuler des informations: sujet, destinataire, contenu, etc.

/* ... */
	    Message		message	    = new MimeMessage(session);
	    InternetAddress	recipient   = new InternetAddress("sylvain@localhost");
	    message.setRecipient(Message.RecipientType.TO, recipient);
	    message.setSubject("Hello JavaMail");
	    message.setText("JavaMail vous dit bonjour!");

Remarque:

Ici, j'utilise un message MimeMessage. Comme vous vous en doutez, cela représente un message MIME compatible avec la RFC822.

C'est le seul format de message définit par les spécifications de JavaMail. Néanmoins, chaque mise en oeuvre de JavaMail est susceptible de fournir des formats de messages spécialisés. Ainsi, la mise en oeuvre de référence fournie par Sun offre par exemple la classe com.sun.mail.smtp.SMTPMessage qui permet de régler certaines options liées à la transmission de ce message par SMTP.

Mais, dans la plupart des cas, MimeMessage est très largement suffisant. Donc autant rester dans le cadre des spécifications...

Transport

Enfin, le code le plus intéressant – et le plus actif: celui chargé de transmettre le message. Code le plus intéressant, mais aussi le plus court:

/* ... */
	    Transport.send(message);

L'appel à la méthode Transport.send ouvre une connexion avec le serveur SMTP, transmet le message, puis ferme la connexion avec le serveur.

Remarque:

Tous les paramètres de connexion sont extraits du message et de l'objet session associé.

Code complet

Voici maintenant le code complet nécessaire pour envoyer un message. En plus de ce qui a été décrit plus haut, celui-ci contient les imports nécessaires et la gestion des exceptions qui peuvent se produire:

import java.util.Properties;
 
import javax.mail.Session;
import javax.mail.Message;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.InternetAddress;
import javax.mail.Transport;
 
import javax.mail.internet.AddressException;
import javax.mail.NoSuchProviderException;
import javax.mail.MessagingException;
 
public class SendTextMessage {
    public static void main(String[] args) {
	try {
	    Properties		props	    = new Properties();
	    // props.setProperty("mail.from", "contact@chicoree.fr");
	    Session		session	    = Session.getInstance(props);
 
	    Message		message	    = new MimeMessage(session);
	    InternetAddress	recipient   = new InternetAddress("sylvain@localhost");
	    message.setRecipient(Message.RecipientType.TO, recipient);
	    message.setSubject("Hello JavaMail");
	    message.setText("JavaMail vous dit bonjour!");
 
	    Transport.send(message);
	}
	catch(NoSuchProviderException e) {
	    System.err.println("Pas de transport disponible pour ce protocole");
	    System.err.println(e);
	}
	catch(AddressException e) {
	    System.err.println("Adresse invalide");
	    System.err.println(e);
	}
	catch(MessagingException e) {
	    System.err.println("Erreur dans le message");
	    System.err.println(e);
	}
    }
}

Reste à compiler et exécuter ce code. Bien entendu, il ne faut pas oublier de modifier le CLASSPATH pour utiliser JavaMail:

sh$ export CLASSPATH=".:/usr/local/lib/javamail/mail.jar"
sh$ javac SendTextMessage.java
sh$ java SendTextMessage

Enfin, vous pouvez utiliser votre client de messagerie préféré pour vérifier que le message a bien été envoyé. Pour ma part, comme j'utilise exim comme serveur mail – et qu'il est configuré pour délivrer les messages dans ma boite mail locale, je peux utiliser mail:

sh$ mail
Mail version 8.1.2 01/15/2001.  Type ? for help.
"/var/mail/sylvain": 1 message 1 new
>N  1 sylvain@mobal      Fri Aug 14 01:24   20/640   Hello JavaMail
& 1
Message 1:
From sylvain@mobal Fri Aug 14 01:24:43 2009
Envelope-to: sylvain@localhost
Delivery-date: Fri, 14 Aug 2009 01:24:43 +0200
To: sylvain@localhost
Subject: Hello JavaMail
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
From: sylvain@mobal
Date: Fri, 14 Aug 2009 01:24:43 +0200 

JavaMail vous dit bonjour!

Message multipart

Bien envoyer un message texte seul c'est très bien, mais comment transférer une pièce jointe? C'est exactement à cela que servent les messages multipart.

Code initial

Et c'est vrai que là, JavaMail simplifie largement notre travail – puisque le code va beaucoup ressembler au code précédent:

/* ... */
            Properties          props       = new Properties();
            // props.setProperty("mail.from", "contact@chicoree.fr");
            Session             session     = Session.getInstance(props);
 
            Message             message     = new MimeMessage(session);
            InternetAddress     recipient   = new InternetAddress("sylvain@localhost");
            message.setRecipient(Message.RecipientType.TO, recipient);
            message.setSubject("Hello JavaMail");
 
            // XXX Ici inserer le contenu ''multipart'' du message
 
            Transport.send(message);

Et oui! C'est exactement le code de la première partie de cet article, à ceci près que j'ai enlevé la ligne qui définissait le contenu du message. C'est tout ce qui va changer. Et c'est sur quoi nous allons travailler.

Créer les parties

Notre message sera composé de deux parties: un texte et une image. C'est un message multipart.

Donc, pour cet exemple, je veux transférer un message contenant deux parties:

  1. Du texte
  2. et une image PNG

Créer la partie texte ressemble fortement à ce que nous avions fait dans le message non multipart:

/* ... */
		MimeBodyPart mbp1 = new MimeBodyPart();
		mbp1.setText("JavaMail vous dit bonjour!");

Quand à l'image PNG, nous allons utiliser une variante qui permet de lire un fichier:

/* ... */
		MimeBodyPart mbp2 = new MimeBodyPart();		
		String file = "/home/sylvain/HelloJavaMail.png";
		mbp2.attachFile(file);

Enfin, reste à rassembler ces deux parties, et à attacher l'ensemble au message:

/* ... */
		MimeMultipart mp = new MimeMultipart();
		mp.addBodyPart(mbp1);
		mp.addBodyPart(mbp2);
		message.setContent(mp);
Voici comment le message envoyé peut apparaître dans un client de messagerie graphique

Code complet

Pour terminer voici le code complet du programme:

import java.util.Properties;
 
import javax.mail.Session;
import javax.mail.Message;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.InternetAddress;
import javax.mail.Transport;
 
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMultipart;
 
import javax.mail.internet.AddressException;
import javax.mail.NoSuchProviderException;
import javax.mail.MessagingException;
 
import java.io.IOException;
 
public class SendMultipartMessage {
    public static void main(String[] args) {
	try {
	    Properties		props	    = new Properties();
	    // props.setProperty("mail.from", "contact@chicoree.fr");
	    Session		session	    = Session.getInstance(props);
 
	    Message		message	    = new MimeMessage(session);
	    InternetAddress	recipient   = new InternetAddress("sylvain@localhost");
	    message.setRecipient(Message.RecipientType.TO, recipient);
	    message.setSubject("Hello JavaMail");
 
	    // Partie 1: Le texte
	    MimeBodyPart mbp1 = new MimeBodyPart();
	    mbp1.setText("JavaMail vous dit bonjour!");
 
	    // Partie 2: Le fichier joint
	    MimeBodyPart mbp2 = new MimeBodyPart();
	    String file = "/home/sylvain/HelloJavaMail.png";
	    mbp2.attachFile(file);
 
	    // On regroupe les deux dans le message
	    MimeMultipart mp = new MimeMultipart();
	    mp.addBodyPart(mbp1);
	    mp.addBodyPart(mbp2);
	    message.setContent(mp);
 
	    Transport.send(message);
	}
	catch(IOException e) {
	    System.err.println("Impossible de lire le fichier joint");
	    System.err.println(e);
	}
	catch(NoSuchProviderException e) {
	    System.err.println("Pas de transport disponible pour ce protocole");
	    System.err.println(e);
	}
	catch(AddressException e) {
	    System.err.println("Adresse invalide");
	    System.err.println(e);
	}
	catch(MessagingException e) {
	    System.err.println("Erreur dans le message");
	    System.err.println(e);
	}
    }
}

Conclusion

Nous en avons maintenant terminé de ce tour d'horizon de JavaMail. Vous l'avez constaté, l'API est facile à appréhender – et aucune configuration fastidieuse n'est requise avant de pouvoir transmettre un message. Bref, il s'agit là d'un API comme on souhaiterait en voir plus.

Un dernier mot cependant: nous avons ici utilisé JavaMail pour transmettre un message. Mais cet API ne se réduit pas à cette fonctionnalité. En effet, il est tout aussi possible de consulter sa messagerie avec JavaMail. Mais ce sera pour une autre fois...