Gestión cuentas email (IMAP) en Java

java IconoGestionar una cuenta de correo es un poco más complejo que el envío de un mail. La funcionalidad proporcionada por el API de JavaMail es suficientemente extensa para permitirnos escribir un cliente de mail completamente funcional. A una aplicación especializada en el tratamiento de mails, como podría ser un gestor de listas de correo, podría serle suficiente con la funcionalidad de recepción y envío de correo, pero ahora supón una aplicación de monitorización de servidor que puede requerir cargar periódicamente páginas de distintos servidores web corriendo en host distintos y enviar alertas al webmaster si el servidor web se ha caído. La cosa se complica ¿verdad?. Pues si, la cosa se puede complicar todo lo que queramos, para están los ordenadores….Yo te digo lo que haces una vez y luego repites como un mono el trabajo. Bien, para implementar un proceso(programa) como el segundo de los descritos podríamos emplear un API de Java denominado JavaMail, que es una librería que nos va a facilitar bastante las cosas pues nos proporciona una capa que nos separa de las implementaciones concretas de la comunicación-operación con los servidores de mail. En este artículo nos vamos a centrar en algunos de los aspectos mas importantes de dicha interfaz y su implementación mediante código.

Anatomía JavaMail

JavaMail no es la única forma de gestionar la comunicación por mail. Podríamos escribir programas Java que usando sockets podrían establecer comunicación con el servidor de correo de forma directa. No obstante, en este último caso, la aplicación (el programador) necesitaría amplios conocimientos de protocolos tales como SMTP, POP, e IMAP. El API de JavaMail nos simplifica esta labor enormemente ayudándonos a centrarnos en el mensaje en lugar de pelearnos con detalles de bajo nivel de los protocolos subyacentes. La arquitectura muestra claramente una doble división:

  • La parte de aplicación, que proporciona la API necesaria para que la en la comunicación mediante mail nos podamos olvidar de los protocolos subyacentes. Esta capa implementa el patrón de factoría abstracta. El patrón nos permite escribir código basado en una superclase abstracta sin preocuparnos de los detalles de menor nivel.
  • La parte de servicio, que esta alineada con los protocolos y habla en dicho lenguaje para permitir la comunicación. Estos protocolos corresponden con una serie de clases concretas que especializan el API general a un protocolo particular y un formato concreto.

IMAP4 vs POP3

IMAP (Internet Message Access Protocol) y POP (Post Office Protocol) son dos protocolos construidos para el mismo propósito, recuperación de mensajes, búsquedas en los buzones de correo, etc. La diferencia fundamental entre el uno y el otro estriba en que mientras POP3 asume que es el cliente el que almacena y gestiona el fichero de correo, IMAP lo hace hace al contrario. POP3 no obstante, proporciona herramientas para que el cliente pueda descargar los mails del servidor pero, como ya se ha indicado, el cliente es responsable de almacenar y gestionar dichos mensajes en su propio sistema de almacenamiento. Una vez descargado el mail, POP3 elimina el mensaje original del servidor. IMAP, por otro lado, permite emplear el almacenamiento del propio servidor como almacén de mensajes, hasta que el cliente manualmente decida eliminar dichos mensajes, similar a lo que muchos de nosotros hacemos en GMAIL. IMAP emplea espacio de almacenamiento en el propio servidor y por lo tanto dicho espacio se encuentra limitado

POP3, no se bien el por que, es menos popular y es particularmente interesante para construir un cliente de correo similar a Outlook Express o Thunderbird. IMAP es un jugador bastante popular en la actualidad debido principalmente al protagonismo que han cobrado los denominados servicios «en la nube», ya que puede ser explotado en cualquier momento, desde cualquier lugar y casi con cualquier tipo de dispositivo, tan solo empleando un navegador. Ejemplos de este tipo de servicio son Gmail, Yahoo!, Hotmail, etc.

Gestionando una cuenta de Email

El ejemplo siguiente muestra como recuperar el mail desde la carpeta de entrada. El servidor IMAP empleado en el código es Gmail, con pocos cambios podría valer para cualquiera.


package org.casamier.imapexample;
import java.util.Properties;
import javax.mail.Address;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.Message.RecipientType;
import javax.mail.MessagingException;
import javax.mail.NoSuchProviderException;
import javax.mail.Session;
import javax.mail.Store;

public class MailBean {
private Properties getServerProperties(String protocol,String host, String port) {
Properties properties = new Properties();
properties.put(String.format("mail.%s.host",protocol), host);
properties.put(String.format("mail.%s.port",protocol), port);
properties.setProperty(String.format("mail.%s.socketFactory.class",protocol), "javax.net.ssl.SSLSocketFactory");
properties.setProperty(String.format("mail.%s.socketFactory.fallback",protocol), "false");
properties.setProperty(String.format("mail.%s.socketFactory.port",protocol), String.valueOf(port));

return properties;
}

public void getNewEmails(String protocol, String host,
String port, String userName, String password) {
Properties properties = getServerProperties(protocol,host, port);
Session session = Session.getDefaultInstance(properties);

try {
Store store = session.getStore(protocol);
store.connect(userName, password);

Folder inbox = store.getFolder("INBOX");
inbox.open(Folder.READ_WRITE);

int count = inbox.getMessageCount();
Message[] messages = inbox.getMessages(1, count);
for (Message message : messages) {
if (!message.getFlags().contains(Flags.Flag.SEEN)) {
Address[] fromAddresses = message.getFrom();
System.out.println("...................");
System.out.println("\t From: "+ fromAddresses[0].toString());
System.out.println("\t To: "+ parseAddresses(message.getRecipients(RecipientType.TO)));
System.out.println("\t CC: "+ parseAddresses(message.getRecipients(RecipientType.CC)));
System.out.println("\t Subject: "+ message.getSubject());
System.out.println("\t Sent Date:"+ message.getSentDate().toString());
try {
System.out.println(message.getContent()
s.toString());
} catch (Exception ex) {
System.out.println("Error reading content!!");
ex.printStackTrace();
}
}

}

inbox.close(false);
store.close();
} catch (NoSuchProviderException ex) {
System.out.println("No provider for protocol: "+ protocol);
ex.printStackTrace();
} catch (MessagingException ex) {
System.out.println("Could not connect to the message store");
ex.printStackTrace();
}
}

private String parseAddresses(Address[] address) {

String listOfAddress = "";
if ((address == null) || (address.length < 1))
return null;
if (!(address[0] instanceof InternetAddress))
return null;

for (int i = 0; i < address.length; i++) {
InternetAddress internetAddress =(InternetAddress) address[0];
listOfAddress += internetAddress.getAddress()+",";
}
return listOfAddress;
}
}

package org.casamier.imapexample;

public class mailapp {
public static void main(String[] args){
MailBean bean=new MailBean();
bean.getNewEmails("imap", "imap.gmail.com", "993","user1", "****");
}
}

Cómo funciona

Una vez conectados al servido IMAP , el almacen es configurado para conectar de la siguiente forma:

Store store = session.getStore(protocol);
store.connect(userName, password);

Ahora ya estamos listos para abrir la carpeta correspondiente. Esta sección esta mas dirigida a IMAP por que los servidores POP no gestionan carpetas (simplemente proporcionar información de mail entrante como un único paquete)

Folder inbox = store.getFolder("INBOX");
inbox.open(Folder.READ_WRITE);

Nos saltamos los mensajes que están marcados como leidos. Esto se logra con el siguiente código:

if (!message.getFlags().contains(Flags.Flag.SEEN))

Los mensajes no leídos son mostrados con sus detalles. Cada mensaje esta formado por diversa información tal como cc, asunto, la fecha de envío, el contenido del mensaje, etc. Podríamos incluso identificar si el contenido del mensaje es texto plano o html y procesarlo como es debido. Los métodos ParseAddress extraen las direcciones de mail debido a que los objetos Address de JavaMail son genéricos y pueden representar direcciones de Internet o grupos de noticias. Por lo tanto, el método parsea el objeto  Address y recupera las direcciones de mail correspondientes.

Conclusion

El código mostrado es una simple demostración de cómo se puede gestionar una cuenta de mail. Bastante simple si empleamos JavaMail como se ha podido apreciar. Los programadores no deben bajar a la complejidad de los protocolos subyacentes. Por otro lado, debido a que el mail llega de forma aleatoria (algunas personas son verdaderas máquinad de spam), JavaMail también proporciona mecanismos para «manejar» todos esos mensajes entrantes como si se eventos AWT se tratase (ejemplo). Todas estas características pueden emplearse para crear aplicaciones de mail completamente funcionales, tanto POP como IMAP.

Un saludo a todos y hasta la siguiente.

You must be logged in to post a comment.