Kapitel 11 JavaMail

Det er let at kommunikere via TCP/IP ved hjælp af Java. Alle Internet-protokollerne (ftp, http, smtp, pop3 og så videre) bygger på TCP/IP, og derfor er det også relativt let at kommunikere ved hjælp af disse protokoller. Med JavaMail bliver det imidlertid endnu lettere, hvis man vil bruge en af de protokoller, som anvendes til at sende post. Bruger man JavaMail behøver man slet intet kendskab til den underliggende protokol. Man kan blot anvende de metoder, API’et stiller til rådighed til at hente og sende post.

Du læser en gammel bog
Den bog, du læser her, er fra 1998, og mange ting kan have ændret sig siden da.
Vi håber, at du stadig kan finde relevant information i den.
Hvis du vil læse aktuelle oplysninger om de avancerede dele af Java, anbefaler vi
bogen Core Java – Advanced Features

JavaMail er en udvidelse af Java Development Kit og ikke en integreret del. Det betyder, at API’et skal downloades separat. Det betyder også, at de klasser, man skal bruge, hedder javax.* i stedet for java.*.

 

Terminologien

 

Inden man går i gang med at bruge JavaMail, bør man sætte sig ind i JavaMails terminologi. Mailserveren er den computer, der kører det program, der håndterer posten. Nogle programmer er implementeret således, at der skal bruges et program til afsendelse af post og et program til modtagelse af post. I dette kapitel vil udtrykket mailserver dække over begge programmer.

 

Klientprogrammet er det program, der kontakter mailserveren. Det er dette program, brugeren benytter til afsendelse og modtagelse af post. Kommunikationen mellem klientprogrammet og mailserveren kaldes en session. Det brev, der afsendes kaldes en besked. Beskeder består af en header og en brødtekst. Brødteksten er selve den tekst, beskeden består af. Headeren indeholder informationer om afsenderen, modtagerne og beskedens overskrift. Det er muligt at tilføje egne informationer til headeren – det vil blive gennemgået senere.

 

Opsætning af systemet

 

Inden man kan begynde at bruge JavaMail, skal man indstille sit system, så det ved, hvordan posten skal behandles. Dette gør man ved hjælp af setProperty-metoden, der er en statisk metode i klassen System. Metoden har følgende signatur

 

System.setProperty (String key, String value);

 

key angiver den property, der skal sættes, mens value angiver værdien. Nedenstående tabel viser de properties, det kan være nødvendigt at sætte for at få JavaMail til at fungere.

 

 

 

Property Beskrivelse
mail.store.protocol Angiver store-protokollen. Session.getStore()-metodekaldet returnerer et Store-objekt, der understøtter denne protokol. Man kan vælge at bruge en anden protokol ved at angive denne i kaldet til Session.getTransport(String protokol).
mail.transport.protocol Angiver den protokol, transporten skal benytte. Session.getTransport returnerer et Transport-objekt, der implementerer denne protokol. Man kan vælge at benytte en anden protokol ved at kalde Session.getTransport (String protokol).
mail.host Angiver mailserveren. Hvis denne property ikke er angivet, forsøges den lokale maskine brugt som mailserver.
mail.user Angiver det brugernavn, der skal bruges, når der tilsluttes til en mailserver.
Mail.protokol.host Angiver en protokolafhængig mailserver. Denne overskriver mail.host-vædien.
mail.protokol.user Angiver et protokolafhængigt brugernavn. Dette overskriver mail.user-værdien.
mail.from Angiver brugerens returadresse. Denne værdi bliver brugt af InternetAddress.getLocalAddress(). Angives denne ikke sættes det til at være user@host.

 

 

Afsendelse af en besked

 

Med terminologien og indstillingerne på plads kan man med god samvittighed begynde at bruge JavaMail. Det første der skal oprettes, er et Session-objekt. Session-klassen har nedenstående signatur:

 

public final class Session extends java.lang.Object

{

public static javax.mail.Session getInstance(java.util.Properties, javax.mail.Authenticator);

public static javax.mail.Session getDefaultInstance(java.util.Properties, javax.mail.Authenticator);

public void setDebug(boolean);

public boolean getDebug();

public javax.mail.Provider[] getProviders();

public javax.mail.Provider getProvider(java.lang.String);

public void setProvider(javax.mail.Provider);

 

 

public javax.mail.Store getStore();

public javax.mail.Store getStore(java.lang.String);

public javax.mail.Store getStore(javax.mail.URLName);

public javax.mail.Store getStore(javax.mail.Provider);

public javax.mail.Folder getFolder(javax.mail.URLName);

public javax.mail.Transport getTransport();

public javax.mail.Transport getTransport(java.lang.String);

public javax.mail.Transport getTransport(javax.mail.URLName);

public javax.mail.Transport getTransport(javax.mail.Provider);

public javax.mail.Transport getTransport(javax.mail.Address);

public void setPasswordAuthentication(javax.mail.URLName, javax.mail.PasswordAuthentication);

public javax.mail.PasswordAuthentication getPasswordAuthentication(javax.mail.URLName);

public javax.mail.PasswordAuthentication requestPasswordAuthentication(java.net.InetAddress, int, java.lang.String, java.lang.String, java.lang.String);

public java.util.Properties getProperties();

public java.lang.String getProperty(java.lang.String);

}

 

Som det ses, har klassen ingen constructor. Når man vil have instanser af klassen, bruger man metoderne getInstance og getDefaultInstance. Forskellen på de to er, at getDefaultInstance returnerer en instans, der kan blive brugt flere gange af det samme program, mens getInstance returnerer en nyoprettet instans. Hvis man kalder getDefaultInstance, og der ikke allerede eksisterer en instans, bliver der oprettet en ny.

 

Begge metoder tager de samme typer parametre. Det drejer sig om en række properties og et Authenticator-objekt. Hvis man satte systemindstillinger efter den metode, der blev gennemgået først i kapitlet, kan man få en reference til systemets indstillinger med kommandoen System.getProperties().

 

Authenticator-objektet bruges til at kontrollere, hvilke andre Java-klasser, der kan få adgang til Session-objektet ved hjælp af getDefaultInstance. Session-objektet indeholder informationer om brugerens navn og adgangskode, og derfor skal det så vidt muligt holdes fortroligt. Hvis man ikke ønsker den fortrolighed, kan man angive null i stedet for et Authenticator-objekt – så vil alle andre klasser kunne få en reference til objektet ved at kalde getDefaultInstance med null som Authenticator-objekt.

 

Hvis man ønsker at sikre sit Session-objekt, må man angive et Authenticator-objekt. Det gøres ved at oprette en klasse, der nedarver fra den abstrakte klasse Authenticator. Denne klasse har følgende signatur:

 

public abstract class Authenticator extends java.lang.Object

{

final javax.mail.PasswordAuthentication requestPasswordAuthentication(java.net.InetAddress, int, java.lang.String, java.lang.String, java.lang.String);

 

protected final java.net.InetAddress getRequestingSite();

protected final int getRequestingPort();

protected final java.lang.String getRequestingProtocol();

protected final java.lang.String getRequestingPrompt();

protected final java.lang.String getDefaultUserName();

protected javax.mail.PasswordAuthentication getPasswordAuthentication();

public javax.mail.Authenticator();

}

 

Oprettelse af beskeden

 

Når man har fået en reference til Session-objektet, kan man oprette selve beskeden. På Internet sendes beskeder i MIME-format – Multipurpose Internet Mail Extensions. Derfor bruger man klassen MimeMessage til at angive en besked. Denne klasse findes i pakken javax.mail.internet og har følgende signatur:

 

public class MimeMessage extends javax.mail.Message implements javax.mail.internet.MimePart

{

public javax.mail.internet.MimeMessage(javax.mail.Session);

public javax.mail.internet.MimeMessage(javax.mail.Session,java.io.InputStream);

public javax.mail.Address[] getFrom();

public void setFrom(javax.mail.Address);

public void setFrom();

public void addFrom(javax.mail.Address[]);

public javax.mail.Address[] getRecipients(javax.mail.Message.RecipientType);

public javax.mail.Address[] getAllRecipients();

public void setRecipients(javax.mail.Message.RecipientType, javax.mail.Address[]);

public void addRecipients(javax.mail.Message.RecipientType, javax.mail.Address[]);

public javax.mail.Address[] getReplyTo();

public void setReplyTo(javax.mail.Address[]);

public java.lang.String getSubject();

public void setSubject(java.lang.String);

public void setSubject(java.lang.String, java.lang.String);

public java.util.Date getSentDate();

public void setSentDate(java.util.Date);

public java.util.Date getReceivedDate();

 

public int getSize();

public int getLineCount();

public boolean isMimeType(java.lang.String);

public java.lang.String getDisposition();

public void setDisposition(java.lang.String);

public java.lang.String getEncoding();

public java.lang.String getContentID();

public void setContentID(java.lang.String);

public java.lang.String getContentMD5();

public java.lang.String getDescription();

public void setDescription(java.lang.String);

public void setDescription(java.lang.String, java.lang.String);

public java.lang.String[] getContentLanguage();

public void setContentLanguage(java.lang.String[]);

public java.lang.Object getContent();

public void setContent(java.lang.Object, java.lang.String);

public void setText(java.lang.String);

public void setText(java.lang.String, java.lang.String);

public void setContent(javax.mail.Multipart);

public javax.mail.Message reply(boolean);

public java.lang.String[] getHeader(java.lang.String);

public java.lang.String getHeader(java.lang.String, java.lang.String);

public void setHeader(java.lang.String, java.lang.String);

public void addHeader(java.lang.String, java.lang.String);

public void removeHeader(java.lang.String);

public java.util.Enumeration getAllHeaders();

public void addHeaderLine(java.lang.String);

public java.util.Enumeration getAllHeaderLines();

public void saveChanges();

protected void updateHeaders();

}

 

Som det ses indeholder MimeMessage-klassen en lang række metoder. For at afsende en besked, behøver man kun kende de færreste af dem. De fleste af metoderne er imidlertid særdeles anvendelige og vil derfor blive gennemgået i løbet af kapitlet.

 

De mest nødvendige metoder er setRecipients, setSubject og setText. Man bruger setRecipients til at angive, hvem der skal modtage beskeden. Der findes tre forskellige former for modtagere:

 

  • Almindelige modtagere
  • CC (Carbon Copy)
  • BCC (Blind Carbon Copy)

 

Alle, der modtager beskeden, kan se de almindelige modtagere og CC-modtagere, mens BCC-modtagerne ikke vises. Man skal dog være opmærksom på, at nogen mailservere ikke understøtter BCC og derfor konverterer dem til CC.

 

 

I JavaMail bruger man setRecipients til at angive alle former for modtagere. Metodens første parameter er en konstant, der angiver hvilken type modtager, der er tale om. Metoden accepterer følgende konstanter, der er defineret i klassen Message.RecipientType:

 

  • Message.RecipientType.TO
  • Message.RecipientType.CC
  • Message.RecipientType.BCC

 

Man skal naturligvis også angive, hvilke personer, der skal modtage beskeden. Det gør man ved hjælp af en række Address-objekter. JavaMail kan både benyttes til at sende beskeder til enkelte personer eller til diskussiongrupper (newsgroups). Derfor findes der to forskellige klasser, som begge nedarver fra Address-klassen. Det drejer sig om NewsAddress, der bruges til at sende beskeder til diskussionsgrupper, og InternetAddress, som bruges til at sende almindelige beskeder. InternetAddress har følgende signatur:

 

public class InternetAddress extends javax.mail.Address

{

public javax.mail.internet.InternetAddress();

public javax.mail.internet.InternetAddress(java.lang.String);

public javax.mail.internet.InternetAddress(java.lang.String,java.lang.String);

public javax.mail.internet.InternetAddress(java.lang.String,java.lang.String,java.lang.String);

 

public java.lang.String getType();

public void setAddress(java.lang.String);

public void setPersonal(java.lang.String, java.lang.String);

public void setPersonal(java.lang.String);

public java.lang.String getAddress();

public java.lang.String getPersonal();

public static java.lang.String toString(javax.mail.Address[]);

public static javax.mail.internet.InternetAddress getLocalAddress(javax.mail.Session);

public static javax.mail.internet.InternetAddress[] parse(java.lang.String);

public static javax.mail.internet.InternetAddress[] parse(java.lang.String, boolean);

}

 

Hvis man vil bruge klassens constructor til at oprette en adresse, kan det gøres på flere forskellige måder. Man kan enten angive adressen som en almindelig adresse eller som en adresse og et virkeligt navn. Nedenstående viser, hvordan man kan angive adresser:

 

new InternetAddress(“salg@post.engroshandel.dk”);

new InternetAddress(“billg@microsoft.com”, “Bill Gates”);

 

 

Opretter man et InternetAddress-objekt uden at angive nogen adresser, eller får man senere brug for at ændre adressen, kan man bruge metoden setAddress og setPersonal.

 

InternetAddress indeholder også statiske metoder til at oversætte tekststrenge til adresser. Det drejer sig om parse-metoderne. Når man angiver en adresse i en tekststreng kan dette ske på tre forskellige måder:

 

  • nil eksempelvis billg@microsoft.com.
  • parens eksempelvis billg@microsoft.com (Bill Gates).
  • angles eksempelvis Bill Gates <billg@microsoft.com>.

 

Bemærk at setRecipients tager et array af adresser som parameter. Derfor kan det være en fordel at bruge parse-funktionen, da denne netop returnerer et array af adresser.

 

Metoden setSubject bruges til at angive beskedens overskrift. Denne er blot en tekststreng. Til at angive brødteksten, bruges metodet setText, der også tager en tekststreng som parameter.

 

Afsendelse af beskeden

 

Afsendelsen af beskeden foretages af Transport-klassen:

 

public abstract class Transport extends java.lang.Object

{

public javax.mail.Transport(javax.mail.Session,javax.mail.URLName);

 

public void connect(java.lang.String, java.lang.String, java.lang.String);

public void connect(java.lang.String, int, java.lang.String, java.lang.String);

public void connect();

public boolean isConnected();

public synchronized void close();

public javax.mail.URLName getURLName();

public static void send(javax.mail.Message);

public static void send(javax.mail.Message, javax.mail.Address[]);

public abstract void sendMessage(javax.mail.Message, javax.mail.Address[]);

}

 

Afsendelsen sker i metoden send, der tager beskeden som parameter. Hvis man ikke har tilføjet modtageradresserne til beskedens header, kan man angive dem som parameter til send-metoden i stedet.

 

Nedenstående program viser, hvordan man kan afsende en besked ved hjælp af JavaMail.

 

import javax.mail.*;

import javax.mail.internet.*;

 

public class sendMail

 

{

public static final void main (String args[]) throws Exception

{

Session session = Session.getDefaultInstance(System.getProperties(), null);

 

Message msg = new MimeMessage(session);

 

String to = “modtager@denne.her.adresse.dk”;

String from = “mig@mit.domaene.dk”;

 

try

{

msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to, false));

msg.setFrom (new InternetAddress(from));

}

catch (AddressException ae)

{

System.err.println (ae.toString());

}

catch (MessagingException me)

{

System.err.println (me.toString());

}

 

try

{

msg.setSubject (“Eksempel”);

msg.setText (“Her er indholdet”);

Transport.send (msg);

}

catch (MessagingException me)

{

System.err.println (me.toString());

}

}

}

 

Hvis man vil have et mere avanceret program til postafsendelse kan man bruge programmet MailSender. Det giver en grafisk brugerflade til beskedafsendelsen og giver mulighed for, at man kan sætte CC og BCC. Hvis man vil have flere modtagere af en type, kan man adskille adresserne med et komma.

 

import java.awt.*;

import java.awt.event.*;

import javax.mail.*;

import javax.mail.internet.*;

 

public class MailSender extends Frame implements ActionListener

{

 

private TextField til, cc, bcc, subject;

private TextArea besked;

private Button send;

private Label status;

 

public MailSender()

{

// Tilpas vinduet

 

super (“Beskedsender”);

setSize (500,400);

 

// Opret komponenter

 

til = new TextField();

cc = new TextField();

bcc = new TextField();

subject = new TextField();

besked = new TextArea();

send = new Button (“Afsend”);

status = new Label (“Beskedsender 1.0”);

 

Panel toPanel = new Panel();

toPanel.setLayout(new GridLayout(1,2));

toPanel.add (new Label (“Til”));

toPanel.add (til);

 

Panel ccPanel = new Panel();

ccPanel.setLayout(new GridLayout(1,2));

ccPanel.add (new Label (“CC”));

ccPanel.add (cc);

 

Panel bccPanel = new Panel();

bccPanel.setLayout(new GridLayout(1,2));

bccPanel.add (new Label (“BCC”));

bccPanel.add (bcc);

 

Panel subjPanel = new Panel();

subjPanel.setLayout(new GridLayout(1,2));

subjPanel.add (new Label (“Overskrift”));

subjPanel.add (subject);

 

Panel topPanel = new Panel();

topPanel.setLayout (new GridLayout(4,1));

topPanel.add (toPanel);

topPanel.add (ccPanel);

topPanel.add (bccPanel);

topPanel.add (subjPanel);

 

Panel buttomPanel = new Panel();

buttomPanel.setLayout(new GridLayout(2,1));

buttomPanel.add (send);

buttomPanel.add (status);

 

 

// Tilføj komponenter

 

add (topPanel, BorderLayout.NORTH);

add (besked, BorderLayout.CENTER);

add (buttomPanel, BorderLayout.SOUTH);

 

// Tilføj eventhåndtering

 

send.addActionListener (this);

}

 

public static final void main (String args[])

{

MailSender me = new MailSender();

me.show();

}

 

public void actionPerformed(ActionEvent e)

{

if (e.getSource() == send)

{

status.setText (“Sender besked…”);

try

{

Session session = Session.getDefaultInstance(System.getProperties(), null);

Message msg = new MimeMessage(session);

 

msg.setRecipients (Message.RecipientType.TO, InternetAddress.parse (til.getText()));

msg.setRecipients (Message.RecipientType.CC, InternetAddress.parse (cc.getText()));

msg.setRecipients (Message.RecipientType.BCC, InternetAddress.parse (bcc.getText()));

msg.setSubject (subject.getText());

msg.setText (besked.getText());

Transport.send (msg);

status.setText (“Besked afsendt.”);

}

catch (Exception ex)

{

status.setText (ex.toString());

ex.printStackTrace();

}

}

}

}

 


Definition af headeren

Indtil videre er kun en lille del af de oplysninger, headeren kan indeholde, blevet gennemgået. Nedenstående skema viser hvilke headers, der anvendes.

 

Header Beskrivelse Metode
From Afsenderadressen setFrom
Sender Den adresse, beskeden er sendt fra. Ingen
Subject Beskedens overskrift setSubject
To Beskedens modtager setRecipients
CC CC-modtagere setRecipients
BCC BCC-modtagere setRecipients
Comment Kommentarer om brevet. Ingen
Reply-To Den adresse, der skal sendes svar til. SetReplyTo
Resent-Reply-To Som Reply-To, men ved en besked der er sendt mere end en gang. Ingen
Resent-From Som From, men ved en besked der er sendt mere end en gang. Ingen
Resent-Sender Som Sender, men ved en besked der er sendt mere end en gang. Ingen
Date Det tidspunkt beskeden er afsendt på. setSentDate
Resent-To Som To, men ved en besked der er sendt mere end en gang. Ingen
Resent-CC Som CC, men ved en besked der er sendt mere end en gang. Ingen
Resent-BCC Som BCC, men ved en besked der er sendt mere end en gang. Ingen
Message-ID Beskedens ID. Ingen
Resent-Message-ID Som Message-ID, men ved en besked der er sendt mere end en gang. Ingen
In-Reply-To Den besked, denne besked er et svar på. Ingen
References En liste over henvisninger Ingen
Keywords Nøgleord i beskeden. Ingen
Encrypted Angiver om beskeden er krypteret. Ingen
Content-Descripton Beskrivelse af beskedens indhold. setDescription
Content-ID ID. setContentID
Content-Language Sproget af indholdet som defineret i RFC1766. setContentLanguage

 

 

 

Udover de headere, ovenstående tabel viser, findes der en række tilføjelser. Disse indledes alle med X. De enkelte postprogrammer kan selv definere disse tilføjelser, og man kan således ikke regne med, at modtagerens postprogram kan forstå dem. De mest udbredte er X-Mailer, der angiver navnet på det program, der har afsendt beskeden, og X-priority, der angiver beskedens prioritet.

 

Hvis man ønsker at besvare en besked, kan man bruge metoden reply til at oprette en besked, der har headers indstillet som en svarbesked.

Beskeder i flere dele

 

Hvis man vil sende en besked med vedhæng – for eksempel en vedlagt fil – skal man oprette en besked i flere dele – en mime multipart message. Dette gøres ved hjælp af klassen MimeMultipart. Denne klasser har følgende signatur:

 

public class MimeMultipart extends javax.mail.Multipart

{

public javax.mail.internet.MimeMultipart();

public javax.mail.internet.MimeMultipart(java.lang.String);

public javax.mail.internet.MimeMultipart(javax.activation.DataSource);

 

public synchronized void setSubType(java.lang.String);

public synchronized int getCount();

public synchronized void addBodyPart(javax.mail.BodyPart);

public synchronized void addBodyPart(javax.mail.BodyPart, int);

public synchronized javax.mail.BodyPart getBodyPart(int);

public synchronized javax.mail.BodyPart getBodyPart(java.lang.String);

public void writeTo(java.io.OutputStream);

}

 

Dernæst skal der oprettes et MimeBodyPart-objekt for hver del, beskeden skal bestå af. MimeBodyPart har følgende signatur:

 

public class MimeBodyPart extends javax.mail.BodyPart implements javax.mail.internet.MimePart

{

public javax.mail.internet.MimeBodyPart();

public javax.mail.internet.MimeBodyPart(java.io.InputStream);

public javax.mail.internet.MimeBodyPart(javax.mail.internet.InternetHeaders,byte[]);

 

public int getSize();

public int getLineCount();

 

public java.lang.String getContentType();

public boolean isMimeType(java.lang.String);

public java.lang.String getDescription();

public void setDescription(java.lang.String);

public void setDescription(java.lang.String, java.lang.String);

public java.lang.Object getContent();

public void setContent(java.lang.Object, java.lang.String);

public void setText(java.lang.String);

public void setText(java.lang.String, java.lang.String);

public void setContent(javax.mail.Multipart);

public java.lang.String[] getHeader(java.lang.String);

public java.lang.String getHeader(java.lang.String, java.lang.String);

public void setHeader(java.lang.String, java.lang.String);

public void addHeader(java.lang.String, java.lang.String);

public void removeHeader(java.lang.String);

public java.util.Enumeration getAllHeaders();

public void addHeaderLine(java.lang.String);

public java.util.Enumeration getAllHeaderLines();

static boolean isMimeType(javax.mail.internet.MimePart, java.lang.String);

static void setText(javax.mail.internet.MimePart, java.lang.String, java.lang.String);

static java.lang.String getDescription(javax.mail.internet.MimePart);

static void setDescription(javax.mail.internet.MimePart, java.lang.String, java.lang.String);

}

 

Man angiver indholdet af en del af beskeden ved at benytte metoden setContent. Denne har to parametre. Det er det objekt, som er selve indholdet, og en tekststreng, der angiver, hvilken mimetype indholdet er. De forskellige mimetyper vil blive gennemgået senere i dette kapitel.

 

Når de forskellige dele er blevet oprettet, skal de tilføjes til MimeMultipart-objektet. Det gør man ved hjælp af metoden addBodyPart. Endeligt skal MimeMultipart-objektet sættes som indholdet af en MimeMessage. Metoden setContent bruges til dette. Nedenstående eksempel viser, hvordan man kan sende tekst og et billede i samme besked.

 

import javax.mail.*;

import javax.mail.internet.*;

import java.io.*;

 

public class SendImage

{

public static final void main (String args[])

{

// Indstillinger

 

String to = “modtager@domæne.dk”;

 

String from = “afsender@domæne.dk”;

 

// Indlæs billedet

FileInputStream in = null;

try

{

in = new FileInputStream (“Image.gif”);

}

catch (FileNotFoundException fnfe)

{

System.out.println (“Filen ‘Image.gif’ kunne ikke findes.”);

System.exit(0);

}

 

byte buffer[] = null;

 

try

{

int size = in.available();

buffer = new byte[size];

in.read(buffer);

}

catch (IOException ioe)

{

System.out.println (“Fejl under læsning af fil.”);

System.exit(0);

}

 

// Opret multipart

 

MimeMultipart multipart = new MimeMultipart();

MimeBodyPart text = new MimeBodyPart();

MimeBodyPart billede = new MimeBodyPart();

 

// Sæt indholdet

 

try

{

text.setContent (“Her er billedet”, “text/plain”);

billede.setContent (buffer, “image/gif”);

}

catch (MessagingException me)

{

System.out.println (“Beskedernes indhold kunne ikke sættes.”);

System.exit(0);

}

 

 

// Tilføj til multipart

 

try

{

multipart.addBodyPart (text);

multipart.addBodyPart (billede);

}

catch (MessagingException me)

{

System.out.println (“Delene kunne ikke tilføjes til beskeden.”);

System.exit (0);

}

 

// Opret besked

 

Session session = Session.getDefaultInstance(System.getProperties(), null);

Message msg = new MimeMessage (session);

try

{

msg.setContent (multipart);

msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to, false));

msg.setFrom (new InternetAddress (from));

msg.setSubject (“Et billede”);

}

catch (MessagingException me)

{

System.out.println (“Den endelige besked kunne ikke oprettes.”);

System.exit(0);

}

 

// Afsend beskeden

 

try

{

Transport.send (msg);

}

catch (MessagingException me)

{

System.out.println (“Beskeden kunne ikke afsendes.”);

me.printStackTrace();

System.exit(0);

}

}

}

 


Mimetyper

 

Når man sender beskeder i flere dele, skal man som nævnt angive hvilken mimetype, de forskellige dele har. Mimetyperne er opdelt i forskellige niveauer. Det første niveau angiver den overordnede type – for eksempel image – mens det næste niveau angiver en mere specifik type – for eksempel gif. Nedenstående tabel viser en oversigt over de mimetyper, der er standardiserede. Mange programmer opretter egene mimetyper til deres data. Dette er muligt, da mimestandarden er udvidelig.

 

Mimetype Beskrivelse
Text Tekst af en eller anden art.
text/plain Almindelig tekst uden formatering.
text/richtext Formateret tekst som defineret i RFC 1341.
image Et billede af en eller anden art.
image/jpeg Et billede i jpeg-format.
image/gif Et billede i gif-format.
audio Lyd af en eller anden form.
audio/basic Lyd kodet med 8bit ISDN mu-law [PCM] med en sample rate på 8000 Hz.
video Film af en eller anden art.
video/mpeg Film i mpeg-format
application Data i ufortolket binær form eller information, der skal fortolkes af en applikation.
application/octet-stream Ufortolket data. Det eneste et program, der modtager denne type, kan gøre, er at tilbyde brugeren at gemme dataene.
application/Postscript Data i postscript-format.
message En besked
message/rfc822 En besked formateret i henhold til RFC 822.
message/partial En del af en besked.
message/external-body En besked, hvor selve besked ligger i en ekstern fil.

 

Der findes mange flere mimetyper end de, der er angivet herover. Disse er blot de typer, der er defineret i beskrivelsen af mime (RFC 2046).

Modtagelse af besked

 

At kunne sende beskeder er imidlertid kun halvdelen af et postprogram. Man skal også gerne kunne modtage de beskeder, andre sender til en. Her findes der to forskellige protokoller. Det er POP3 – Post Office Protocol – og IMAP – Internet Message Access Protocol. I øjeblikket understøtter JavaMail kun

 

IMAP, men det forventes at fremtidige versioner også vil indeholde understøttelse for POP3.

 

Ligesom når man afsender post, bruger man Session-klassen, når man henter post. Den oprettes på den vanlige måde ved hjælp af getDefaultInstance-metoden. Dernæst skal man have en reference til et Store-objekt. Store-klassen repræsenterer en database, der kan indeholde et hierarki af foldere og beskeder. Det er også denne klasse, der definerer protokoller og henter beskeder fra folderne. Klassen har nedenstående signatur:

 

public abstract class Store extends java.lang.Object

{

public void connect();

public void connect(java.lang.String, java.lang.String, java.lang.String);

public void connect(java.lang.String, int, java.lang.String, java.lang.String);

public boolean isConnected();

public synchronized void close();

public javax.mail.URLName getURLName();

public abstract javax.mail.Folder getDefaultFolder();

public abstract javax.mail.Folder getFolder(java.lang.String);

public abstract javax.mail.Folder getFolder(javax.mail.URLName);

public synchronized void addConnectionListener(javax.mail.event.ConnectionListener);

public synchronized void removeConnectionListener(javax.mail.event.ConnectionListener);

public synchronized void addStoreListener(javax.mail.event.StoreListener);

public synchronized void removeStoreListener(javax.mail.event.StoreListener);

public synchronized void addFolderListener(javax.mail.event.FolderListener);

public synchronized void removeFolderListener(javax.mail.event.FolderListener);

public java.lang.String toString();

}

 

Man får en instans af Store-klassen ved at kalde getStore-metoden på Session-objektet. Den eneste parameter til metoden er en tekststreng, der angiver protokollen.

 

For at tilslutte mailserveren bruger man metoden connect. Her kan man angive adressen på mailserveren, brugernavn og kodeord. Hvis brugernavnet er ukendt, eller hvis kodeordet er forkert, opstår en AuthenticationFailedException, mens alle andre fejl vil medføre en MessagingException.

 

Som det ses, kan man tilføje tre slags listeners til Store-objektet. Det drejer sig om ConnectionListener, StoreListener og FolderListener.

 

Store-klassen genererer følgende events:

 

 

 

Event Beskrivelse
ConnectionEvent Opstår, når programmeter slutter til mailserveren, eller når en eksisterende forbindelse afbrydes eller afsluttes.
StoreEvent Bruges til at sende advarsler og andre beskeder fra mailserveren til brugeren. Metoden getMessageType kan bruges til at få at vide, hvilken type besked, der er tale om. Det kan enten være ALERT eller NOTICE. Hvis typen er ALERT, skal programmet vise beskeden på en måde, der tiltrækker brugerens opmærksomhed.
FolderEvent Opstår når der sker en ændring i en af folderne. Det kan være oprettelse af en ny folder, sletning af en folder eller omdøbning af en folder.

 

Foldere

 

På baggrund af Store-objektet kan man få en reference til et Folder-objekt. Det sker ved hjælp af metoden getFolder eller getDefaultFolder. Folder-objektet repræsenterer en folder på mailserveren. Klassen har følgende signatur:

 

public abstract class Folder extends java.lang.Object

{

public abstract java.lang.String getName();

public abstract java.lang.String getFullName();

public javax.mail.Store getStore();

public abstract javax.mail.Folder getParent();

public abstract boolean exists();

public abstract int getType();

public abstract boolean hasNewMessages();

public abstract javax.mail.Folder getFolder(java.lang.String);

public abstract void open(int);

public abstract void close(boolean);

public abstract int getMessageCount();

public synchronized int getNewMessageCount();

public synchronized int getUnreadMessageCount();

public abstract javax.mail.Message getMessage(int);

public synchronized javax.mail.Message[] getMessages(int, int);

public synchronized javax.mail.Message[] getMessages(int[]);

public synchronized javax.mail.Message[] getMessages();

public javax.mail.Folder[] list();

public javax.mail.Message[] search(javax.mail.search.SearchTerm);

public javax.mail.Message[] search(javax.mail.search.SearchTerm, javax.mail.Message[]);

 

public synchronized void addConnectionListener(javax.mail.event.ConnectionListener);

public synchronized void removeConnectionListener(javax.mail.event.ConnectionListener);

public synchronized void addFolderListener(javax.mail.event.FolderListener);

public synchronized void removeFolderListener(javax.mail.event.FolderListener);

public synchronized void addMessageCountListener(javax.mail.event.MessageCountListener);

public synchronized void removeMessageCountListener(javax.mail.event.MessageCountListener);

public synchronized void addMessageChangedListener(javax.mail.event.MessageChangedListener);

public synchronized void removeMessageChangedListener(javax.mail.event.MessageChangedListener);

}

 

Foldere kan indeholde underfoldere og beskeder. Metoden getType angiver, om en folder kan indeholde andre foldere, beskeder eller begge dele. Metoden returnerer en int, indeholdende en eller begge af følgende værdier:

 

  • HOLDS_FOLDERS hvis folderen kan indeholde andre foldere.
  • HOLDS_MESSAGES hvis folderen kan indeholde beskeder.

 

Metoden getDefaultFolder returnerer roden af folderhierakiet. Man kan bruge metoden list til at få en liste over alle foldere i den aktuelle folder. Denne metode returnerer et array af Folder-objekter. Hvis man vil have navnene på disse foldere, skal man efterfølgende kalde getName på samtlige foldere. Metoderne getMessageCount, getNewMessageCount og getUnreadMessageCount returnerer henholdsvis antallet af beskeder, nye beskeder og ulæste beskeder i den pågældende folder.

 

Nedenstående klasse viser, hvordan man kan liste alle foldere i roden af hierakiet og vise, hvor mange beskeder hver af dem indeholder.

 

import javax.mail.*;

import javax.mail.internet.*;

import java.util.*;

 

public class MailInfo

{

public static final void main (String args[]) throws Exception

{

Properties indstillinger = System.getProperties();

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

 

 

Store store = session.getStore(“imap”);

store.connect(“host.mit-domain.dk”, “bruger”, “kodeord”);

 

Folder folder = store.getDefaultFolder();

if (folder == null)

{

System.out.println (“No Default Folder”);

}

 

Folder liste[] = folder.list();

 

System.out.println (“Oversigt over foldere:”);

System.out.println (“======================”);

 

for (int i = 0; i < liste.length; i++)

{

System.out.println (liste[i].getName());

System.out.println (“-> Nye beskeder:    ” + liste[i].getNewMessageCount());

System.out.println (“-> Ulæste beskeder: ” + liste[i].getUnreadMessageCount());

System.out.println (“-> Beskeder i alt:  ” + liste[i].getMessageCount());

}

System.out.println (“======================”);

}

}

 

Folder-klassen kan også generere events. Nedenstående skema viser de mulige events, og hvornår de optræder.

 

Event Beskrivelse
ConnectionEvent Opstår, når en folder åbnes eller lukkes.
FolderEvent Opstår, når folderen oprettes, slettes eller omdøbes.
MessageCountEvent Opstår,  når antallet af beskeder ændres.

 

Beskeder

 

Beskeder i en folder er nummereret fortløbende. Typisk afspejler beskedernes numre den rækkefølge, de er ankommet i. Den første – ældste – besked vil således have nummer 1. Hvis beskeder bliver slettet, skal man være opmærksom på, at beskednumrene kan blive ændret.

 

Hvis man vil hente en eller flere beskeder, kan man gøre det på baggrund af beskedens nummer. Vil man kun hente en enkelt besked, skal man bruge metoden getMessage, der tager beskedens nummer som parameter. Hvis man vil hente flere beskeder, kan man bruge metoden getMessages. Denne returnerer et array af Message-objekter. Parametre til denne metode er den første og den sidste besked identificeret ved beskedens nummer.

 

 

Ved afsendelse af beskeder, repræsenteredes beskederne af MimeMessage-klassen. Dette er ikke tilfældet, når der hentes beskeder. Her behandles alle beskeder abstrakt gennem klassen Message, og det er ikke sikkert, at man kan caste et Message-objekt til et MimeMessage-objekt. Det betyder, at man kun kan bruge de metoder, Message-klassen stiller til rådighed. Nedenstående signatur viser de metoder, der findes i Message-klassen.

 

public abstract class Message extends java.lang.Object implements javax.mail.Part

{

public abstract javax.mail.Address getFrom();

public abstract javax.mail.Address[] getRecipients(javax.mail.Message.RecipientType);

public javax.mail.Address[] getAllRecipients();

public javax.mail.Address[] getReplyTo();

public abstract java.lang.String getSubject();

public abstract java.util.Date getSentDate();

public abstract java.util.Date getReceivedDate();

public abstract javax.mail.Flags getFlags();

public int getMessageNumber();

public javax.mail.Folder getFolder();

public abstract javax.mail.Message reply(boolean);

public abstract int getSize();

public abstract int getLineCount();

public abstract java.lang.String getContentType();

public abstract boolean isMimeType(java.lang.String);

public abstract java.lang.String getDisposition();

public abstract java.lang.String getDescription();

public abstract java.lang.String getFileName();

public abstract java.lang.Object getContent();

public abstract java.lang.String[] getHeader(java.lang.String);

public abstract java.util.Enumeration getAllHeaders();

}

 

I ovenstående specifikation er kun de metoder, der bruges til at hente information om beskeden inkluderet. Klassen indeholder selvfølgeligt tilsvarende set-metoder.

 

De fleste af klassens metoder har navne, der forklarer metodernes semantik. Klassen GetMessage viser, hvordan man kan hente informationer om en besked. Klassens kildetekst ses herunder.

 

import javax.mail.*;

import javax.mail.internet.*;

import java.text.*;

import java.util.*;

 

public class GetMessage

{

public static final void main(String args[])

{

if (args.length != 4)

 

{

System.out.println (“Forkert syntaks.”);

System.out.println (“java GetMessage <server> <brugernavn> <kodeord> <beskednummer>”);

System.exit(0);

}

 

String server = args[0];

String bruger = args[1];

String kodeord = args[2];

 

int besked = 1;

 

try

{

besked = Integer.parseInt(args[3]);

}

catch (NumberFormatException spe)

{

System.out.println (“Ugyldigt beskednummer.”);

System.exit(0);

}

 

Properties indstillinger = System.getProperties();

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

 

Store store = null;

 

try

{

store = session.getStore(“imap”);

}

catch (NoSuchProviderException nspe)

{

System.out.println (“IMAP ikke understøttet.”);

System.exit(0);

}

 

try

{

store.connect(server, bruger, kodeord);

}

catch (MessagingException me)

{

System.out.println (“Det var ikke muligt at slutte til mailserveren.”);

System.exit(0);

}

 

 

Folder folder = null;

 

try

{

folder = store.getFolder(“INBOX”);

}

catch (MessagingException me)

{

System.out.println (“Folderen kunne ikke findes.”);

System.exit(0);

}

 

try

{

folder.open(Folder.READ_ONLY);

}

catch (MessagingException me)

{

System.out.println (“Folderen kunne ikke åbnes.”);

}

 

Message msg = null;

 

try

{

msg = folder.getMessage (besked);

}

catch (MessagingException me)

{

System.out.println (“Beskeden kunne ikke findes.”);

System.exit(0);

}

catch (IndexOutOfBoundsException ioobe)

{

System.out.println (“Ugyldigt beskednummer.”);

System.exit(0);

}

 

System.out.println (“Informationer om besked nummer ” + besked);

System.out.println ();

try

{

System.out.println (“Titel:    ” + msg.getSubject());

System.out.println (“Afsender: ” + msg.getFrom());

 

Address modtagere[] = msg.getAllRecipients();

for (int i = 0; i < modtagere.length; i++)

{

System.out.println (“Andre modtagere: ” + ((InternetAddress) modtagere[i]).getAddress());

}

 

 

System.out.println (“Afsendelsestidspunkt: ” + (new SimpleDateFormat()).format(msg.getSentDate()));

System.out.println (“Modtagelsestidspunkt: ” + (new SimpleDateFormat()).format(msg.getReceivedDate()));

}

catch (MessagingException me)

{

System.out.println (“Ugyldig besked.”);

System.exit(0);

}

}

}

 

Fremtiden

 

JavaMail er et forholdsvis ungt API, og der er allerede planlagt ændringer i forhold til den version, der er blevet gennemgået her.

 

Eksempelvis vil der blive oprettet en metode til at konvertere Java chars til tegn i mime-tegnsættet. Metoden kommer sandsynligvis til at ligge i klassen javax.mail.internet.MimeUtility og have følgende signatur:

 

public static String mimeCharset (String);

 

Derudover vil der blive tilføjet nogle metoder i Folder-klassen. Den første er getMode, der returnerer, hvorvidt folderen er åbnet med skriverettigheder. Metoden getMode får sandsynligvis følgende signatur:

 

public int getMode ()

 

Der bliver også oprettet en metode ved navn getURLName. Denne returnerer en URL, der angiver den aktuelle folder.  Signaturen for den nye metode bliver nok

 

public URLName getURLName () throws MessagingException

 

Endeligt vil der sandsynligvis blive oprettet en fælles superklasse for klasserne Store og Transport. Dette medfører ikke ændringer i nogen af de to klasser, men gøres kun for at gøre det lettere at vedligeholde klasserne.

 

Sammenfatning

I dette kapitel er API’et JavaMail blevet gennemgået. Det er blevet vist, hvordan man ved hjælp af JavaMail kan sende og modtage post. Det er også blevet beskrevet, hvordan man anvender de mere avancerede muligheder som for eksempel angivelse af mimetyper og definition af headere.

 

Da JavaMail er en forholdsvis nyudviklet teknologi, er det også blevet beskrevet, hvordan man kan forvente, at JavaMail vil være opbygget i fremtiden.

 

 

FAQ

 

Er det gratis at distribuere programmer, der er baseret på JavaMail?

 

I øjeblikket er det. Med JavaMail-pakken følger filen License. Denne fil beskriver de nøjagtige retningslinier for distribution af JavaMail.

 

Hvorfor kan mit JavaMail-program ikke udføres? Jeg får at vide, at den ikke kan finde en klasse startende med javax.activation.

 

JavaMail før brug af Java Activation Framework (JAF). Derfor skal JAF være installeret, før JavaMail-programmerne vil virke. JAF kan downloades gratis fra Javasofts hjemmeside.

 

Kan JavaMail bruges fra JDK 1.0?

 

Nej. Man skal have JDK 1.1 eller nyere for at kunne bruge JavaMail.

 

Du læser en gammel bog
Den bog, du læser her, er fra 1998, og mange ting kan have ændret sig siden da.
Vi håber, at du stadig kan finde relevant information i den.
Hvis du vil læse aktuelle oplysninger om de avancerede dele af Java, anbefaler vi
bogen Core Java – Advanced Features

Comments are closed.