SMTPConnection.java |
package fr.umlv.ji.tcp.smtp; import java.io.*; import java.net.*; /** * Classe premettant d'envoyer un courrier électronique en utilisant * le proctocole SMTP (RFC 821). */ public class SMTPConnection { /** Port TCP par défaut des serveurs SMTP. */ public final static int SMTP_PORT = 25; /** Socket de la connexion TCP. */ private Socket s; /** Flot en écriture sur la connexion TCP. */ private PrintWriter output; /** Flot en lecture sur la connexion TCP. */ private LineNumberReader input; /** État de la connexion vers le serveur SMTP. */ private boolean connected = false; /** Adresse électronique de l'émetteur. */ private String fromAddr; /** Adresse Internet du serveur SMTP. */ InetAddress mailHost; /** Marqueur de fin de ligne pour SMTP. */ static final String EOL = "\r\n"; /** Contructeur récupérant le nom du serveur SMTP et l'adresse de courrier électronique par défaut de l'émetteur. */ public SMTPConnection() throws IOException { // Récupération du nom du serveur de mail dans la propriété // système "mail.host" String mailHostName = System.getProperty("mail.host"); // Récupération de l'adresse Internet correspondant au nom du serveur // En son absence, on utilise la machine locale comme serveur if (mailHostName==null) mailHost = InetAddress.getLocalHost(); else mailHost = InetAddress.getByName(mailHostName); // Récupération de l'adresse éléctronique de l'émetteur dans la // propriété système "user.fromaddr" fromAddr = System.getProperty("user.fromaddr"); // En son absence, on utilise <user.name>@<machine.locale> if (fromAddr==null) { fromAddr = System.getProperty("user.name"); fromAddr = fromAddr + "@" + mailHostName; } } /** Création de la connexion TCP vers le serveur SMTP et présentation du client. */ public void connect() throws IOException { // Si la connexion est déjà établie, il n'y a rien à faire if (connected) return; // Appel au constructeur de la socket, qui établit la connexion s = new Socket(mailHost,SMTP_PORT); // Récupération du flot en lecture sur la connexion input = new LineNumberReader( new InputStreamReader(s.getInputStream(), "ASCII")); // Lecture de la réponse readResponse(); // Récupération du flot en écriture sur la connexion output = new PrintWriter( new OutputStreamWriter(s.getOutputStream(), "8859_1")); // Envoi de la requête de présentation sendLine("EHLO " + InetAddress.getLocalHost().getHostName()); // Lecture des lignes de réponses en vérifiant que le serveur // SMTP accepte les caractères sur 8 bits boolean support8bit = false; String line; do { line = input.readLine(); System.err.println(line); if (line.indexOf("8BITMIME")!=-1) support8bit = true; } while (line.charAt(3)=='-'); // Code de statut suivi d'un tiret: d'autres lignes suivent if (!support8bit) throw new SMTPException("8bit message not supported"); connected=true; // Mise à jour de l'état de la connexion } /** Lecture des lignes constituant une réponse du serveur. Affichage de tout ce qui est lu. */ void readResponse() throws IOException { String line; // On lit une ligne line = input.readLine(); System.err.println(line); // En cas d'erreur, on lève une exception if (line.charAt(0)=='4' || line.charAt(0)=='5') throw new SMTPException(line); // S'il y a encore des lignes à suivre, on rappelle la méthode if (line.charAt(3)=='-') readResponse(); } /** Envoi d'un message contenant un texte utilisant le codage ISO8859-1. @param to destinataire. @param subject sujet du message. @param message contenu du message. */ public void sendMessage(String to, String subject, String message) throws IOException { // Si la connexion n'est pas établie, il faut l'établir if (!connected) connect(); // Envoi des différentes requêtes et lecture de chaque // réponse du serveur sendLine("MAIL FROM: " + fromAddr); readResponse(); sendLine("RCPT TO: " + to); readResponse(); sendLine("DATA"); readResponse(); // Ajout de trois lignes d'en-têtes avant l'envoi des données sendLine("Mime-Version: 1.0"); sendLine("Content-type: text/plain; charset=\"iso-8859-1\""); sendLine("Subject: " + subject); // Une ligne vide termine les lignes d'en-têtes sendLine(); // On envoie ensuite le corps du message sendLine(message); // Et enfin, une ligne ne contenant qu'un point sendLine("."); // On lit ensuite la réponse readResponse(); } /** Envoi d'une ligne au serveur. La ligne envoyée au serveur est également affichée. @param line la ligne à envoyer. */ void sendLine(String line) throws IOException { output.print(line); output.print(EOL); output.flush(); System.err.println(line); } /** Envoi d'une ligne vide. */ void sendLine() throws IOException { sendLine(""); } /** Déconnexion du serveur SMTP. */ public void disconnect() throws IOException { if (connected) { // La déconnexion se fait par l'envoi d'une requête QUIT sendLine("QUIT"); readResponse(); // Ensuite, on ferme la socket qui ferme la connexion s.close(); // Mise à jour de l'état de la connexion connected = false; } } /** Réinitialise le dialogue avec le serveur. Utilisé en cas d'erreur au cours du dialogue. */ public void reset() throws IOException { // Il faut, avant tout, être connecté if (!connected) { connect(); } // puis envoyer une requête RSET sendLine("RSET"); readResponse(); } /** Méthode appelée lors de la destruction de l'objet. Ferme proprement la connexion avec le serveur. */ protected void finalize() { try { disconnect(); } catch(IOException ex) {} } /** Méthode envoyant le même message à une liste de destinataires, passés en argument sur la ligne de commande après le sujet du message. Le message est lu sur l'entrée standard. */ public static void main(String[] args) throws IOException { // Vérification de la présence d'arguments sur la ligne de commande if (args.length<2) { System.err.println("Usage: " +"java fr.umlv.ji.tcp.smtp.SMTPConnection <subject> <dest>+"); System.exit(1); } // Récupération du message sur l'entrée standard. System.out.println("Entrez votre message :"); StringBuffer messageBuffer = new StringBuffer(); LineNumberReader reader = new LineNumberReader(new InputStreamReader(System.in)); String line; while ((line=reader.readLine()) != null) messageBuffer.append(line); String message = messageBuffer.toString(); // Établissement de la connexion vers le serveur SMTPConnection connexion = new SMTPConnection(); connexion.connect(); // Envoyer le message à chaque destinataire for (int i=1; i<args.length; i++) { try { connexion.sendMessage(args[i],args[0],message); } catch(SMTPException e) { System.err.println(e); connexion.reset(); } } connexion.disconnect(); // Fermer la connexion vers le serveur. } }