Return-Path: Received: from pacific-carrier-annex.mit.edu by po10.mit.edu (8.9.2/4.7) id MAA00166; Tue, 22 Jan 2002 12:34:00 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by pacific-carrier-annex.mit.edu (8.9.2/8.9.2) with SMTP id MAA18751; Tue, 22 Jan 2002 12:25:08 -0500 (EST) Date: Tue, 22 Jan 2002 17:30:00 GMT+00:00 From: "JDC Tech Tips" To: alexp@mit.edu Message-Id: <8184254-135833555@hermes.sun.com> Subject: JDC Tech Tips January 22, 2002 (Retrieving Mail, COMM API) Precedence: junk Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: Beyond Email J D C T E C H T I P S TIPS, TECHNIQUES, AND SAMPLE CODE WELCOME to the Java Developer Connection(sm) (JDC) Tech Tips, January 22, 2001. This issue covers: * Retrieving Mail with the JavaMail(tm) API * Working with the Java(tm) Communications API These tips were developed using Java 2 SDK, Standard Edition, v 1.3 and Java 2 Enterprise 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). You can view this issue of the Tech Tips on the Web at http://java.sun.com/jdc/JDCTechTips/2002/tt0122.html - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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" (http://java.sun.com/jdc/JDCTechTips/2001/tt1023.html#tip2) 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 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 (http://java.sun.com/products/javamail/). 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 (http://java.sun.com/products/javabeans/glasgow/jaf.html). You can also get the JavaMail API and the JavaBeans Activation Framework as part of the Java 2 Platform, Enterprise Edition 1.3 download at http://java.sun.com/j2ee/download.html. Source code for the JavaMail classes is available through the J2EE 1.3 Sun Community Source Licensing (SCSL) program at http://www.sun.com/software/communitysource/j2ee/. 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 at http://java.sun.com/jdc/onlineTraining/JavaMail/. 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 (http://www.jcp.org/jsr/detail/80.jsp) 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 at http://java.sun.com/products/javacomm/. 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 at http://java.sun.com/products/javacomm/javadocs/API_users_guide.html . . . . . . . . . . . . . . . . . . . . . . . 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: jdc-webmaster@sun.com * SUBSCRIBE/UNSUBSCRIBE - To subscribe, go to the subscriptions page, (http://developer.java.sun.com/subscription/), choose the newsletters you want to subscribe to and click "Update". - To unsubscribe, go to the subscriptions page, (http://developer.java.sun.com/subscription/), uncheck the appropriate checkbox, and click "Update". - To use our one-click unsubscribe facility, see the link at the end of this email: - 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. To use our one-click unsubscribe facility, select the following URL: http://sunmail.sun.com/unsubscribe?8184254-135833555