<!----><!----><!----><!----><!----><!---->
<!----><!----><!----><!----> Tech Tips Archive January 22, 2002 WELCOME to the Java Developer Connection (JDC) Tech Tips, January 22, 2002. This issue covers:
These tips were developed using Java 2 SDK, Standard Edition, v 1.3. This issue of the JDC Tech Tips is written by John Zukowski, president of JZ Ventures, Inc. (http://www.jzventures.com). <!---->
<!----> RETRIEVING MAIL WITH THE JAVAMAIL API The JavaMail API provides the framework for sending and retrieving electronic messages (email). The JDC Tech Tip "Sending Mail With the JavaMail API" showed you how to send mail via SMTP through the JavaMail API. In this tip, you'll see how to retrieve messages from your POP/IMAP server. In many ways retrieving messages is similar to sending. For example, sending mail involves using the Session , Message , Address , and Transport classes. Retrieving messages involves the same Session and Message classes, however you also use Folder and Store classes. Once you make a connection to the mail server for message retrieval, the messages are stored in a Folder of the Store . The first thing you do to retrieve mail is connect to the mail server, just as you do for sending mail. But the mail servers are different. When you send mail, you connect to a server that supports the Simple Mail Transfer Protocol (SMTP). This is a protocol explicitly for sending electronic mail. When you retrieve mail, you connect to a server that supports the Post Office Protocol, Version 3 (POP3) or Internet Message Access Protocol, Version 4 (IMAP4) protocol. These protocols are designed for retrieving electronic mail. POP is a simple protocol. It allows users to retrieve mail, but it doesn't have the sophistication to do things like identify "new" mail. IMAP, by comparison, is more sophisticated. You can get a mail session with either the getDefaultInstance() or getInstance() methods of Session . Calling the getDefaultInstance() method returns a shared session instance. This means that the same session is returned (and thus shared) by every call to the method. The getInstance() method returns a new session instance each time you call it. New sessions are useful when you don't want other threads to be working simultaneously with the shared session. When you get the session, you must pass a Properties instance. This contains property settings such as the mail server you're using for the connection. You need to set the "mail.pop3.host " (or "mail.imap.host ") to the mail server for the connection (for example, pop.example.com): // Setup properties
Properties props = System.getProperties();
props.put("mail.pop3.host", host);
When you send mail, you should authenticate the connection, for instance, prompt for a username and password. You can do this by extending JavaMail's Authenticator class. For example, the following class, PopupAuthenticator , uses a Swing JOptionPane to prompt for a username and password. In this example, the user would enter the username and password as a comma-separated list. Notice that the getPasswordAuthentication() method returns the username and password. (Feel free to improve on this to use a JPasswordField instead for the password.). <!---->
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);
}
}
|
<!----> After you have the Properties , and an Authenticator , you can get a Session : // Setup authentication, get session
Authenticator auth = new PopupAuthenticator();
Session session =
Session.getDefaultInstance(props, auth);
Then make a connection to the Store with the getStore() method, passing the method the appropriate mail protocol for your server -- either "pop3" or "imap". Here's how you would make the appropriate connection to a POP3 server: // Get the store
Store store = session.getStore("pop3");
store.connect();
The call to the connect() method of Store triggers a call to PopupAuthenticator . As mentioned earlier, PopupAuthenticator prompts for a valid username and password combination. If you respond with a valid userid and password for the mail account, a connection is established with the mail server and you can then read your mail. All mail is stored in folders, that is, instances of the Folder class. So to read mail, the first thing you do is connect to the appropriate Folder. In the case of POP mail, there is only one folder, INBOX. In the case of IMAP, the Folder can be INBOX or any other folders that you created. Assuming you want to read mail from your INBOX, simply connect to the folder with the getFolder() method of Session: // Get folder
Folder folder = store.getFolder("INBOX");
Next, you need to open the Folder with the open() method. You can open it in either Folder.READ_WRITE mode or Folder.READ_ONLY mode. To read messages, you can use read-only, although if you want to delete messages, you need to use READ_WRITE . folder.open(Folder.READ_ONLY);
Connecting to the Folder gives you access to the individual Message objects. You can use the getMessage() method to get an individual message, or as in the following example, use the getMessages() method to get all the messages: // Get directory
Message message[] = folder.getMessages();
The Folder class also defines a getNewMessageCount() method to count the number of new messages in the Folder . However you shouldn't use it if you use a POP server -- remember POP doesn't support the concept of "new" messages. You have several options in deciding what to retrieve from each message. For instance, you can call getFrom() or getSubject() to retrieve the identity of the sender (as an Address array), or the message subject, respectively. <!---->
// Display from (only first) and subject of messages
for (int i=0, n=message.length; i<n; i++) {
System.out.println(i + ": "
+ message[i].getFrom()[0]
+ "\t" + message[i].getSubject());
}
|
<!----> More than likely though, you're interested in the message content. Typically, you use the getContent() method to see the message content: System.out.println(message[i].getContent());
You can also use the writeTo() method to get the message content. This permits you to save the entire contents of the message (including headers) to an output stream. After reading your mail, be sure to close the Folder and the Store . In the case of the Folder , the close() method requires you to specify whether you want to expunge any deleted messages. The Store doesn't require any arguments to its close() method: // Close connection
folder.close(false);
store.close();
What follows is a complete program, Fetch , that demonstrates the concepts described above. In order to run the program, you'll need to have the JavaMail API installed, as well as the JavaBeans Activation Framework. Information about where to get the downloads follows the program below. The Fetch program displays the first 200 characters of any messages currently stored in your INBOX. If your mail server supports IMAP and not POP, change the "pop3 " references in the code to "imap ". Before you compile the program, remember to first compile the PopupAuthenticator class shown earlier. Run the Fetch program from the command line like this: java Fetch mailserver
Replace "mailserver " with the name of your mail server. In response, the program will prompt you for your userid and password. <!---->
import java.io.*;
import java.util.Properties;
import javax.mail.*;
import javax.mail.internet.*;
public class Fetch {
public static void main (String args[])
throws Exception {
String host = args[0];
// Get system properties
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();
// 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());
String content =
message[i].getContent().toString();
if (content.length() > 200) {
content = content.substring(0, 200);
}
System.out.print(content);
}
// Close connection
folder.close(false);
store.close();
System.exit(0);
}
}
|
<!----> The latest version of the JavaMail API is available for download from the JavaMail API page. To use the JavaMail API, you must also have the JavaBeans Activation Framework installed. The JavaBeans Activation Framework is available for download from the JavaBeans Activation Framework page. You can also get the JavaMail API and the JavaBeans Activation Framework as part of the Java 2 Platform, Enterprise Edition 1.3 download. Source code for the JavaMail classes is available through the J2EE 1.3 Sun Community Source Licensing (SCSL) program. Here's a variation on the previous approach. If you don't want to use an Authenticator, get a Session without setting any properties. Then, provide the host name, username, and password to the connect() method. The following snippet shows this behavior: <!---->
// Setup 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);
|
<!----> Notice that the Fetch example does not deal with any message content as an attachment. For information on fetching attachments, see the tutorial "Fundamentals of the JavaMail API. Also, if you use Yahoo for mail, you must enable POP Access & Forwarding from their Options screen to get mail through the JavaMail API. You can't use Hotmail though -- it doesn't support remote access. <!---->
<!----> WORKING WITH THE JAVA COMMUNICATIONS API The Java Communications (COMM) API is an optional package for the Java 2 platform. It provides support for communicating with peripheral devices through the serial and parallel ports of a computer. It is a special API in the sense that while the API is well defined across platforms, you must download a platform-specific version of the COMM libraries to actually use them. This tip will demonstrate the COMM API by showing you how to get a list of the available ports on a machine and printing to a printer. The COMM API does not include support for communicating over Universal Serial Bus (USB) ports. Support for USB ports will be provided by a separate API that is currently undergoing a public review through the Java Community Process (JCP). See JSR 80 for details. To begin, download and unpack the Java Communications API. To get the Java Communications API for Windows and Solaris platforms visit the Java Communications API page. When you do that, you need to do a little setup work. You don't just put the comm.jar file into your class path, though that is the first step. You also must copy the shared library to the bin directory, and the javax.comm.properties file to the lib directory of the runtime environment. For Java 2 SDK, version 1.3 for Windows, that means: copy comm.jar \jdk1.3\jre\lib\ext
copy win32com.dll \jdk1.3\bin
copy javax.comm.properties \jdk1.3\jre\lib
After doing the setup work, the Java Communications API classes are available from the javax.comm package. The key classes in the package are CommPortIdentifier and CommPort . You use CommPortIdentifier to find out the set of installed CommPort objects. You can then communicate with any individual CommPort object. To find out what ports are installed, you ask the CommPortIdentifier for the installed set with getPortIdentifiers() . This returns an Enumeration of CommPortIdentifier objects. Each object is of the type PORT_PARALLEL or PORT_SERIAL , two constants in the CommPortIdentifier class. To demonstrate, the following fetches the set of ports available and reports the name and type of each: <!---->
import javax.comm.*;
import java.util.Enumeration;
public class ListPorts {
public static void main(String args[]) {
Enumeration ports =
CommPortIdentifier.getPortIdentifiers();
while (ports.hasMoreElements()) {
CommPortIdentifier port =
(CommPortIdentifier)ports.nextElement();
String type;
switch (port.getPortType()) {
case CommPortIdentifier.PORT_PARALLEL:
type = "Parallel";
break;
case CommPortIdentifier.PORT_SERIAL:
type = "Serial";
break;
default: /// Shouldn't happen
type = "Unknown";
break;
}
System.out.println(port.getName() + ": " + type);
}
}
}
|
<!----> ListPorts should produce results similar to the following: COM1: Serial
COM2: Serial
LPT1: Parallel
LPT2: Parallel
In addition to walking through an Enumeration of ports from the CommPortIdentifier , you can ask for a specific port. You do this by passing the name of the port (LPT1, for instance) to the getPortIdentifier() identifier method. This returns the port identifier, or throws a javax.comm.NoSuchPortException if the port doesn't exist. // Get port
CommPortIdentifier portId =
CommPortIdentifier.getPortIdentifier(portname);
To read from or write to a port, use the open() method. The open() method requires an owner name for the port, and a timeout value in milliseconds. // Open port
// Open requires a owner name and timeout
CommPort port = portId.open("Application Name", 30000);
After you've opened a port, you can read and write to it just like a socket connection. The InputStream is available from the getInputStream() method of CommPort and the OutputStream is available with getOutputStream() . // Setup output
OutputStream os = port.getOutputStream();
BufferedOutputStream bos =
new BufferedOutputStream(os);
Let's use the COMM API to print a file. To do that, you simply find the printer port, open it, get its OutputStream , and send the file contents through it. The following example demonstrates that sequence. It prints a sample PostScript file named sample.ps . You'll need to create the sample file first. Be sure to close the port and streams when you are finished with them. <!---->
import javax.comm.*;
import java.io.*;
public class PrintFile {
public static void main(String args[])
throws Exception {
if (args.length != 2) {
System.err.println(
"usage : java PrintFile port file");
System.err.println(
"sample: java PrintFile LPT1 sample.ps");
System.exit(-1);
}
String portname = args[0];
String filename = args[1];
// Get port
CommPortIdentifier portId =
CommPortIdentifier.getPortIdentifier(portname);
// Open port
// Open requires a owner name and timeout
CommPort port = portId.open("Application Name", 30000);
// Setup reading from file
FileReader fr = new FileReader(filename);
BufferedReader br = new BufferedReader(fr);
// Setup output
OutputStream os = port.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(os);
int c;
while ((c = br.read()) != -1) {
bos.write(c);
}
// Close
bos.close();
br.close();
port.close();
}
}
|
<!----> For more information about the Java Communications API, see the Java Communications API Users Guide. <!---->
<!----> IMPORTANT: Please read our Terms of Use and Privacy policies: http://www.sun.com/share/text/termsofuse.html http://www.sun.com/privacy/ FEEDBACK Comments? Send your feedback on the JDC Tech Tips to: [email protected] SUBSCRIBE/UNSUBSCRIBE - To subscribe, go to the subscriptions page, choose the newsletters you want to subscribe to and click "Update". - To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update". - ARCHIVES You'll find the JDC Tech Tips archives at: http://java.sun.com/jdc/TechTips/index.html - COPYRIGHT Copyright 2002 Sun Microsystems, Inc. All rights reserved. 901 San Antonio Road, Palo Alto, California 94303 USA. This document is protected by copyright. For more information, see: http://java.sun.com/jdc/copyright.html JDC Tech Tips January 22, 2002 <!----> Sun, Sun Microsystems, Java, Java Developer Connection, JavaMail, and JavaBeans are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. <!----><!----><!----><!----><!----><!----><!----><!----> |