16.11 E-Mail
 
E-Mail ist heute ein wichtiger Teil der modernen Kommunikation. Die Vorteile bei der Technik sind vielfältig: Das Medium ist schnell, die Nachrichtenübertragung erfolgt asynchron, und die Informationen können direkt weiterverarbeitet werden: ein Vorteil, der bei herkömmlichen Briefen nicht gegeben ist.
16.11.1 Wie eine E-Mail um die Welt geht
 
In einem E-Mail-System kommen mehrere Komponenten vor, die kurz benannt werden sollen:
|
User. Der Benutzer des Mail-Systems, der Nachrichten verschickt oder empfängt. |
|
Mail User Agent (MUA). Die Schnittstelle zwischen dem Benutzer und dem Mail-System. |
|
Message Store (MS). Dient dem Mail User Agent zum Ablegen der Nachrichten. |
|
Message Transfer Agent (MTA). Diese Komponenten des Message Transfer Systems sind verantwortlich für die eigentliche Nachrichtenübermittlung. |
|
Message Transfer System (MTS). Ist die Gesamtheit der Message Transfer Agents und ihrer Verbindungen. |
Die Nachrichtenübermittlung läuft also über diese Komponenten, wobei der Benutzer über sein Mail User Agent (MUA) die Nachricht erstellt. Anschließend wird diese Nachricht vom MUA an den Message Transfer Agent übergeben. Nun ist es Aufgabe dieser Agenten, die Botschaft entweder direkt (der Empfänger ist im gleichen Netzwerk wie der Sender) oder über Store-and-Forward zu übermitteln. Danach ist der Sender aus dem Spiel, und der Empfänger nimmt die E-Mail entgegen. Sie wird vom Ziel-MTA an den Mail-User-Agenten des Abrufenden geholt.
16.11.2 Das Simple Mail Transfer Protocol und RFC 822
 
Für die Übertragung von E-Mail hat sich auf breiter Basis das Simple Mail Transfer Protocol (kurz SMTP) etabliert. X.400 war durch die Standardisierung zwar auf einem guten Weg, aber dann stecken geblieben. SMTP ist ein Versende-Protokoll, welches im RFC 2821 beschrieben ist. Zusammen mit dem RFC 822 (Standard for the Format of ARPA Internet Text Messages), welches den Austausch Text-basierter Nachrichten im Internet beschreibt, bildet es das Gerüst des Mail-Systems. Über RFC 822 wird nur der Aufbau der Nachrichten beschrieben – es ist kein Protokoll – und im RFC 2821 das Protokoll zum Verschicken und Übertragen der Nachrichten von einem Rechner zum anderen beschrieben. Beide Systeme sind schon recht alt, das Simple Mail Transfer Protocol stammt ebenso wie der Standard für die ARPA-Internet-Text-Nachrichten aus dem Jahre 1982. Was früher noch durchging, wird heute immer mehr zum Hindernis, da die (böse) kommerzielle Welt ganz andere Weichen stellt.
SMTP verwendet den Standard RFC 822 zur Schreibweise der E-Mail-Adressen. Diese Adressierung benutzt den Rechnernamen (beziehungsweise Netznamen) des Adressaten. Mit dem eingänglichen Fully Qualified Host Name (kurz FQHN) lassen sich die E–Mails leicht verteilen. Denn jeder Rechner ist im DNS aufgeführt, und wenn der Name bekannt ist, lässt es sich leicht zum Empfänger routen. So macht es zum Beispiel das Programm sendmail. Es baut eine direkte Verbindung zum Zielrechner auf und legt die Nachricht dort ab. Da allerdings gerne eine Unabhängigkeit von real existierenden Rechnern erreicht werden soll, werden in der Regel MX-Records (Mail Exchanger Resource Records) gesetzt. Dann tritt ein anderer Rechner als Mail Transfer Agent auf, und so ist Erreichbarkeit für jene Rechner gewährleistet, die nicht am Internet angeschlossen sind. Außerdem können mehrere Rechner als MTAs definiert werden, um die Ausfallsicherheit zu erhöhen. Zudem haben MX-Records den Vorteil, dass auch (einfachere) E-Mail-Adressen formuliert werden können, für die es keinen Rechner gibt.
Multipurpose Internet Mail Extensions (MIME)
In den Anfängen des Internets bestand eine E-Mail meistens aus lesbaren englischen Textnachrichten. Wenn denn einmal binäre Dateien verschickt werden sollten, musste sie der Benutzer unter Unix mit einem uuencode in 7-Bit-ASCII umwandeln, um sie anschließend zu verschicken. Der Standard des RFC 822 kann viele der heute anzutreffenden Daten nicht kodieren:
|
Binärdaten (zum Beispiel Audiodaten, Bilder, Video, Datenbanken) |
|
Nachrichten in Sprachen mit Umlauten und Akzenten (Deutsch, Französisch) |
|
Nachrichten in nicht lateinischen Sprachen (Hebräisch, Russisch) oder sogar Sprachen ohne klassisches Alphabet (Chinesisch, Japanisch) |
Um Abhilfe zu schaffen, wurde MIME im RFC 1341 und RFC 1521 vorgeschlagen. Um ASCII-fremde Nachrichten zu kodieren, werden fünf Nachrichten-Header definiert und die Binärdateien nach base64-Encoding umgesetzt. Für Nachrichten, die fast nur aus ASCII-Zeichen bestehen, wäre dies aber zu großer Overhead, sodass Quoted Printing Encoding eingesetzt wird. Dies definiert lediglich alle Zeichen über 127 durch zwei hexadezimale Zeichen. Dieses Kodierungsverfahren entdecken wir oft in URLs, die von Formularen erzeugt werden, etwa http://www.google.de/search?q=r%FCssel.
Probleme mit SMTP
SMTP bereitet den Anwendern und Systemverwaltern einiges Kopfzerbrechen. So müssen sie sich mit dem Versand von gefälschten E-Mails herumschlagen (Mail-Spoofing), zudem ist unerbetene kommerzielle Werbung (Unsolicited Commercial E-Mail, kurz UCE) und UBE (Unsolicited Bulk E-Mail), besser bekannt als Spam, ein wirtschaftlich negativer Faktor. Das Ursprungs-SMTP wird mit diesen Problemen nicht fertig, da der Einsatz für ein überschaubares Netz gedacht war, dessen Teilnehmer sich kennen. Viele SMTP-Server sind so brav, dass sie eine E-Mail von jedem beliebigen Absender zu jedem beliebigen Adressaten schicken. Auch andere Probleme sind noch ungelöst. Dazu gehören zum Beispiel eine Einlieferungsbestätigung (Proof of Submission). Zwar lässt sendmail das Senden von Empfangsbestätigungen mit einem speziellen Return-Receipt-To-Feld zu, doch dieses ist bisher nicht offiziell im RFC 822 standardisiert.
16.11.3 POP (Post Office Protocol)
 
Die Idee eines E-Mail-Programms ist einfach: Zunächst muss eine Verbindung zum richtigen E-Mail-Server stehen, und anschließend lässt sich die Kommunikation mit einigen Kommandos regeln. Mit dieser Technik ist es dann möglich, eine Mail zu empfangen und zu senden. Nun besteht das E-Mail-System aber aus zwei Teilen: zum einen aus dem Empfänger und zum anderen aus dem Sender. Die empfangende Seite setzt auf das POP3-Protokoll, die sendende auf SMTP oder IMAP. POP3 ist die dritte Version des Post Office Protocol. Der POP3-Server sitzt auf der Empfängerseite und stellt die Infrastruktur bereit, damit die E-Mail eingesehen werden kann.1
Beide Systeme arbeiten also Hand in Hand. Wird mittels SMTP-Server eine E-Mail versendet, so kann sie durch den POP3-Server abgerufen werden.
16.11.4 E-Mails versenden mit der JavaMail API von SUN
 
Nachdem wir alles mehr theoretisch betrachtet haben, soll nun ein kleines Programm folgen, mit dem sich eine E-Mail abschicken lässt. Das Programm ist bewusst klein. Es nutzt die JavaMail API, eine eigene Bibliothek, die zum Versenden und Empfangen von E-Mail entworfen wurde. Sie lässt sich von http://java.sun.com/products/javamail/ beziehen. Zudem muss das Archiv activation.jar für das JavaBeans Activation Framework2
mit im Klassenpfad aufgenommen werden. Bei Enterprise-Applikationen sind die Archive Bestandteil einer J2EE-Installation.
Um eine E-Mail mit JavaMail zu verwenden, sind nicht viele Klassen zu verstehen: Session steht für eine Verbindung mit dem Mail-Server, Message (bzw. MimeMessage) für die zu versendende Nachricht, und Address repräsentiert einen Sender und die Empfänger. Die Klasse Transport ist für den Versand zuständig.
Listing 16.16
com/javatutor/insel/mail/SendJavaMail.java
package com.javatutor.insel.mail;
import java.util.*;
import javax.mail.*;
import javax.mail.internet.*;
public class SendJavaMail
{
public static void postMail( String recipient,
String subject,
String message, String from )
throws MessagingException
{
Properties props = new Properties();
props.put( "mail.smtp.host", "mail.java-tutor.com" );
Session session = Session.getDefaultInstance( props );
Message msg = new MimeMessage( session );
InternetAddress addressFrom = new InternetAddress( from );
msg.setFrom( addressFrom );
InternetAddress addressTo = new InternetAddress( recipient );
msg.setRecipient( Message.RecipientType.TO, addressTo );
msg.setSubject( subject );
msg.setContent( message, "text/plain" );
Transport.send( msg );
}
public static void main( String[] args ) throws Exception
{
postMail( "Buchtest@java-tutor.com",
"Tolles Buch",
"Wow. Das Buch ist schön zu lesen",
"JavaTutor@java-tutor.com");
}
}
An dem Beispiel ist abzulesen, dass der Empfänger (Buchtest@java-tutor.com) eine Nachricht von JavaTutor@java-tutor.com bekommt. Das Subjekt ist »Tolles Buch«, und der dritte Parameter gibt den Inhalt der E-Mail an.
Hinweis Falls das Senden nicht funktioniert, kann dies daran liegen, dass der Server mit einer »POP before send« Authentifizierung arbeitet. Das heißt: Der Anwender muss erst mit POP die E-Mail erfragen und kann dann eine neue E-Mail senden.
|
16.11.5 MimeMultipart-Nachrichten schicken
 
Neben den klassischen MIME-Typen application, audio, image, message und video zur Beschreibung der Datentypen einer E-Mail dient der Typ multipart dazu, in einer E-Mail mehrere Teile mit (in der Regel) unterschiedlichen MIME-Teilen zu kodieren. Die JavaMail-API bietet für diesen Fall die Klasse (Mime)Multipart an; eine Containerklasse, der mit addBodyPart() diverse (Mime)BodyPart-Objekte hinzugefügt werden können. Zum Schluss – sind die Köper aufgebaut – setzt auf dem Message-Objekt setContent() nun nicht mehr das einfache MimeMessage-Objekt mit einem expliziten MIME-Typ, sondern das MimeMultipart-Objekt.
Das nachfolgende Beispiel zeigt ein Message-Objekt mit zwei Teilen. Einmal eine normale text/plain-Nachricht und zum anderen eine text/html-Nachricht. Der Konstruktor eines MimeMultipart-Objekts gibt der mehrtyp-Nachricht einen Namen. Ist er mit dem String »alternative«, so bedeutet dies für den Mail-Client, dass es verschiedene Versionen desselben Textes enthält. Standardmäßig versendet so zum Beispiel Microsoft Outlook die E-Mails. Sie werden als reiner Text und als HTML verschickt.
MimeMultipart content = new MimeMultipart( "alternative" );
MimeBodyPart text = new MimeBodyPart();
MimeBodyPart html = new MimeBodyPart();
text.setText( "Text als normaler String" );
text.setHeader( "MIME-Version" , "1.0" );
text.setHeader( "Content-Type" , text.getContentType() );
html.setContent( "<html>Text als <b>HTML</b></html>", "text/html");
html.setHeader( "MIME-Version" , "1.0" );
html.setHeader( "Content-Type" , html.getContentType() );
content.addBodyPart( text );
content.addBodyPart( html );
Message msg = ...
msg.setContent( content );
msg.setHeader( "MIME-Version" , "1.0" );
msg.setHeader( "Content-Type" , content.getContentType() );
msg.setHeader( "X-Mailer", "Java-Mailer V 1.60217733" );
msg.setSentDate( new Date() );
Anhänge
Anhänge kodiert die JavaMail API über DataSource-Objekte; FileDataSource steht etwa für einen Datei-Anhang.
DataSource fileDataSource = new FileDataSource( dateiname );
Soll dieser Anhang an die Nachricht (MimeBodyPart) angehängt werden, ist setData-Handler() zu verwenden:
BodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setDataHandler( new DataHandler(fileDataSource) );
messageBodyPart.setFileName( dateiname ); // gibt dem Anhang einen Namen
multipart.addBodyPart( messageBodyPart );
Es ist sinnvoll, mit setFileName() einen Namen für den Anhang zu vergeben, damit der Empfänger der E-Mail diesen Anhang einfach unter diesem Namen speichern kann.
16.11.6 E-Mails mittels POP3 abrufen
 
Die andere Seite soll ebenso betrachtet werden. Sie ist ein klein wenig aufwändiger, da die Nachrichten (Message-Objekte) erst dekodiert werden müssen. Dennoch geht die Arbeitsweise leicht aus dem Programm hervor.
Listing 16.17
com/javatutor/insel/mail/GetEMails.java
package com.javatutor.insel.mail;
import java.util.*;
import java.io.*;
import javax.mail.*;
import javax.mail.internet.*;
public class GetEMails
{
public static void getMail( String host, String user, String passwd )
throws Exception
{
Session session = Session.getDefaultInstance( new Properties() );
Store store = session.getStore( "pop3" );
store.connect( host, user, passwd );
Folder folder = store.getFolder( "INBOX" );
folder.open( Folder.READ_ONLY );
Message[] message = folder.getMessages();
for ( int i = 0; i < message.length; i++ )
{
Message m = message[i];
System.out.println( "Nachricht: " + i );
System.out.println( "From: " + m.getFrom()[0] );
System.out.println( "Subject: " + m.getSubject() );
Multipart mp = (Multipart) m.getContent();
for ( int j = 0; j < mp.getCount(); j++ )
{
Part part = mp.getBodyPart( j );
String disposition = part.getDisposition();
if ( disposition == null )
{
MimeBodyPart mimePart = (MimeBodyPart)part;
if ( mimePart.isMimeType("text/plain") )
{
BufferedReader in = new BufferedReader(
new InputStreamReader(mimePart.getInputStream()) );
for ( String line; (line=in.readLine()) != null; )
System.out.println( line );
}
}
}
}
folder.close( false );
store.close();
}
public static void main( String[] args ) throws Exception
{
getMail( "pop.t-online.de",
"12345678–0001@t-online.de", "passwd" );
}
}
Das Programm listet alle E-Mails vom Server auf und schreibt die Inhalte auf den Bildschirm. Die Nachrichten werden aber nicht vom Server gelöscht. In dem oberen Beispiel ist das Passwort natürlich anzupassen. Um eine Nachricht vom Server zu löschen, darf der Ordner nicht mit READ_ONLY geöffnet werden, sondern mit Folder.READ_WRITE. Anschließend lässt sich einer Nachricht, repräsentiert durch ein Message-Objetkt, mit setFlag() ein Lösch-Hinweis geben.
message.setFlag( Flags.Flag.DELETED, true );
Die Daten werden jedoch nur dann vom Server gelöscht, wenn zum Schluss folder.close(true) aufgerufen wird. Ohne den Aufruf von close() mit dem Argument true bleiben die Nachrichten erhalten.
Beispiel Um herauszufinden, ob überhaupt Nachrichten auf dem Server vorliegen, können wir auf dem aktuellen folder-Objekt die Methode getMessageCount() nutzen.
|
16.11.7 Ereignisse und Suchen
 
Die JavaMail-API bietet einige Glanzstücke, unter ihnen ein System für verschiedene Ereignisse:
Listener
|
Angewendet auf
|
Aufgaben
|
MessageCountListener
|
Folder
|
Findet neu eingetroffene Nachrichten. (Bei POP3 muss das Postfach geschlossen sein.)
|
ConnectionListener
|
Service (Store, Transport), Folder
|
Benachrichtigung beim Öffnen, Schließen, Zwangstrennung
|
FolderListener
|
Folder
|
Ordner angelegt, umbenannt, gelöscht
|
MessageChangedListener
|
Folder
|
Änderung, etwa am Folder oder Headern
|
StoreListener
|
Store
|
Nachricht mit Wichtigkeit ALERT oder NOTICE
|
TransportListener
|
Transport
|
zugestellt, nicht zugestellt, zum Teil zugestellt
|
Das Zweite ist ein Suchsystem, das JavaMail über das Paket javax.mail.search definiert. Zunächst wird ein Suchterm aus SearchTerm-Objekten aufgebaut. Diese abstrakte Basisklasse definiert eine Methode match(), die von Unterklassen passend implementiert wird:
|
AddressTerm und Unterklassen FromTerm, RecipientTerm vergleichen javax.mail. Address-Objekte. Address besitzt Unterklassen InternetAddress und NewsAddress |
|
StringTerm. Sucht nach Teilzeichenketten. Interessant sind die Unterklassen AddressStringTerm (mit Unterklassen FromStringTerm, RecipientStringTerm), BodyTerm, HeaderTerm, MessageIDTerm, SubjectTerm |
|
FlagTerm. Testet, ob Nachrichten gewisse Flags besitzen. |
|
ComparisonTerm. Vergleiche über die Unterklassen DateTerm, IntegerComparisonTerm. Ein Datum ist durch die Unterklassen ReceivedDateTerm und SentDateTerm weiter gegliedert, ein IntegerComparisonTerm besitzt die Unterklassen MessageNumberTerm und SizeTerm. |
|
AndTerm, NotTerm, OrTerm. Verknüpfungen zwischen Termen |
Die nächsten Anweisungen bauen ein Such-Objekt auf, das im Betreff ein »Re:« erkennt und auf die Zeichenkette »Nigeria-Connection« im Körper reagiert. search() durchsucht einen Folder und liefert die Nachrichten, die auf dieses Muster passen.
SearchTerm st = new AndTerm( new SubjectTerm( "Re:" ),
new BodyTerm("Nigeria-Connection") );
Message[] msgs = folder.search( st );
1 Der E-Mail-Client von Microsoft zieht Probleme mit sich, denen die meisten von uns lieber aus dem Weg gehen würden. Als in der Fernsehwerbung zwischen 1996 und 1997 der Internet Explorer beworben wurde, spielte im Hintergrund die Musik von Wolfgang Amadeus Mozart (1756–1791). In Mozarts Requiem, welches geschichtlich gesehen schon mit Verwunderungen verbunden war, taucht am Ende der Werbung der Choral »Confutatis maledictis, flammis acribus addictis« auf. Zeitgleich folgt der Microsoft-Slogan »Where do you want to go today?«. Für die Nicht-Lateiner wird es erst bei der Übersetzung lustig: »Die Verdammten und Angeklagten, die in den Flammen der Hölle verurteilt sind«.
2 Zu beziehen unter http://java.sun.com/products/javabeans/glasgow/jaf.html.
|