API JavaMail

22
API JavaMail Autor: Sun Traductor: Juan Antonio Palos (Ozito) API JavaMail o Introducción al API JavaMail o Revisión de los Protocolos Relacionados SMTP POP IMAP MIME NNTP y Otros Instalar el API JavaMail o Instalación Instalar JavaMail 1.2 Instalar JavaMail 1.1.3 Instalar el Marco de Trabajo de Activación de JavaBeans Usarlo con Java 2 Enterprise Edition o Configurar Nuestro Entorno JavaMail Paso 1 Paso 2 Paso 3 Paso 4 Paso 5 Paso 6 Paso 7 Las clases Corazón o Revisar las Clases Corazón Session Message Address Authenticator Transport Store y Folder Más allá Utilización del API JavaMail o Enviar Mensajes o Leer Mensajes o Borrar Mensajes y Banderas o Autentificación o Responder a Mensajes o Re-Enviar Mensajes o Trabajar con Attachments o Enviar Attachments o Obtener Attachments o Procesar Mensajes HTML o Enviar Mensajes HTML o Includir Imágenes en Nuestos Mensajes Buscar Con SearchTerm o Búsquedas con SearchTerm o Recursos

description

uso implementacion de la API JavaMail enviar correo desde javause implementation of the JavaMail API to send email from java

Transcript of API JavaMail

Page 1: API JavaMail

API JavaMail Autor: Sun

Traductor: Juan Antonio Palos (Ozito)

API JavaMail o Introducción al API JavaMail o Revisión de los Protocolos Relacionados

SMTP POP IMAP MIME NNTP y Otros

Instalar el API JavaMail o Instalación

Instalar JavaMail 1.2 Instalar JavaMail 1.1.3 Instalar el Marco de Trabajo de Activación de JavaBeans Usarlo con Java 2 Enterprise Edition

o Configurar Nuestro Entorno JavaMail Paso 1 Paso 2 Paso 3 Paso 4 Paso 5 Paso 6 Paso 7

Las clases Corazón o Revisar las Clases Corazón

Session Message Address Authenticator Transport Store y Folder Más allá

Utilización del API JavaMail o Enviar Mensajes o Leer Mensajes o Borrar Mensajes y Banderas o Autentificación o Responder a Mensajes o Re-Enviar Mensajes o Trabajar con Attachments o Enviar Attachments o Obtener Attachments o Procesar Mensajes HTML o Enviar Mensajes HTML o Includir Imágenes en Nuestos Mensajes

Buscar Con SearchTerm o Búsquedas con SearchTerm o Recursos

Page 2: API JavaMail

API JavaMail

Introducción al API JavaMail

El API JavaMail es un paquete opcional (extensión estándard) para leer, componer, y enviar mensajes electrónicos.

Usamos este paquete para crear programas del tipo MUA (Mail User Agent), similares a Eudora, Pine, y Microsoft Outlook. Su propósito principal no es transportar, enviar, o re-enviar mensajes como sendmail u otros programas del tipo MTA (Mail Transfer Agent). En otras palabras, los usuarios interactúan con los programas para leer y escribir e-mails. Los programas MUA tratan con los programas MTA para el envío real.

El API JavaMail está diseñado para proporcionar acceso independiente del protocolo para enviar y recibir mensajes dividiendose en dos partes:

La primera parte del API es el foco de este tutor. Basicamente, cómo enviar y recibir mensajes independientemente del proveedor/protocolo.

La segunda parte habla de lenguajes especificos del protocolo como SMTP, POP, IMAP, y NNTP. Con el API, JavaMail para poder comunicar con un servidor, necesitamos un proveedor para un protocolo.

Revisión de los Protocolos Relacionados

Antes de mirar dentro de las especificaciones del API JavaMail, echemos un vistazo a los protocolos usados con el API. Básicamente son cuatro:

SMTP

POP

IMAP

MIME

También ejecutaremos sobre NNTP y algunos otros. Entender lo básico de cada protocolo nos ayudará a entender mejor cómo usar el API JavaMail. Aunque el API sea independiente del protocolo, no podemos evitar las limitaciones de los protocolos subyacentes. Si una capacidad no está soportada por el protocolo elegido, el API JavaMail no hará que esa capacidad aparezca por arte de magia.

(Como veremos pronto, este es un problema normal cuando trabajamos con POP).

SMTP

El protocolo Simple Mail Transfer Protocol (SMTP) está definido por la RFC 821. Define el mecanismo para enviar e-mail. En el contexto del API JavaMail, nuestro programa basado en JavaMail comunicará con el servidor SMTP de nuestro proveedor de servicios (ISP). Este servidor SMTP dejará el mensaje en el servidor SMTP del recipiente(s) para que sea recogido por los usuarios a través de POP o IMAP. Esto no requiere que nuestro servidor SMTP sea un rele abierto, pues se utiliza la autentificación, pero es nuestra responsabilidad asegurarnos de que el servidor SMTP se configure correctamente. No hay nada en el API JavaMail sobre tareas como el configuración de un servidor para retransmitir mensajes o para agregar y para quitar cuentas del e-mail.

POP

POP viene de Post Office Protocol. Actualmante en la versión 3, también conocido como POP3, la RFC 1939 define este protocolo.

Page 3: API JavaMail

POP es el mecanismo que la mayoría de la gente usa en Internet para conseguir su correo. Define el soporte de un sólo mailbox por cada usuario. Ésto es todo lo que lo hace, y ésta también es la fuente de la mayoría de la confusión. Muchas de las cosas con que gente se familiariza cuando usa POP, como la capacidad de ver cuántos mensajes de correo nuevos tienen, no lo soporta POP en absoluto. Estas capacidades se construyen en programas como Eudora o Microsoft Outlook, que recuerdan cosas como los últimos correos recibidos y calculan cuántos tenemos nuevos. Así pues, al usar el API JavaMail, si queremos este tipo de información tendremos que calcularla nosotros mismos.

IMAP

IMAP es un protocolo más avanzado para recibir mensajes. Definido en la RFC 2060, IMAP viene de Internet Message Access Protocol, y está actualmente en la versión 4, también conocida como IMAP4. Para usar el IMAP, nuestro servidor de correo debe soportar este protocolo. No podemos simplemente cambiar nuestro programa para usar IMAP en vez de POP y que se soporte todo IMAP. Si asumimos que nuestro servidor de correo soporta IAMP, nuestro programa basado en JavaMail puede aprovecharse de los usuario que tienen carpetas múltiples en el servidor y estas carpetas se pueden compartir por varios usuarios.

Debido a las capacidades más avanzadas, podríamos pensar que IMAP sería utilizado por todos. Pero no es así. Sobrecarga mucho el servidor de correo, requiriendo que el servidor reciba los nuevos mensajes, los entrege a los usuarios cuando sean solicitados, y los mantiene en las distintas carpetas de cada usuario. Aunque que esto centraliza las copias de seguridad, también hace que las carpetas de correo a largo plazo de los usuarios se hagan cada vez más grandes, y todo el mundo sufre cuando se agota el espacio en el disco. Con POP, los mensajes recuperados son eliminados del servidor de correo.

MIME

MIME viene de Multipurpose Internet Mail Extensions. No es un protocolo de transferencia de e-mail. En su lugar, define el contenido de lo que se está transfiriendo: el formato de los mensajes, los attachments, etc. Hay muchos documentos que tienen efecto sobre esto: las RFC 822, RFC 2045, RFC 2046, y RFC 2047. Como usuario del API JavaMail, normalmente no tendremos que preocuparnos sobre estos formatos. Sin embargo, estos formatos existen y son utilizados por nuestros programas.

NNTP y Otros

A causa de la división del API JavaMail entre proveedor y cualquier otra cosa, podemos fácilmente soportar protocolos adicionales. Sun Mantiene una lista de proveedores de terceras partes que se aprovechan de los protocolos para los que Sun no proporciona soporte. Allí encontraremos soporte para NNTP Network News Transport Protocol [newsgroups], S/MIME Secure Multipurpose Internet Mail Extensions, y más.

Page 4: API JavaMail

Instalar el API JavaMail o Instalación

Instalar JavaMail 1.2 Instalar JavaMail 1.1.3 Instalar el Marco de Trabajo de Activación de JavaBeans Usarlo con Java 2 Enterprise Edition

o Configurar Nuestro Entorno JavaMail Paso 1 Paso 2 Paso 3 Paso 4 Paso 5 Paso 6 Paso 7

Instalar el API JavaMail

Instalación

Hay dos versiones del API JavaMail usadas comunmente hoy en dia: la 1.2 y la 1.1.3. Todos los ejemplos de este artículo funcionan con ámbas. Mientras 1.2 es el último, 1.1.3 es la versión incluida en la versión 1.2.1 de la Plataforma Java 2 Enterprise Edition (J2EE), por eso es tan usado. La versión del API que queramos usar afecta a lo que tengamos que descargar e instalar. Todo funcionará con el JDK 1.1.6+, de la Plataforma Java 2, Standard Edition (J2SE) versión 1.2.x, y J2SE versión 1.3.x.

Nota: después de instalar la implementación de JavaMail de Sun, podrás encontrar muchos

programas de ejemplo en el directorio: demo.

Instalar JavaMail 1.2

Para usar el API JavaMail 1.2, descargamos la implementación, JavaMail 1.2,

descomprimimos el fichero javamail-1_2.zip, y añadimos el fichero mail.jar a nuestro CLASSPATH. La implementación 1.2 viene con proveedores para SMTP, IMAP4, y POP3 junto con las clases corazón.

Después de instalar JavaMail 1.2, instalamos el marco de trabajo de activación de JavaBeans.

Instalar JavaMail 1.1.3

Para usar el API JavaMail 1.1.3, descargamos la implementación JavaMail 1.1.3,

descomprimimos el ficherosjavamail1_1_3.zip, y añadimos el fichero mail.jar a nuestro CLASSPATH. La implementación 1.1.3 viene con proveedores para SMTP y IMAP4, junto con las clases corazón.

Si queremos acceder a un servidor POP con JavaMail 1.1.3, descargamos e instalamos un proveedor POP3. Sun tiene uno disponible separado de la implementación de JavaMail.

después de descargar y descomprimir pop31_1_1.zip, también añadimos pop3.jar a nuestro

CLASSPATH.

Después de instalar JavaMail 1.1.3, instalamos el marco de trabajo de activación de JavaBeans.

Page 5: API JavaMail

Instalar el Marco de Trabajo de Activación de JavaBeans

Todas las versiones del API JavaMail requieren el Marco de Trabajo para la Activación de JavaBeans.

El marco de trabajo añade soporte para tecleo arbitrario de bloques de datos y manejarlos correctamente. Esto no suena muy bien, pero es nuestro soporte básico para MIME-type

encontrado en muchos navegadores y herramientas de correo, hoy en día. Después de

descargar el marco de trabajo, descomprimimos el fichero jaf1_0_1.zip, y añadimos el

ficheroactivation.jar a nuestro CLASSPATH.

Para usuarios de JavaMail 1.2, deberíamos tener mail.jar y activation.jar en nuestro CLASSPATH.

Para usuarios de JavaMail 1.1.3, deberíamos tener mail.jar, pop3.jar, y activation.jar en nuestro CLASSPATH. Si no tenemos planes de utilizar POP3, no necesitamos añadirlo a nuestro CLASSPATH.

Si no queremos modificar nuestra variable de entorno CLASSPATH, copiamos los

ficheros JAR a nuestro directorio lib/extbajo el directorio del Java Runtime Environment (JRE). Por ejemplo, para la versión J2SE 1.3, el directorio por defecto

seríaC:\jdk1.3\jre\lib\ext en una plataforma Windows.

Usarlo con Java 2 Enterprise Edition

Si usamos J2EE, no tenemos que hacer nada especial para usar el API básico de JavaMail;

viene con las clases del J2EE. Sólo debemos asegurarnos de que el fichero j2ee.jar está en nuestro CLASSPATH y que tenemos todo configurado.

Para J2EE 1.2.1, el proveedor POP3 viene separado, por eso lo descargamos y seguimos los pasos para incluir el proveedor POP3 como se mostró en Instalar JavaMail 1.1.3. Los usuario de J2EE 1.3 obtienen el proveedor POP3 con el J2EE por eso no requieren una instalación separada. Tampoco se requiere ninguna instalación para el Marco de Trabajo de Activación de JavaBeans.

Configurar Nuestro Entorno JavaMail

Paso 1

Descargar la última versión de la implementación del API JavaMail desde Sun.

Paso 2

Descargar la última versión del Marco de Trabajo de Activación de JavaBeans desde Sun.

Paso 3

Descomprimir los paquetes descargados. Obtendremos un fichero ZIP para todas los plataformas de los dos paquetes.

Podemos usar la herramienta jar para descomprimir los paquetes.

Page 6: API JavaMail

Paso 4

Añadimos los ficheros mail.jar y activation.jar recien descomprimidos a

nuestro CLASSPATH.

Copiamos estos ficheros a nuestro directorio de librerías de extensión. Para Windows, y usando una instalación por defecto, el comando se parecería a esto:

cd \javamail-1.2

copy mail.jar \jdk1.3\jre\lib\ext

cd \jaf-1.0.1

copy activation.jar \jdk1.3\jre\lib\ext

Si no nos gusta copiar los ficheros al directorio de librerías de extensión, en Sun puedes encontrar instrucciones detalladaspara configurar el CLASSPATH sobre Windows NT

Paso 5

Vamos dentro del directorio demo que viene con la implementación del API JavaMail y

compilamos el programa msgsend para enviar un mensaje de prueba:

javac msgsend.java

Paso 6

Ejecutamos el programa pasandole una dirección "from" en la opción -o, nuestro servidor

SMTP con la opción -M, y la dirección "to" (sin opción). Luego introduciremos el subject, el texto de nuestro mensaje y el caracter de fin-de-fichero (CTRL-Z) para indicar el final de la introducción del mensaje.

Debemos asegurarnos de reemplazar las direcciones correctas:

java msgsend -o from@address -M SMTP.Server to@address

Si no estas seguro de tu servidor SMTP, contacta con el administrador de tu sistema o pregunta a tu proveedor de Internet.

Paso 7

Para asegurarnos de que hemos recibido el mensaje, debemos chequearlo con nuestro lector de correo habitual (Eudora, Outlook Express, pine, ...).

Page 7: API JavaMail

Las clases Corazón o Revisar las Clases Corazón

Session Message Address Authenticator Transport Store y Folder Más allá

Las clases Corazón

Revisar las Clases Corazón

Antes de profundizar en las classes de JavaMail, veremos las clases corazón que componen el API: Session, Message,Address, Authenticator, Transport, Store, y Folder. Todas estas

clases se encuentran en el paquete del nivel superior del API JavaMail: javax.mail, aunque

frecuentemente nos veremos utilizando clases del paquete javax.mail.internet.

Session

La clase Session define una sesión de correo básica. Es a través de esta de sesión de la que

todas las demás funcionan. El objeto Session se aprovecha de un

objeto java.util.Properties para obtener información como el servidor de correo, el nombre de usuario, la password, y otra información que puede compartirse a lo largo de toda la aplicación.

El constructor para las clases es privado. Podemos obtener una sola sesión por defecto que

puede ser compartida con el método getDefaultInstance():

Properties props = new Properties();

// fill props with any information

Session session = Session.getDefaultInstance(props, null);

O podemos crear una única sesión con getInstance():

Properties props = new Properties();

// fill props with any information

Session session = Session.getInstance(props, null);

En ambos casos el argumento null es un objeto Authenticator que no se utiliza en este

momento, lo veremos más adelante en Authenticator.

En la mayoría de los casos, es suficiente usar la sesión compartida, incluso si se trabaja con una sesión de correo para múltiples mailboxes de usuario. Podemos añadir una combinación de nombre de usuario y passsword en un paso posterior en el proceso de comunicación, manteniendolo todo separado.

Message

Una vez que tenemos nuestro objeto Session, es hora de empezar a crear un mensaje para

enviar. Esto se hace con un objeto Message.

Page 8: API JavaMail

Siendo una clase abstracta, debemos trabajar con una subcalse, en la mayoría de los casos

serájavax.mail.internet.MimeMessage.

Un MimeMessage es un mensaje de e-mail que entiende los tipos MIME, definidos en las distintas RFCs. Las cabeceras de mensajes están restringidas a caracteres US-ASCII, aunque en ciertos campos de cabecera se pueden codificar caracteres no ASCII.

Para crear un Message, le pasamos el objeto Session al constructor de MimeMessage:

MimeMessage message = new MimeMessage(session);

Nota: Hay otros constructores, como para crear mensajes desde streams de entrada

formateados RFC822.

Una vez que tenemos nuestro mensaje, podemos configurar sus diferentes partes, como Message implementa el interfacePart (con MimeMessage implementando MimePart).

El mecanismo básico para configurar el contenidos es el método setContent(), con los argumentos para el contenido y tipo mime:

message.setContent("Hello", "text/plain");

Sin embargo, si sabemos que estámos trabajando con un MimeMessage y nuestro mensaje es

texto plano, podemos usar su método setText() que sólo requiere el contenido real, dejando

por defecto el tipo MIME a text/plain:

message.setText("Hello");

Para mensajes de texto plano la última forma es el mecanismo preferido para seleccionar el contenido. Para enviar otros tipos de mensajes, como HTML, usaremos el formador, que veremos más adelante.

Para seleccionar el subject, usamos el método setSubject():

message.setSubject("First");

Address

Una vez que hemos creado la Session y el Message, y también hemos rellenado el mensaje

con contenido, es hora de poner dirección a nuestra carta con un objeto Address.

Como Message, Address es una clase abstracta. Usaremos la

clase javax.mail.internet.InternetAddress.

Para crear una dirección con sólo la dirección e-mail, se la pasamos al constructor:

Address address = new InternetAddress("[email protected]");

Si queremos que aparezca el nombre junto a la dirección e-mail, también podemos pasárselo al constructor:

Address address = new InternetAddress("[email protected]", "George

Bush");

Page 9: API JavaMail

Necesitaremos crear objetos address para los campos from y to del mensaje. A menos que el servidor lo evite, no hay nada que nos impida enviar un mensaje que parezca que viene de otra persona.

Una vez que hemos creado las direcciones, las conectamos al mensaje de una de estas dos

formas. Para identificar al que lo envía, usamos los métodos setFrom() y setReplyTo().

message.setFrom(address)

Si nuestro mensane necesita varias direcciones "from", usamos el método addFrom():

Address address[] = ...;

message.addFrom(address);

Para identificar a los receptores del mensaje, usamos el método addRecipient(). Este método

requiere unMessage.RecipientType junto a la dirección.

message.addRecipient(type, address)

Los tres tipos predefinidos de direcciones son:

Message.RecipientType.TO

Message.RecipientType.CC

Message.RecipientType.BCC

Por eso, si el mensaeje fuera dirigido al vice-presidete, enviando copia a la primera dama, esto sería lo apropiado:

Address toAddress = new InternetAddress("[email protected]");

Address ccAddress = new InternetAddress("[email protected]");

message.addRecipient(Message.RecipientType.TO, toAddress);

message.addRecipient(Message.RecipientType.CC, ccAddress);

El API JavaMail no proporciona mecanismo para chequear la validez de una dirección e-mail. Pero si podemos hacer que nuestro programa soporte un scan de caracteres válidos (según lo definido en la RFC 822) o verificar nosotros mismos el registro MX (Mai Exchange), esto va más allá del ámbito del API JavaMail.

Authenticator

Como las clases java.net, el API JavaMail peude aprovecharse de un Authenticator para proteger accesos a recursos mediante un nombre de usuario y una password. Para el API

JavaMail, el recursos es el servidor de correo. ElAuthenticator JavaMail se encuentra en el

paquete javax.mail y es diferente de la clase de java.net con el mismo nombre. Las dos no

comparten el mismo Authenticator ya que el API JavaMail funciona con Java 1.1, que no

tenía la veriedad java.net.

Para usar el Authenticator, subclasificamos la clase abstracta y devolvemos un

ejemplar PasswordAuthentication del método getPasswordAuthentication(). Debemos

registrar el Authenticator con la sesión cuando se crea. Luego, nuestro Authenticator será notificado cuando sea necesaria una autentificación. Podríamos mostrar una ventana o leer el nombre de usuario y la password desde un fichero de configuración (aunque si no está

encriptado no es seguro), devolviendolo al llamador como un objeto PasswordAuthentication.

Properties props = new Properties();

// fill props with any information

Authenticator auth = new MyAuthenticator();

Page 10: API JavaMail

Session session = Session.getDefaultInstance(props, auth);

Transport

La parte final del envío de un mensaje es usar la clase Transport. Estas clase habla el lenguaje específico del protocolo para enviar mensajes (normalmente SMTP). Es una clase

abstracta y funciona como Session.

Podemos usar la versión por defecto de la clase sólo llamando al método estático send():

Transport.send(message);

O, podemos obtener un ejemplar específico desde la sesión para nuestro protocolo, pasándole el nombre de usuario y la password (en blanco si no son necesarias), enviar el mensaje, y cerrar la conexión:

message.saveChanges(); // implicit with send()

Transport transport = session.getTransport("smtp");

transport.connect(host, username, password);

transport.sendMessage(message, message.getAllRecipients());

transport.close();

Esta última forma es mejor cuando necesitamos enviar varios mensajes, porque mantendrá activa la conexión entre mensajes. El mecanismo básico send() hace un conexión separada al

servidor para cada llamada a método.

Nota: Para ver los comandos enviados al servidor de correo activaremos la bandera

debug consession.setDebug(true).

Store y Folder

Obtener los mensajes empieza de forma similar a enviar mensajes, con una Session.

Sin embargo, después de obtener la sesión, conectamos a un Store, probablemente con un

nombre de usuario y una password o Authenticator. Como con Transport, le decimos

al Store qué protocolo utilizar:

// Store store = session.getStore("imap");

Store store = session.getStore("pop3");

store.connect(host, username, password);

Después de conectar al Store, podemos obtener un Folder, que debe estar abierto antes de

poder leer los mensajes que hay en su interior:

Folder folder = store.getFolder("INBOX");

folder.open(Folder.READ_ONLY);

Message message[] = folder.getMessages();

Para POP3, la única carpeta disponible es INBOX. Si estamos usando IMAP, podremos disponer de otras carpetas.

Nota: Los proveedores de Sun se han pensado para ser inteligentes. Mientras

que Message message[] = folder.getMessages(); podría parecer una operación lenta

que lee todos los mensajes del servidor, sólo cuando realmente necesitamos obtener una

parte del mensaje es cuando el contenido es recuperado.

Page 11: API JavaMail

Una vez que tenemos un Message para leer, podemos obtener sus contenidos

con getContent() o escribir sus contenidos en un stream con writeTo(). El

método getContent() sólo obtiene el contenido del mensaje, mientras que la salida

dewriteTo() incluye las cabeceras.

System.out.println(((MimeMessage)message).getContent());

Después de haber leído el e-mail, cerramos la conexión al folder y al store.

folder.close(aBoolean);

store.close();

El valor boolenao pasado al método close() del folder significa si actualizamos o no la carpeta

eliminando los mensajes borrados.

Más allá

Esencialmente, entender cómo usar las siete clases es todo lo que necesitamos para manejar el API JavaMail. La mayoría de las otras capacidades del API JavaMail construidas desde estas siete clases hacen algo un poco diferente o de una forma particular, como si el contenido es un attachment. Ciertas tareas, como las búsquedas, están aisladas y se describen en la sección Busquedas por SearchItem.

Page 12: API JavaMail

Utilización del API JavaMail o Enviar Mensajes o Leer Mensajes o Borrar Mensajes y Banderas o Autentificación o Responder a Mensajes o Re-Enviar Mensajes o Trabajar con Attachments o Enviar Attachments o Obtener Attachments o Procesar Mensajes HTML o Enviar Mensajes HTML o Includir Imágenes en Nuestos Mensajes

Utilización del API JavaMail

Ya hemos visto como trabajar con las partes principales del API JavaMail. En esta página encontraremos aproximaciones de cómo conectar las piezas para realizar tareas específicas.

Enviar Mensajes

Enviar un mensaje de e-mail implica obtener una sesión, crear y rellenar un mensaje y enviarlo. Podemos especificar nuestro servidor SMTP configurando la propiedad mail.smtp.host del

objeto Properties cuando se obtuvo la Session:

String host = ...;

String from = ...;

String to = ...;

// Get system properties

Properties props = System.getProperties();

// Setup mail server

props.put("mail.smtp.host", host);

// Get session

Session session = Session.getDefaultInstance(props, null);

// Define message

MimeMessage message = new MimeMessage(session);

message.setFrom(new InternetAddress(from));

message.addRecipient(Message.RecipientType.TO,

new InternetAddress(to));

message.setSubject("Hello JavaMail");

message.setText("Welcome to JavaMail");

// Send message

Transport.send(message);

Deberíamos situar el código dentro de un bloque try-catch, porque la configuración del mensaje y su envío pueden lanzar excepciones.

Aquí tienes el código fuente MailExample.java completo.

Page 13: API JavaMail

Leer Mensajes

Para leer mensajes, obtenemos una sesión, y nos conectamos con el store apropiado para nuestro mailbox, abrimos la carpeta apropiada, y obtenemos nuestros mensajes. También, no debemos olvidarnos de cerrar la conexión cuando hayamos terminado.

String host = ...;

String username = ...;

String password = ...;

// Create empty properties

Properties props = new Properties();

// Get session

Session session = Session.getDefaultInstance(props, null);

// Get the store

Store store = session.getStore("pop3");

store.connect(host, username, password);

// Get folder

Folder folder = store.getFolder("INBOX");

folder.open(Folder.READ_ONLY);

// Get directory

Message message[] = folder.getMessages();

for (int i=0, n=message.length; i<n; i++) {

System.out.println(i + ": " + message[i].getFrom()[0]

+ "\t" + message[i].getSubject());

}

// Close connection

folder.close(false);

store.close();

Lo que hagamos con cada mensaje es cosa nuestra. El bloque de código anterior sólo muestra de quién viene el mensaje y el subject. Técnicamente hablando, la lista de direcciones "from"

podría estar vacía y la llamada a getFrom()[0] podría lanzar una excepción.

Para mostrar el mensaje completo, podemos pedírselo al usuario después de haya visto los

campos subject, y luego llamar al método writeTo() si quiere verlo.

BufferedReader reader = new BufferedReader (

new InputStreamReader(System.in));

// Get directory

Message message[] = folder.getMessages();

for (int i=0, n=message.length; i<n; i++) {

System.out.println(i + ": " + message[i].getFrom()[0]

+ "\t" + message[i].getSubject());

System.out.println("Do you want to read message? " +

"[YES to read/QUIT to end]");

String line = reader.readLine();

if ("YES".equals(line)) {

message[i].writeTo(System.out);

} else if ("QUIT".equals(line)) {

break;

}

}

Aquí tienes el código fuente GetMessageExample.java completo.

Page 14: API JavaMail

Borrar Mensajes y Banderas

Borrar mensajes implica trabajar con lasFlags asociadas con los mensajes. Hay diferentes banderas para diferentes estados, algunas definidas por el sistema y otras definidas por el

usuario. Las banderas predefinidas se definen en forma de clase interna Flags.Flag y se listan

abajo:

Flags.Flag.ANSWERED

Flags.Flag.DELETED

Flags.Flag.DRAFT

Flags.Flag.FLAGGED

Flags.Flag.RECENT

Flags.Flag.SEEN

Flags.Flag.USER

Sólo porque una bandera exista no significa que sea soportada por todos los proveedores/servidores de correo. Por ejemplo, excepto la de mensaje borrado, el protocolo POP no soporta ninguna de ellas. Chequear por nuevo correo no es una tarea de POP pero si está construidad en los clientes de correo. Para conocer las banderas soportadas, solicitamos

la carpeta congetPermanentFlags().

Para borrar mensajes, seleccionamo la bandera DELETED del mensaje:

message.setFlag(Flags.Flag.DELETED, true);

Primero debemos abrir la carpeta en modo READ_WRITE:

folder.open(Folder.READ_WRITE);

Luego, cuando hayamos procesado todos los mensajes, cerramos la carpeta, pasando un valor true para purgar todos los mensajes borrados.

folder.close(true);

Hay un método expunge() de Folder que puede usarse para borrar los mensajes. Sin embargo, no funciona con el proveedor POP3 de Sun.

Otros proveedores podrían o no podrían implementar estas capacidades. Serían más que las implementadas por los proveedores de IMAP. Como POP sólo soporta acceso al mailbox, nosotros tenemos que cerrar la carpeta para borrar los mensajes con el proveedor de Sun.

Para deseleccionar una bandera, sólo pasando false al método setFlag(). Para ver si una

bandera está seleccionada, lo comprobamos con isSet().

Autentificación

Aprendimos anteriormente que podemos usar un Authenticator para pedir un nombre de usuario y una password cuando sea necesario, en vez de pasarlo en strings. Aquí veremos como hacer un uso más útil de la autentificación.

En lugar de conectar al Store con el host, el username, y la password, configuramos

las Properties que tiene el host, y le decimos a la Session el ejemplar

del Authenticator personalizado:

// Setup properties

Page 15: API JavaMail

Properties props = System.getProperties();

props.put("mail.pop3.host", host);

// Setup authentication, get session

Authenticator auth = new PopupAuthenticator();

Session session = Session.getDefaultInstance(props, auth);

// Get the store

Store store = session.getStore("pop3");

store.connect();

Luego subclasificamos Authenticator y devolvemos un

objeto PasswordAuthentication desde el métodogetPasswordAuthentication(). Abajo tenemos una implementación de dicho método, con un sólo campo para ámbos. Sólo debemos introducir las dos partes en un campo, separadas por una coma.

import javax.mail.*;

import javax.swing.*;

import java.util.*;

public class PopupAuthenticator extends Authenticator {

public PasswordAuthentication getPasswordAuthentication() {

String username, password;

String result = JOptionPane.showInputDialog(

"Enter 'username,password'");

StringTokenizer st = new StringTokenizer(result, ",");

username = st.nextToken();

password = st.nextToken();

return new PasswordAuthentication(username, password);

}

}

Como el PopupAuthenticator trata con Swing, arrancará el thread de manejo de eventos para

el AWT. Esto básicamente requiere que añadamos una llamada a System.exit() en nuestro

código para parar el programa.

Responder a Mensajes

La clase Message incluye un método reply() para configurar un nuevo Message con el recipiente apropiado, añadiendo "Re: " al subject si no está ya. Esto no añade nada al contenido del mensaje, sólo copia las cabeceras from o reply-to al nuevo recipiente. El método toma un parámetro booleano indicando si la respuesta va aser a uno (false) o a todos (true).

MimeMessage reply = (MimeMessage)message.reply(false);

reply.setFrom(new InternetAddress("[email protected]"));

reply.setText("Thanks");

Transport.send(reply);

Para configurar la dirección reply-to cuando se envía un mensaje, utilizamos el método setReplyTo().

Aquí tienes el código fuente ReplyExample.java completo.

Page 16: API JavaMail

Re-Enviar Mensajes

Re-enviar mensajes es un poco más complicado. No hay una sóla llamada a método, y construimos el mensaje a re-enviar trabajando con las partes que componen un mensaje.

Un mensaje de correo puede estar compuesto de varias partes, cada parte es un BodyPart, o

más específiamente, unMimeBodyPart cuando se trabaja con mensajes MIME. Las diferentes

partes del cuerpo se combinan en un contenedor llamado Multipart o, de nuevo, más

especificamente un MimeMultipart.

Para re-enviar un mensaje, creamos una parte para el texto de nuestro mensaje y una segunda

parte con el mensaje a re-enviar, y las combinamos dentro de un multipart.

Luego añadimos el multipart a un mensaje direccionado apropiadamente y lo enviamos.

Es esto esencialmente. Para copiar el contenido de un mensaje a otro, sólo lo copiamos sobre

su DataHandler, una clase del JavaBeans Activation Framework.

// Create the message to forward

Message forward = new MimeMessage(session);

// Fill in header

forward.setSubject("Fwd: " + message.getSubject());

forward.setFrom(new InternetAddress(from));

forward.addRecipient(Message.RecipientType.TO,

new InternetAddress(to));

// Create your new message part

BodyPart messageBodyPart = new MimeBodyPart();

messageBodyPart.setText(

"Here you go with the original message:\n\n");

// Create a multi-part to combine the parts

Multipart multipart = new MimeMultipart();

multipart.addBodyPart(messageBodyPart);

// Create and fill part for the forwarded content

messageBodyPart = new MimeBodyPart();

messageBodyPart.setDataHandler(message.getDataHandler());

// Add part to multi part

multipart.addBodyPart(messageBodyPart);

// Associate multi-part with message

forward.setContent(multipart);

// Send message

Transport.send(forward);

Trabajar con Attachments

Los Attachments son recursos asociados con un mensaje e-mail, normalmente mantenidos fuera del mensaje, como un fichero de texto, una hoja de cálculo o una imagen. Al igual que con los programas de e-mail normales como Eudora y Pine, podemos adjuntar recursos a nuestros mensajes con el API JavaMail y obtener dichos attachments cuando recibamos el mensaje.

Enviar Attachments

Enviar attachments es bastante sencillo. Construimos las partes de un mensaje completo. Después de la primera parte, el texto del mensaje, añadimos otras partes donde

Page 17: API JavaMail

el DataHandler para cada una es nuestro attachment, en vez de compartir el handler como en el caso de reenvio de mensajes. Si estamos leyendo el attachment desde un fichero, nuestra fuente de datos es un FileDataSource.

Si leemos desde una URL, es una URLDataSource.

Una vez que tenemos nuestro DataSource, se lo pasamos al constructor de DataHandler, y

finalmente lo adjutamos alBodyPart con setDataHandler().

Asumiendo que queremos retener el nombre del fichero original para el attachment, la última cosa a hacer es seleccionar el nombre de fichero asociado con el attachment con el

método setFileName() de BodyPart. Todo esto lo podemos ver aquí:

// Define message

Message message = new MimeMessage(session);

message.setFrom(new InternetAddress(from));

message.addRecipient(Message.RecipientType.TO,

new InternetAddress(to));

message.setSubject("Hello JavaMail Attachment");

// Create the message part

BodyPart messageBodyPart = new MimeBodyPart();

// Fill the message

messageBodyPart.setText("Pardon Ideas");

Multipart multipart = new MimeMultipart();

multipart.addBodyPart(messageBodyPart);

// Part two is attachment

messageBodyPart = new MimeBodyPart();

DataSource source = new FileDataSource(filename);

messageBodyPart.setDataHandler(new DataHandler(source));

messageBodyPart.setFileName(filename);

multipart.addBodyPart(messageBodyPart);

// Put parts in message

message.setContent(multipart);

// Send the message

Transport.send(message);

Cuando incluimos attachments con nuestros mensajes, si nuestro programa es un servlet, los usuarios deben subir el fichero cuando nos digan donde enviar el mensaje. La subida de cada

fichero puede ser manejada con un tipo de formulario codificado multipart/form-data.

<FORM ENCTYPE="multipart/form-data"

method=post action="/myservlet">

<INPUT TYPE="file" NAME="thefile">

<INPUT TYPE="submit" VALUE="Upload">

</FORM>

Nota: El tamaño del mensaje está limitado por el servidor SMTP, no por el API

JavaMail. Si tenemos problemas podemos incrementar el tamaño de la pila seleccionado

los parámetros ms ymx.

Aquí tienes el código fuente MailExample.java completo.

Page 18: API JavaMail

Obtener Attachments

Obtener attachments de nuestros mensajes es un poco más complicado que enviarlos, ya que MIME no tiene la sencilla noción de Attachments. El contenido de nuestro mensaje es un

objeto Multipart cuando tiene attachments. Entonces necesitamos procesar cada Part, para obtener el contenido principal del attachment(s). Las partes marcadas con una disposición

de Part.ATTACHMENT desde part.getDisposition() son claramente attachments. Sin embargo, los attachments también pueden venir sin disposición (y un tipo MIME no texto) o una

disposición de Part.INLINE. Cuando la disposición es Part.ATTACHMENT o Part.INLINE,

podemos grabar el contenido de esa parte del mensaje.

Obtenemos el nombre del fichero original con getFileName() y el stream de entrada

con getInputStream().

Multipart mp = (Multipart)message.getContent();

for (int i=0, n=multipart.getCount(); i<n; i++) {

Part part = multipart.getBodyPart(i));

String disposition = part.getDisposition();

if ((disposition != null) &&

((disposition.equals(Part.ATTACHMENT) ||

(disposition.equals(Part.INLINE))) {

saveFile(part.getFileName(), part.getInputStream());

}

}

El método saveFile() sólo crea un File desde el nombre del fichero, lee los bytes desde el stream de entrada y los escribe en el fichero. En el caso de que el fichero ya exista, se añade un número al final del nombre del fichero hasta que se encuentre uno que no exista.

// from saveFile()

File file = new File(filename);

for (int i=0; file.exists(); i++) {

file = new File(filename+i);

}

El código de arriba cubre el caso más sencillo cuando las partes del mensaje se marcan apropiadamente. Para cubrir todos los casos. Debemos manejar cuando la disposición es null y obtener el tipo MIME de la parte para manejarla de forma apropiada.

if (disposition == null) {

// Check if plain

MimeBodyPart mbp = (MimeBodyPart)part;

if (mbp.isMimeType("text/plain")) {

// Handle plain

} else {

// Special non-attachment cases here of image/gif, text/html, ...

}

...

}

Procesar Mensajes HTML

Enviar mensajes basados en HTML puede dar un poco más de trabajo que enviar mensaje sólo de texto, aunque no demaisado. Todo depende de los requerimientos que especifiquemos.

Page 19: API JavaMail

Enviar Mensajes HTML

Si todo lo que necesitamos hacer es enviar el equivalente de un fichero HTML como el mensaje y dejar que el lector de correo se preocupe de colocar cualquier imagen embebida o piezas

relacionadas, usamos el método setContent() de Message, pasandole el contenido como

un String y selecionando el tipo de contenido como text/html.

String htmlText = "<H1>Hello</H1>" +

"<img src=\"http://www.jguru.com/images/logo.gif\">";

message.setContent(htmlText, "text/html"));

En la parte del receptor, si procesamos el mensaje con el API JavaMail, no hay nada dentro del API para mostrar mensajes HTML. El API JavaMail sólo ve un stream de bytes. Para mostrar el

mensaje HTML, debemos usar un JEditorPane de Swing o cualquier otro componente

visualizador de terceras partes.

if (message.getContentType().equals("text/html")) {

String content = (String)message.getContent();

JFrame frame = new JFrame();

JEditorPane text = new JEditorPane("text/html", content);

text.setEditable(false);

JScrollPane pane = new JScrollPane(text);

frame.getContentPane().add(pane);

frame.setSize(300, 300);

frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

frame.show();

}

Includir Imágenes en Nuestos Mensajes

Por otro lado, si queremos que nuestro mensaje HTML sea completo, con imagenes embebidas incluidas como parte del mensaje, debemos tratar las imágenes como un attachment y referenciarlas con una URL especial cid, donde el cid es una referencia a la

cabecera Content-ID de la imagen adjunta.

El proceso de embeber imágenes es muy similar a adjuntar un fichero a un mensaje, la única

diferencia es que tenemos que decirle al MimeMultipart que las partes están relacionadas

configurando su subtipo en el constructor (o consetSubType()) y configurando la

cabecera Content-ID de la imagen a un string aleatorio que es usado como el src de la

imagen en la etiqueta img.

Este código explica todo lo anterior:

String file = ...;

// Create the message

Message message = new MimeMessage(session);

// Fill its headers

message.setSubject("Embedded Image");

message.setFrom(new InternetAddress(from));

message.addRecipient(Message.RecipientType.TO,

new InternetAddress(to));

// Create your new message part

BodyPart messageBodyPart = new MimeBodyPart();

String htmlText = "<H1>Hello</H1>" +

"<img src=\"cid:memememe\">";

messageBodyPart.setContent(htmlText, "text/html");

// Create a related multi-part to combine the parts

Page 20: API JavaMail

MimeMultipart multipart = new MimeMultipart("related");

multipart.addBodyPart(messageBodyPart);

// Create part for the image

messageBodyPart = new MimeBodyPart();

// Fetch the image and associate to part

DataSource fds = new FileDataSource(file);

messageBodyPart.setDataHandler(new DataHandler(fds));

messageBodyPart.setHeader("Content-ID","memememe");

// Add part to multi-part

multipart.addBodyPart(messageBodyPart);

// Associate multi-part with message

message.setContent(multipart);

Aquí tienes el código fuente HtmlImageExample.java completo.

Page 21: API JavaMail

Buscar Con SearchTerm o Búsquedas con SearchTerm o Recursos

Buscar Con SearchTerm

Búsquedas con SearchTerm

El API JavaMail incluye un mecanismo de filtrado encontrado en el paquete

javax.mail.search para construir unSearchTerm.

Una vez construido, podemos solicitarel a una Folder qué mensajes concuerdan, recuperar un

array de objetos Message:

SearchTerm st = ...;

Message[] msgs = folder.search(st);

Hay disponibles 22 clases diferentes para ayudarnos a construir un SearchTerm.

AND (clase AndTerm)

OR (clase OrTerm)

NOT (clase NotTerm)

SENT DATE (clase SentDateTerm)

CONTENT (clase BodyTerm)

HEADER (FromTerm / FromStringTerm, RecipientTerm/ RecipientStringTerm, SubjectTerm,

etc.)

Esencialmente, construimos una expresión lógica para concordar mensajes, luegos los buscamos. Por ejemplo, el siguiente término busca los mensajes con uns string (parcial) en el

sibject de ADV o un campo "from" [email protected].

Podríamos considerar la ejecución periódica de esta consulta y borrar automáticamente cualquier mensaje devuelto.

SearchTerm st =

new OrTerm(

new SubjectTerm("ADV:"),

new FromStringTerm("[email protected]"));

Message[] msgs = folder.search(st);

Recursos

Se pueden hacer muchas más cosas con el API JavaMail que las descritas aquí. Podrás encontrarlas en las sigueintes direcciones:

JavaMail API Home

JavaBeans Activation Framework Home

javamail-interest mailing list

Sun's JavaMail FAQ

jGuru's JavaMail FAQ

Third Party Products List

Page 22: API JavaMail