Introduzione
All'interno
delle funzionalità offerte dalla piattaforma
Java, si trova anche il supporto alla po-sta elettronica,
realizzato tramite le API JavaMail. Questa libreria
offre le funzionalità necessa-rie ad implementare
applicazioni di email completamente funzionanti, come
Outlook o Netsca-pe Mail. Non essendo realizzata con
componenti visuali - la creazione di una interfaccia
utente è interamente a carico dello sviluppatore
- è utilizzabile sia in applicazioni desktop
che sul lato server, ad esempio per implementare una
WebMail.
Figura 1 - Tipologie di client di posta elettronica
(clicca per ingrandire l'immagine)
Come
noto, esistono diversi protocolli che consentono ad
una applicazione di realizzare la po-sta elettronica.
I principali sono tre:
- SMTP
(Simple Mail Transfer Protocol). Consente l'invio
di un messaggio di posta;
- POP
(Post Office Protocol). Protocollo comunemente utilizzato
per la ricezione di messaggi di posta da un server;
- IMAP
(Internet Message Access Protocol). Protocollo di
posta orientato al server e di tipo drop-and-store,
più evoluto rispetto a POP e dotato di funzionalità
di gestione del server che facilita la gestione della
posta off-line.
Attualmente
le versioni più diffuse sono la 3 per POP e la
4 per IMAP.
JavaMail, come vedremo, supporta tutti questi protocolli,
ma non ne è limitato, in quanto im-plementa un'architettura
a provider, che consente di svincolare le applicazioni
dal reale proto-collo utilizzato, creando una astrazione
di un completo sistema di posta elettronica. In modo
similare a quanto avviene in JDBC, dove la comunicazione
effettiva al database avviene trami-te driver specifici,
allo stesso modo JavaMail si astrae dai protocolli specifici,
che sono co-munque forniti assieme al package principale.
Si
noti che le implementazione dei provider di riferimento
appartengono al package sun.* e non a javax.*. Non sono
quindi API standard facenti parte delle specifiche di
JavaMail.
Le
piattaforme
Il package JavaMail è ottenibile in due diversi
modi, per prima cosa è possibile scaricare l'implementazione
di riferimento e la documentazione dal sito ufficiale
ospitato da SUN, che si trova all'indirizzo http://java.sun.com/products/javamail/.
Il package è utilizzabile all'interno di un ambiente
J2SE a partire dalla versione 1.1.7, e richiede anche
il JavaBeans Activation Framework (http://java.sun.com/products/javabeans/glasgow/jaf.html)
un package forse poco famoso, che ha lo scopo di abilitare
la gestione, all'interno di applicazioni Java, di blocchi
di dati di tipo arbitrario, incapsulandoli ed accedendovi,
e di scoprire le operazioni effettuabili su di essi.
Esempi sono le immagini JPEG o GIF, oppure documenti
Word od Excel; l'Activation Framework è utilizzato
all'interno di JavaMail per supportare gli allegati
binari ai messaggi di posta ed anche per scoprire a
runtime il tipo di dato memorizzato all'interno di un
blocco bina-rio.
Se invece si sta utilizzando la piattaforma Java2 Enterprise
Edition (J2EE), a partire dalla ver-sione 1.3, non è
necessario scaricare né l'una, né l'altra,
in quanto i servizi legati alla posta e-lettronica sono
parte fondamentale e formante della piattaforma enterprise.
Ovviamente le modalità d'accesso cambieranno
leggermente nelle due piattaforme, in modo similare
alle differenze che esistono in JDBC per accedere ad
una connessione al database in una applicazione J2SE
ed in una applicazione J2EE, ma il corpo delle funzionalità
rimane il medesimo.
Invio
di un messaggio
Per illustrare con semplicità un utilizzo pratico
di JavaMail, si osservi il listato 1, che imple-menta
un semplice programma di invio di un messaggio di posta,
forse il più semplice realiz-zabile con queste
API. La prima cosa che si nota è la presenza
dell'importazione dei package javax.mail e javax.mail.internet,
due componenti principali di JavaMail.
All'interno del primo package si trovano le classi principali,
come Session e Message, utilizzati nel programma per
l'invio del messaggio; la prima classe - di tipo final
- implementa una ses-sione di posta ed ha lo scopo di
raccogliere proprietà e configurazioni e di fornire
le sessioni alle classi client. Le sessioni possono
essere di due tipi: condivise o meno; nel primo caso
una unica sessione viene utilizzata da parte di più
sezioni del programma, tipicamente in una appli-cazione
desktop. In ambiente server è invece preferibile
utilizzare sessioni non condivise, otte-nute in modo
similare a come in JDBC si ottiene una connessione da
un DataSource.
Per ottenere una sessione condivisa è necessario
utilizzare il metodo Sessione.getDefaultInstance() a
cui è indispensabile passare un oggetto Properties
con i parame-tri di configurazione necessari ad operare
con il protocollo di posta. L'unico parametro indi-spensabile
in questo caso è mail.smtp.host, che indica il
nome o l'indirizzo del server SMTP di invio.
Il programma poi crea un oggetto Message di tipo MimeMessage
e ne imposta le proprietà. In particolare:
- il
mittente;
- il
destinatario;
- l'oggetto;
- la
data di invio;
- il
testo del messaggio.
Questi
parametri sono impostati tramite i metodi riassunti
in tabella 1 che nella classe Message sono astratti,
mentre in MimeMessage sono effettivamente implementati.
Tabella 1 - Alcuni metodi della classe Message
A
questo punto è possibile inviare il messaggio
utilizzando il metodo Transport.send(). Questo metodo
si occuperà dunque di individuare tutti i destinatari
(tramite Message.getAllRecipients()) ed ad inviargli
il messaggio, utilizzando il trasporto appropriato per
ciascun destinatario (alcuni di questi potrebbero non
essere destinatari Internet).
Gli indirizzi sono infatti stati rappresentati con oggetti
InternetAddress (classe presente nel package javax.mail.internet),
classe che rappresenta indirizzi nella forma nome@server.dominio
e che estende javax.mail.Address.
Il metodo send() può sollevare due eccezioni
nel caso l'invio non vada a buon fine: SendFaildException
e MessagingException entrambi presenti nel package javax.mail.
Si
noti che send() può eseguire un invio parziale.
Se ad esempio un messaggio è indirizzato a più
destina-tari, chiamiamoli Mario, Giovanni, Andrea, Luca,
Elisa e Maurizio nell'ordine e l'invio fallisce per
Gio-vanni, Luca e Maurizio, l'invio a Mario, Andrea
ed Elisa (chi mancava dall'elenco precedente) viene
co-munque fatto. Al termine delle operazioni viene sollevata
una eccezione che riassume quanto successo: fornisce
l'elenco dei destinatari per cui l'invio è andato
a buon fine e l'elenco dei destinatari per cui l'invio
non è riuscito.
Listato
1 - Invio.java
package com.mokabyte.mokabook2.javamail;
import
java.util.*;
import javax.mail.*;
import javax.mail.internet.*;
public
class Invio {
public static void main( String[] args ) {
try
{
Properties props = System.getProperties();
props.put( "mail.smtp.host",
args[2] );
Session session = Session.getDefaultInstance(
props );
Message message = new MimeMessage(
session );
InternetAddress from = new InternetAddress(
args[0] );
InternetAddress to[] = InternetAddress.parse(
args[1] );
message.setFrom( from );
message.setRecipients( Message.RecipientType.TO,
to );
message.setSubject( args[3]
);
message.setSentDate( new Date()
);
message.setText( args[4] );
Transport.send(message);
} catch(MessagingException e)
{
e.printStackTrace();
}
}
}
Per
eseguire l'esempio è possibile utilizzare il
file di Ant build.xml fornito con il codice sor-gente,
ma è necessario modificare i parametri che riguardano
il destinatario ed il server SMTP da utilizzare. Per
inviare il messaggio di prova digitare poi:
ant
invio
La porzione di script di Ant che si occupa di ereguire
il programma è la seguente:
<target
name="testInvio">
<java classname="com.mokabyte.mokabook2.javamail.Invio"
fork="yes">
<classpath refid="project-classpath"/>
<arg value="sender@null.it" />
<arg value="max@bigatti.it" />
<arg value="mail.tin.it" />
<arg value="[Mokabyte] - Messaggio di prova"
/>
<arg value="Questo e' un messaggio di prova
per verificare l'invio di un messaggio attraverso le
API di SUN Javamail. Questo package implementa una astrazione
di un sistema di posta elettronica fornendo anche provider
per i protocolli SMTP, IMAP e POP3" />
</java>
</target>
Nota:
l'elenco delle librerie richieste per eseguire gli esempi
sono: activation.jar, imap.jar, mailapi.jar, pop3.jar,
smtp.jar.
Se
tutto funziona correttamente, si dovrebbe essere in
grado di ricevere il messaggio ed ottene-re qualcosa
simile al quanto presente in figura 2.
Figura 2 - Il messaggio ricevuto dal programma "Invio"
(clicca per ingrandire l'immagine)
Ricevere
messaggi
Implementando un completo insieme di funzionalità
per la gestione della posta elettronica, co-me accennato
JavaMail dispone anche del supporto alla ricezione di
messaggi di posta elettro-nica, tramite l'accesso a
server di posta come POP e IMAP.
Il supporto alla ricezione dei messaggi è inserito
al più ampio contesto dei folder, contenitori
di messaggi che ricalcano concettualmente le caselle
di posta dei programmi di email, come la posta in arrivo,
la posta in uscita e la posta inviata.
La classe Folder, presente nel package javax.mail, rappresenta
un folder astratto che può conte-nere messaggi
(oggetti Message), altri folder o entrambi in modo gerarchico
sotto forma di al-bero. Le sottoclassi di Folder, come
IMAPFolder e POP3Folder, completano l'infrastruttura
im-plementando gli specifici protocolli, limitando eventualmente
la flessibilità nella costruzione di gerarchie
di Folder, nel caso il protocollo specifico non supporti
questa possibilità. I Folder la-vorano in stretto
contatto con gli oggetti Store, che si occupano invece
di fornire un modello per la memorizzazione dei messaggi,
per il protocollo di accesso e per l'ottenimento dei
mes-saggi. Anche in questo caso Store è una classe
astratta usata come superclasse da IMAPStore e POP3Store,
le due implementazioni fornite da JavaMail.
Il
nome completo di un folder può avere significati
diversi in funzione dell'implementazione concreta del
folder, anche se il nome "INBOX" è
riservato per indicare il folder principale del server,
ma si noti che le implementazioni di Store devono obbligatoriamente
fornire un IN-BOX. Se il folder primario per un certo
protocollo esiste, si chiamerà INBOX, in caso
contrario non ci sarà nessun folder con questo
nome e la chiamata Folder.getFolder("INBOX")
ritornerà null; per verificare l'esistenza di
un folder è però consigliato utilizzare
il metodo Folder.exists().
I
passi per leggere da una casella di posta prevedono
dunque, dopo l'ottenimento di un oggetto Session, il
recupero dell'oggetto Store a partire dalla sessione,
tramite il metodo Session.getStore(). Questo ritornerà
un oggetto Store in funzione del protocollo configurato
nel-la proprietà mail.store.protocol; in alternativa
è possibile chiamare il metodo Session.getStore(string)
e fornire direttamente il protocollo desiderato, come
ad esempio "pop3". Se il protocollo richiesto
non viene trovato, viene sollevata una eccezione NoSuchProviderException.
Una
volta ottenuto l'oggetto Folder che rappresenta la casella
richiesta, è necessario aprirla tramite il metodo
open(), che si aspetta un parametro modo, che può
valere Folder.READ_ONLY e Folder.READ_WRITE; una volta
aperto il folder è possibile leggerne i messaggi
con il metodo getMessages() (per una panoramica dei
metodi di Folder si veda la ta-bella 2).
Tabella 2 - Metodi della classe Folder
Nel
listato 2 è presente un esempio di lettura di
messaggi che utilizza un server POP3. Come si vede l'implementazione
ricalca la procedura sopra esposta; nel visualizzare
i messaggi è stato implementato un controllo
sul mittente. Di norma il metodo getPersonal() su un
oggetto InternetAddress fornisce il nome del mittente,
ma non sempre. Alcune volte il metodo ritorna null ed
è dunque necessario rivolgersi al metodo toString()
per ottenere una rappresentazione significativa dell'indirizzo.
Listato
2 - Ricezione.java
package com.mokabyte.mokabook2.javamail;
import
java.util.*;
import
javax.mail.*;
import javax.mail.internet.*;
public
class Ricezione {
public static void main(String args[]) {
try {
Properties props = System.getProperties();
Session session = Session.getDefaultInstance(props,
null);
Store store = session.getStore("pop3");
store.connect(args[0],
args[1], args[2]);
Folder folder = store.getDefaultFolder();
if (folder != null) {
folder = folder.getFolder("INBOX");
if (folder
!= null) {
folder.open(Folder.READ_ONLY);
Message[]
elencoMessaggi = folder.getMessages();
for
(int indice = 0; indice < elencoMessaggi.length;
indice++) {
Message
messaggio = elencoMessaggi[ indice ];
InternetAddress
fromAddress = (InternetAddress)messaggio.getFrom()[0];
String
from = fromAddress.getPersonal();
if(
from == null ) {
from
= fromAddress.toString();
}
System.out.println("DA:"
+ from + " OGGETTO: " + messaggio.getSubject()
+
"
DATA: " + messaggio.getSentDate()
);
}
folder.close(false);
} else {
System.out.println(
"Folder non trovato" );
}
} else {
System.out.println(
"Folder di default non trovato" );
}
store.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
Per
eseguire l'esempio utilizzare il comando:
Ant
ricezione
La
porzione di script di Ant eseguita è la seguente
(attenzione anche in questo caso ad indicare i parametri
di configurazione corretti):
<target
name="testRicezione">
<java classname="com.mokabyte.mokabook2.javamail.Ricezione"
fork="yes">
<classpath refid="project-classpath"/>
<arg value="pop3.server.it" />
<arg value="max/bigatti.it" />
<arg value="password" />
</java>
</target>
Un
tipico output è simile al seguente (riformattato):
DA:Apple Developer Connection
OGGETTO: ADC News #372
DATA: Sun Oct 26 03:37:20 CET 2003
DA:Apple
iCards
OGGETTO: Massimiliano Bigatti has sent you an Apple
iCard
DATA: Thu Oct 30 10:17:28 CET 2003
DA:mrossi@tiscalinet.it
OGGETTO: orologio a mano...
DATA: Thu Oct 30 18:03:12 CET 2003
DA:sender@null.it
OGGETTO: [Mokabyte] - Messaggio di prova
DATA: Thu Oct 30 18:49:52 CET 2003
DA:sender@null.it
OGGETTO: [Mokabyte] - Messaggio di prova
DATA: Thu Oct 30 18:50:48 CET 2003
Conclusioni
In questa puntata sono state affrontate le classi che
consentono l'invio e la ricezione dei mes-saggi di posta
elettronica tramite SMTP e POP3; nella prossima verranno
descritti gli eventi ed i messaggi multipart.
Link e risorse
[1] JavaMail QuickStart - http://www.javaworld.com/javaworld/jw-10-2001/jw-1026-javamail.html
[2] Managing ezines with JavaMail and XSLT, Part 2 -
http://www-106.ibm.com/developerworks/xml/library/x-xmlist2/?open&l=842%2Ct=gr%2Cp=JavaMail2
[3] Fundamentals of the JavaMail API short course -
http://developer.java.sun.com/developer/onlineTraining/JavaMail/contents.html
[4] JavaMail Homepage - http://java.sun.com/products/javamail/
[5] JavaMail API documentation - http://java.sun.com/products/javamail/javadocs/index.html
[6] JavaBeans Activation Framework - http://java.sun.com/products/javabeans/glasgow/jaf.html
|