Exercice commenté Auteur : cj-tronquet@ifrance.com Mailer java 1. Intitulé Ecrire une applet qui permette d envoyer un e-mail à partir d une page web. Cette applet devra contenir les champs From:, To:, Subject:, et le texte du message. Un bouton déclenchera l envoi du mail. 2. Approche Nous allons faire communiquer notre applet avec un serveur SMTP (Simple Mail Transfer Protocol). Ce protocole est le plus utilisé pour transmettre des e-mails. Du fait des restrictions de sécurité de Java, l applet ne peut qu établir une connection entre serveurs résident sur la même machine que l applet. Notre applet sera donc localisée sur une machine qui héberge également un serveur SMTP. 2.1. Le protocole SMTP Voici une session type de communication entre un client et un serveur SMTP : - le client ouvre un socket sur le port 25 du serveur SMTP (port par défaut). - Pour accord, le serveur SMTP renvoie une chaîne qui commence par 220. - Le client envoie la commande HELO suivie par son nom de domaine. - Pour accord, le serveur répond avec une chaîne commençant par 250. - Le client envoie la chaîne MAIL FROM: suivie de l adresse de l émetteur. - Si le serveur accepte cette adresse, il répond par le code 250. - Le client envoie la chaîne RCPT TO: suivie de l adresse du destinataire. - Si vous avez suivi, le serveur accepte en envoyant le code 250. - Puis le client envoie la commande DATA. - Le serveur envoie alors le code 354. - Le client peut alors envoyer son mail à proprement parler. Pour annoncer au serveur que le message est terminé, il faut envoyer le caractère «.» seul sur une ligne. - Le serveur répond alors par 250 si il a bien reçu le message. - Le client envoie la commande QUIT pour demander la fin de la connexion. - Le serveur envoie alors le code 221 et ferme la communication. 2.2. Fonctions et classes utiles La classe Socket permet d effectuer la liaison entre le client et le serveur. Les streams d écriture et de lecture sur le socket sont PrintStream et DataInputStream. Pour l écriture, on utilisera les méthodes println et flush de la classe PrintStream et pour la lecture, la méthode readline de DataInputStream. A des fins de propreté et de solidité de notre applet, on pourra utiliser les classes d exceptions adaptées à notre cas : ProtocolException, UnknownHostException, et IOException.
C est là que l on voit clairement l avantage de Java sur d autres langages : sa simplicité. Il suffit seulement des quelques fonctions ci-dessus pour pouvoir implémenter un mailer web! 3. Solution commentée 3.1. Vue d ensemble Il nous faut tout d abord créer l environnement graphique qui permettra d écrire un e-mail. Pour cela on utilisera dans cet exercice le gestionnaire de mise en page GridBagLayout ; cela va mous permettre un positionnement précis des objets dans le cadre de l applet. Toutes ces opérations se font naturellement dans la méthode init. On va redéfinir la méthode action pour intercepter l appui sur le bouton «Envoyer». Si l evènement intercepté provient bien du bouton, alors on exécute la méthode «envoyer» qui se charge d émettre le mail vers le serveur SMTP. On va écrire la méthode Trace qui nous permettra d écrire dans la zone de message toutes les informations utiles (notamment de connexion). Si les codes que le serveur renvoie ne sont pas ceux attendus, on va générer des exceptions. Celles-ci seront traitées par la fonction appelante, en l occurrence action. 3.2. Code source Mail.java import java.applet.applet; import java.net.*; import java.io.*; import java.awt.*; public class Mail extends java.applet.applet { TextArea tmessage; // zone de texte contenant le texte du mail Button benvoie; // pour envoyer le mail TextField tsujet; // zone texte contenant le sujet TextField tto; // zone texte contenant le destinataire du message TextField tfrom; // zone texte contenant l'émetteur du message public void init() { //Positionnement des objets GridBagLayout gridbag = new GridBagLayout(); GridBagConstraints g = new GridBagConstraints(); setfont(new Font("Arial", Font.PLAIN, 12)); setlayout(gridbag); g.anchor = GridBagConstraints.NORTHEAST; g.fill = GridBagConstraints.HORIZONTAL; g.weightx = 1.0; g.weighty = 1.0; benvoie = new Button("Envoyer") ; gridbag.setconstraints(benvoie, g); add(benvoie); g.gridwidth = GridBagConstraints.RELATIVE; Label labelfrom = new Label("De :"); gridbag.setconstraints(labelfrom, g); add(labelfrom); tfrom = new TextField("") ; gridbag.setconstraints(tfrom, g); add(tfrom); benvoie = new Button("Envoyer") ; gridbag.setconstraints(benvoie, g); add(benvoie); Label labelto = new Label("à :") ; gridbag.setconstraints(labelto, g); add(labelto);
tto = new TextField("") ; gridbag.setconstraints(tto, g); add(tto); Label labelsujet = new Label("Sujet :") ; gridbag.setconstraints(labelsujet, g); add(labelsujet); tsujet = new TextField("") ; gridbag.setconstraints(tsujet, g); add(tsujet); Label labelmessage = new Label("Message :") ; gridbag.setconstraints(labelmessage, g); add(labelmessage); g.fill = GridBagConstraints.BOTH ; g.gridheight = GridBagConstraints.REMAINDER; tmessage = new TextArea("",5,40) ; gridbag.setconstraints(tmessage, g); add(tmessage); public boolean action(event evt, Object arg) { if (evt.target instanceof Button) { // si l'evt a été généré par le bouton try { envoyer( tto.gettext(), tfrom.gettext(), tsujet.gettext(), tmessage.gettext() ) ; //on écrit un message dans la zone du message catch(unknownhostexception uhe) { Trace("*** EXCEPTION: Hote inconnu: " + uhe ) ; catch(protocolexception pe) { Trace("*** EXCEPTION de protocole: " + pe ) ; catch(ioexception ioe) { Trace("*** EXCEPTION e/s: " + ioe ) ; return true ; public void envoyer( UnknownHostException { String to_address, String from_address, String ssu, String smess) throws IOException, ProtocolException, tmessage.settext("") ; //on ecrit un récapitulatif dans la zone de message Trace("+---------Envoi d'un mail-----------------------+") ; Trace(" De: " + from_address) ; Trace(" à: " + to_address) ; Trace(" Sujet: " + ssu) ; Trace("+-----------------------------------------------+"); Trace(" Message : " + smess) ; Trace("+-----------------------------------------------+") ; Socket socket; DataInputStream in; PrintStream out; String hote; String str; // Le stream de lecture du Socket // Le stream d'ecriture du Socket // Identification du poste // Pour la lecture de donnees // Identification du poste hote = InetAddress.getLocalHost().toString() ; // On aurait tout aussi bien pu spécifier explicitement l'hôte // ex: www.wanadoo.fr
// Ouverture du socket (connection au serveur SMTP) // et des streams de lecture et d'ecriture socket = new Socket(getDocumentBase().getHost(), 25); in = new DataInputStream(socket.getInputStream()); out = new PrintStream(socket.getOutputStream()); // lecture du message initial if (!str.startswith("220")) throw new ProtocolException(str); while (str.indexof('-') == 3) { if (!str.startswith("220")) throw new ProtocolException(str); // Envoie de HELO au serveur SMTP out.println( "HELO " + hote ); // On est connecte au serveur... // Envoi des infos d'émetteur et de destinataire out.println( "MAIL FROM: " + from_address ); out.println( "RCPT TO: " + to_address ); // On est pret a envoyer les donnees out.println( "DATA" ); if (!str.startswith("354")) throw new ProtocolException(str); //Texte du message // Emetteur - Destinataire - Sujet out.println("from: " + from_address); out.println("to: " + to_address); out.println( "Subject: " + ssu + "\n" ); // lignes non obligatoire mais fortement recommandées, sous peine de refus des mails out.println("comment: Unauthenticated sender"); out.println("x-mailer: Simple tsmtp"); out.println(""); out.println( smess ) ; out.println(".") ; out.println("quit"); out.flush(); in.close() ; Trace("Fin du mail...") ;
socket.close(); return ; public void Trace(String str) { tmessage.appendtext(str + "\n"); //penser au caractère de fin de ligne "\n" return ; public static void main(string args[]) { Frame f = new Frame("Mailer web"); Mail mailer = new Mail(); mailer.init(); mailer.start(); f.add("center", mailer); f.resize(350, 200); f.pack(); f.show();