Enviar correo desde Java

Esta ocasión crearemos una librería que permita enviar correos desde java. Existen infinidad de buenos ejemplos en la web, pero intentaré darle un toque un pelín más avanzado creando una librería y externalizando la configuración de la cuenta.

La visión de conjunto sería meter la configuración en un archivo xml con los datos de una cuenta, para que el cliente envíe desde ella a una dirección de email, un correo. Esto es, los parámetros que aceptará serán el destino, el asunto del correo y el texto.
Un posible escenario sería un portal que envia correos al departamento de ventas desde una cuenta genérica tipo "usuariocualquiera@delportal.com".

Editado:Al final he añadido un rápido ejemplo para probar que funciona la librería en una aplicación web. Es una aplicación que va de un jsp a otro, nada más. Al final esta entrada responde a la pregunta "Cómo enviar un correo desde un jsp".

Lo haré desde el entorno habitual: maven, eclipse, el jdk es el 1.6 y utilizaré las javamail 1.4.5. Crearé dos versiones de librerias, unas con las javamail y otras sin ellas, ya que si vamos a utilizar la libreria realizada en un servidor completo de aplicaciones tipo glassfish no nos haría falta incluirlas, ya que implementan las javamail. En tomcat, por ejemplo, si que necesitaríamos la versión que incluye dependencias.

En la mayor parte de los ejemplos que he visto se "hardcodeaba" los parámetros. En mi caso opto por una solución más versatil que es tomar los valores de un xml, que eventualmente nos permitiría portar la libreria de una aplicación a otro.

Vayamos al lio. Creamos un proyecto quickstart base para aplicaciones de escritorio. Esto es vamos a crear una libreria que tenga un "main" para poder probarlo.
Una vez creado el proyecto añadimos las librerias de javamail.

    <dependencies>
        <dependency>
            <groupId>javax.mail</groupId>
            <artifactId>mail</artifactId>
            <version>1.4.5</version>
        </dependency>
    </dependencies>


 El método main es simple:

public static void main(String[] args) {
        String destiny = args[0];
        args[0]="";
        String text = "";
        for(String item: args){
            text+=" "+item;
        }
        String subject = "Asunto";
        System.out.println("Entran " + destiny +" - "+ subject+" - " + text);
        InternetAddress destinyAddress = null;
        try {
            destinyAddress = new InternetAddress(destiny);
        } catch (AddressException e) {
            e.printStackTrace();
        }
        Mailer mailer = new Mailer(destinyAddress, subject, text);
        System.out.println("Entran " + destiny + " - " + text);


por simplicidad ni siquiera meto un logger, directamente un System.out.println para tener algo de feedback.

Poca explicación de esto. El método main toma los valores de linea de comandos para "parseándolos" inyectarlo a la clase Mailer, que es la que realmente tiene la lógica y el misterio.

En este caso voy a pasarle unos parámetros al constructor que directamente enviará el correo.
Veamos pues el código de este constructor:

public Mailer(InternetAddress destiny, String subject, String text) {
        props = loadConfiguration();
        Session session = Session.getDefaultInstance(props);
        session.setDebug(true);
        String from = props.getProperty("mail.smtp.user");
        MimeMessage message = createMessage(destiny, subject, text, session,
                from);
        sendMessage(session, from, message);
    }


Props en un Properties de java que carga valores con un loadConfiguration.
Se obtiene una mailSession con esas propiedades y se establece el modo debug a true para que nos de una salida informada. Ni que decir que dicho parámetro podría establecerse en la configuración o pasado el desarrollo inicial ponerlo directamente a false.
El siguiente paso es especificar quien va a enviar el mensaje. En nuestro caso lo cargamos desde el archivo de propiedades. Despues creamos el mensaje y por último lo enviamos.

Queda ver qué hace cada uno de los métodos:

private Properties loadConfiguration() {
        Properties propertiesFromFile = new Properties();
        try {
            propertiesFromFile.loadFromXML(new FileInputStream("mail.xml"));
        } catch (InvalidPropertiesFormatException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return propertiesFromFile;
    }


  No tiene mucho misterio. Los Properties tienen para cargar valores directamente desde un InputStream. Si alguien tiene mucho vicio puede abrir el archivo de texto y parsearlo a pedales. ;-)

El archivo "mail.xml" tiene que estar en la carpeta del proyecto. Y el mio, para gmail es así:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
    <comment>Archivo de propiedades de Correo</comment>
    <entry key="mail.smtp.starttls.enable">true</entry>
    <entry key="mail.smtp.user">micuenta@gmail.com</entry>
    <entry key="mail.smtp.port">587</entry>
    <entry key="mail.smtp.auth">true</entry>
    <entry key="mail.smtp.pass">CONTRASE</entry>
    <entry key="mail.smtp.host">smtp.gmail.com</entry>
</properties>


Aqui cada uno debería investigar o saber cuales son los datos de su proveedor.

Para crear el mensaje:

    private MimeMessage createMessage(InternetAddress destiny, String subject,
            String text, Session session, String from) {
        MimeMessage message = new MimeMessage(session);
        try {
            message.setFrom(new InternetAddress(from));
            message.addRecipient(Message.RecipientType.TO, destiny);
            message.setSubject(subject);
            message.setText(text);
        } catch (AddressException e) {
            e.printStackTrace();
        } catch (MessagingException e) {
            e.printStackTrace();
        }
        return message;
    }


Para enviar el mensaje:

    private void sendMessage(Session session, String from, MimeMessage message) {
        Transport t;
        String pass = props.getProperty("mail.smtp.pass");
        try {
            t = session.getTransport("smtp");
            t.connect(from, pass);
            t.sendMessage(message, message.getAllRecipients());
            t.close();
        } catch (NoSuchProviderException e) {
            e.printStackTrace();
        } catch (MessagingException e) {
            e.printStackTrace();
        }
    }


Para probarlo lo lanzo con:
clean compile exec:java -Dexec.mainClass="es.sinjava.labs.App" -Dexec.args="andres@amena.com prueba de molón ". Le especifico cual es la clase main y le paso como parámetros un primer string que es la dirección y el resto el texto.

Y para que me genere la librería ejecuto clean package assembly especificando en el pom:

<build>
        <finalName>mailer</finalName>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>es.sinjava.labs.App</mainClass>
                        </manifest>
                    </archive>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
            </plugin>
        </plugins>
    </build>


De tal manera que me genera dos jar, uno con las javamail y otro sin ellas. Hay varios detalles que se quedan en al aire: primero la gestión de logs y el segundo la ejecucción en primer plano del envío, pero eso lo dejo para una segunda revisión en la que abordaré la integración de esta librería en un proyecto web.


El proyecto comprimido lo tienes aqui.  La clase que tiene toda la "historia" la puedes ver rápidamente en Pastebin. Me ha sorprendido que hagan falta menos de 80 lineas para escribir el código que envia un correo y más teniendo en cuenta que el 60% es captura de excepciones.

Si realizas/pruebas este proyecto no te olvides de colocar el archivo mail.xml en la carpeta del proyecto, si lo ejecutas desde el propio eclipse o si lo lanzas como ejecutable en la carpeta que tengas el jar, obviamente deberás lanzar el jar "con dependencias".

Editando:
Como prueba de concepto, para comprobar que dicha librería funciona correctamente desde un aplicación web. He creado una aplicación web con dos jsp, el primero tiene un formulario con la dirección y el texto y el segundo una pantalla de resultado. Por el camino se llama a dicha librería para que realice el envío del correo.
Previamente, para poder utilizar dicha librería en el proyecto, voy a instalarla en el repositorio local de maven, ejecutando mvn install o, desde el eclipse, click con el botón derecho sobre el proyecto , Run As.. Maven Install.
En el pom de la aplicación web añadimos la dependencia:

<dependencies>
        <dependency>
            <groupId>es.sinjava.labs</groupId>
            <artifactId>mailgmail</artifactId>
            <version>1.0.0</version>
        </dependency>
    </dependencies>


Con los datos que yo he creado la libreria tengo esos son los valores.
Veamos el jsp de entrada. "index.jsp":
<html>
<head>
<title>Enviador de correo</title>
</head>
<body>
    <h2>Introduce los datos</h2>
    <form name="frmMail" action="send.jsp">
        <table>
            <tr>
                <td>Dirección de destino</td>
                <td><input type="text" name="destiny"></td>
            </tr>
            <tr>
                <td>Texto</td>
                <td><input type="text" name="content" height="5"></td>
            </tr>
            <tr>
                <td></td>
                <td><input type="submit"></td>
            </tr>
        </table>
    </form>
</body>
</html>
Un form con dos campos y botón.¿Quién dijo que no me interesaba el diseño de páginas web?
Y el jsp de salida, "send.jsp":
<html>
<head>
<title>Enviador de correo</title>
</head>
<body>
    <h1>Correo enviado</h1>
    <%@ page import="es.sinjava.labs.Mailer" %>
    <%
        String destiny = request.getParameter("destiny");
        String content = request.getParameter("content");
        String subject = "Enviado desde el jsp";
        Mailer nuevoMailer = new Mailer(destiny, subject, content);
    %>   
    <h2> Enviado el correo a <%=destiny%> </h2>
</body>
</html>
Creo que para alguien que haya programado algo en jee no tiene mucho misterio estos jsp minimalistas.Así que tampoco ahondaré en ello. El import de la clase, la captura de párametro de la llamada y la llamada al constructor del mailer.

El proyecto completo está aquí.
Consideraciones:
La librería toma la configuración de un archivo mail.xml que, si se despliega en un tomcat, habrá que colocarlo su carpeta.
Me parece un churro enviar un correo desde un jsp. Me parece otro churro enviar directamente desde el constructor Mailer.
Probar con precaución en un servidor obsoleto tipo OC4J, tengo serías dudas de que funcionase.