Email is one of the most important functions provided by the Internet. Many of us send and receive email on a daily basis. The JavaMail API provides the capability to develop email clients and mail-enabled Java applications. In this chapter, you'll learn how mail systems work and how the JavaMail API is used to create email clients. You'll finish the chapter by developing a simple Internet mail client.
Email systems consist of two major components: a mail client or user agent (UA), and a mail server or message transfer agent (MTA). User agents let users compose and send email and retrieve email from message transfer agents. Message transfer agents store and forward email for user agents and support the exchange of mail across a network or group of networks (see Figure 34.1).
FIGURE 34.1. How email systems work.
Examples of user agents are email programs, such as Eudora and Outlook. These programs also provide limited message transfer capabilities. Examples of message transfer agents are email server programs, such as Sendmail and Exchange. On the Internet, the Post Office Protocol 3 (POP3) is the most popular protocol for user agents to receive mail from message transfer agents. The Simple Message Transfer Protocol (SMTP) is the most popular protocol for user agents to send mail to message transfer agents, and for message transfer agents to exchange mail with each other. The POP3 protocol is described in Request for Comments (RFC) 1225, and the SMTP protocol is covered in RFC 821. Figure 34.2 shows how POP3 and SMTP are used on the Internet.
The Internet Message Access Protocol (IMAP4) protocol allows user agents to directly access mail folders that are stored on a mail server. IMAP4 leaves mail on the mail server, and POP3 downloads it to the user's computer. IMAP4 lets the user access his mail no matter what computer he is using. IMAP4 is described in RFC 2060.
FIGURE 34.2. How POP3 and SMTP are used on the Internet.
The JavaMail API supports the development of user agents. It can be used to create email client programs in Java, to mail-enable other programs (such as editors and browsers), or to implement special email features in embedded products, such as Web phones. The JavaMail API is not designed to support the development of mail servers, although it does provide the capability to interface with message transfer agents.
The JavaMail API consists of the following four packages:
These packages are contained in the mail.jar file that is distributed with the JavaMail API. The mail.jar file also contains several other packages that, although they are not part of the JavaMail API, support the development of mail clients. These undocumented packages are as follows:
Because these packages are not officially part of the JavaMail API, they may not be available in future versions.
Figure 34.3 shows how the JavaMail API supports the development of user agent software. The email client provides an application layer consisting of the application's GUI and application-specific logic. The application logic consists of mail functions, such as composition, addressing, and mail management. These functions use the classes and interfaces of the JavaMail API to implement general mail-processing capabilities. The JavaMail API classes and interfaces provide basic mail system objects, such as messages, addresses, headers, folders, and so on. The JavaMail API does not presume or provide the underlying messaging protocols, such as POP3, SMTP, or IMAP4. Instead, it provides a general framework for working with messaging systems. The undocumented Sun packages provide support for SMTP and IMAP4. It is expected that Sun or other vendors will provide support for protocols, such as POP3 or the Network News Transfer Protocol (NNTP).
FIGURE 34.3. The JavaMail API layer.
NOTE: JavaMail does not provide all the pieces needed to develop user agent software. It only provides classes for dealing with basic message system objects. You must add your own application logic and messaging protocols.
NOTE: The JavaMail API is not part of JDK 1.2. It must be downloaded separately from the JavaSoft Web site at http://www.javasoft.com/products/javamail/. The JavaMail API requires that the JavaBeans Activation Framework (JAF) be installed. The JAF may be downloaded from http://java.sun.com/beans/glasgow/jaf.html.
NOTE: The mail.jar (JavaMail) and activation.jar (JAF) files must be added to your CLASSPATH before you can use JavaMail. To do this, copy mail.jar and activation.jar to your C:\jdk1.2\lib\ext directory and set your CLASSPATH using the following:
set CLASSPATH=%CLASSPATH%;C:\jdk1.2\lib\ext\mail.jar;C:\jdk1.2\lib\ext\ activation.jar
The javax.mail package provides the basic objects used by mail clients. It consists of 20 classes and three interfaces, as follows:
The most important classes in this list are Message, Store, Folder, Session, and Transport. The Message class provides the basic encapsulation of message objects. It implements the attributes of a message sender, message recipient, message subject, and message content. These attributes are implemented by the supporting classes of the javax.mail package. The Message class supports message types and multipart messages. Message types are integrated with the JavaBeans Activation Framework (JAF) described in Chapter 29, "Glasgow Developments."
The Store class supports the storing and retrieving of messages. A Store object is a collection of Folder objects, which are used to store and organize messages. The Store and Folder classes do not assume a particular implementation. Message storage can be implemented in a variety of ways, ranging from simple files to complex databases. Message storage can be accessed online (IMAP4) or offline (POP3) or a combination of both.
The Transport class is used to exchange messages with message transfer agents. It provides an abstract interface to a message transfer protocol, such as SMTP. It also provides connection management capabilities. In order to use the Transport class, you must start a mail transfer session with a message transfer agent. That's where the Session class comes in. It allows you to establish a session to a mail host using a specific transfer protocol. You'll learn how to use these classes in the mail client example later in this chapter.
The javax.mail.event package defines events, event listeners, and adapters for handling mail system events. The following events are defined:
The event listener interfaces used to implement event handlers for these events are as follows:
The following adapter classes are defined as basic implementations of these event listener interfaces:
All JavaMail event handling uses the JDK 1.1 event delegation model.
The javax.mail.internet package provides classes and interfaces for working with Internet mail headers (RFC 822) and MIME headers. These classes and interfaces are as follows:
These classes provide the basic functionality needed to develop an email client that supports standard Internet mail formats.
The javax.mail.search package provides classes that can be used for performing searches of messages and message parts. These classes are as follows:
You can use these classes to add message-searching capabilities to email clients.
Now that we've covered all the packages of the JavaMail API, let's work on an example so you can see which classes are important and how they are used to implement a mail client.
Listing 34.1 provides the source code for the MailClient application. This program implements a simple mail client that lets you send email to a specific address. The program is kept simple so that you can learn to use the basic classes used in implementing any mail application. Once you understand how MailClient works, feel free to experiment with it by adding other capabilities.
When you run MailClient, it displays the window shown in Figure 34.4. Fill in a destination email address, your source (return) email address, a subject, and then the message's content. When you are finished, click the Send Message button and the program sends the message to the specified destination. It informs you of its progress by displaying information in the status text area. Figure 34.5 shows the results of a message that I sent to myself. If you encounter any errors while running MailClient, make sure that you've entered a valid destination email address.
FIGURE 34.4. The MailClient opening display.
FIGURE 34.5. Sending a message.
MailClient shows how to use the MimeMessage (a subclass of Message), InternetAddress, Session, and Transport classes. It also shows how to perform basic message event handling.
The program begins by setting the mailHost variable to jaworski.com. Feel free to change this variable to the name of your SMTP mail host. After the mail host is identified, the program's GUI components are created.
The program's main(), setup(), and setupMenuBar() methods are fairly routine. The layoutComponents() method is somewhat long, but all it does is lay out the GUI components and add them the application window. A blank label is added at the end of this method. This is done to overcome a bug in the AWT that sometimes fails to display the last component added to a Frame using a null layout.
The sendMessage() method is the heart of the program's message processing. It declares a Properties object that is used to create an SMTP session with my mail host. The mail.smtp.host property is set to the mail host, and the mail.from property is set to the contents of the Source text field. The getInstance() method of the Session class is used to set up a connection with my mail server.
An object of the MimeMessage class is created using the Session object as an argument. The destination addresses are set to the single address specified in the Destination text field. The messages from address, subject, and content are taken from the Source and Subject text fields and the Content text area. The message's MIME type is set to text/plain.
A Transport object is created using the getTransport() method of the Session object. This object is used to perform the actual message transfer. ConnectionHandler and TransportHandler objects are used to handle events associated with the connection itself and the transport of messages across the connection. The connect() method establishes a connection with my mail server, and the sendMessage() method sends the message to the specified address.
The ConnectionHandler class provides three methods that handle the opening, disconnecting, and closing of connections to the mail server. The TransportHandler class provides methods for handling events associated with message delivery. The event handlers display status messages in the Status text area.
The ButtonHandler, MenuItemHandler, and WindowEventHandler classes handle events associated with the program's GUI.
import java.awt.*; import java.awt.event.*; import java.util.*; import javax.mail.*; import javax.mail.event.*; import javax.mail.internet.*; public class MailClient extends Frame { String mailHost = "jaworski.com"; Label toLabel = new Label("To:"); Label fromLabel = new Label("From:"); Label subjectLabel = new Label("Subject:"); Label contentLabel = new Label("Content:"); Label statusLabel = new Label("Status:"); TextField destination = new TextField(); TextField source = new TextField(); TextField subject = new TextField(); TextArea content = new TextArea(); Button send = new Button("Send Message"); TextArea status = new TextArea(); public static void main(String args[]){ MailClient app = new MailClient(); } public MailClient() { super("MailClient"); setup(); addWindowListener(new WindowEventHandler()); setSize(550,450); show(); } void setup() { setupMenuBar(); layoutComponents(); send.addActionListener(new ButtonHandler()); } void setupMenuBar() { MenuBar menuBar = new MenuBar(); Menu fileMenu = new Menu("File"); MenuItem fileExit = new MenuItem("Exit"); fileExit.addActionListener(new MenuItemHandler()); fileMenu.add(fileExit); menuBar.add(fileMenu); setMenuBar(menuBar); } void layoutComponents() { int x = 10; int y = 50; // Set bounds toLabel.setBounds(x,y,50,25); destination.setBounds(x+70,y,300,25); fromLabel.setBounds(x,y+40,50,25); source.setBounds(x+70,y+40,300,25); subjectLabel.setBounds(x,y+80,50,25); subject.setBounds(x+70,y+80,300,25); contentLabel.setBounds(x,y+120,50,25); content.setBounds(x+70,y+120,300,100); statusLabel.setBounds(x,y+240,50,25); status.setBounds(x+70,y+240,300,100); send.setBounds(400,y,100,30); // Add components add(toLabel); add(destination); add(send); add(fromLabel); add(source); add(subjectLabel); add(subject); add(contentLabel); add(content); add(statusLabel); add(status); add(new Label("")); } void sendMessage() { Properties properties = new Properties(); properties.put("mail.smtp.host",mailHost); properties.put("mail.from",source.getText()); Session session = Session.getInstance(properties, null); try { Message message = new MimeMessage(session); InternetAddress[] address = {new InternetAddress(destination.getText())}; message.setRecipients(Message.RecipientType.TO, address); message.setFrom(new InternetAddress(source.getText())); message.setSubject(subject.getText()); message.setContent(content.getText(),"text/plain"); Transport transport = session.getTransport(address[0]); transport.addConnectionListener(new ConnectionHandler()); transport.addTransportListener(new TransportHandler()); transport.connect(); transport.sendMessage(message,address); }catch(Exception e){ status.setText(e.toString()); } } class ConnectionHandler extends ConnectionAdapter { public void opened(ConnectionEvent e) { status.setText("Connection opened."); } public void disconnected(ConnectionEvent e) { status.setText("Connection disconnected."); } public void closed(ConnectionEvent e) { status.setText("Connection closed."); } } class TransportHandler extends TransportAdapter { public void messageDelivered(TransportEvent e) { status.setText("Message delivered."); } public void messageNotDelivered(TransportEvent e) { status.setText("Message NOT delivered."); } public void messagePartiallyDelivered(TransportEvent e) { status.setText("Message partially delivered."); } } class ButtonHandler implements ActionListener { public void actionPerformed(ActionEvent ev){ String s=ev.getActionCommand(); if(s.equals("Send Message")) sendMessage(); } }
class MenuItemHandler implements ActionListener { public void actionPerformed(ActionEvent ev){ String s=ev.getActionCommand(); if(s=="Exit"){ System.exit(0); } } } class WindowEventHandler extends WindowAdapter { public void windowClosing(WindowEvent e){ System.exit(0); } } }
In this chapter, you learned how mail systems work and how the JavaMail API is used to create email clients. You used this knowledge to develop a simple Internet mail client. In the next chapter, you'll learn how to use the directory service capabilities provided by the Java Naming and Directory Interface.
© Copyright, Macmillan Computer Publishing. All rights reserved.