The Message Class

The javax.mail.Message class is the abstract superclass for all individual emails, news postings, and similar messages:

public abstract class Message extends Object implements Part

There’s one concrete Message subclass in the standard JavaMail API, javax.mail.internet.MimeMessage . This is used for both email and Usenet news messages. Service providers are free to add classes for their own message formats. For instance, IBM might provide a NotesMessage class for Lotus Notes.

The Message class mainly declares abstract getter and setter methods that define the common properties of most messages. These properties include the addressees of the message, the recipients of the message, the subject and content of the message, and various other attributes. You can think of these as properties of the envelope that contains the message.

Furthermore, the Message class implements the Part interface. The Part interface mostly handles the body of an email message. It declares methods for getting and setting the content type of the message body, getting and setting the actual message body content, getting and setting arbitrary headers from the message, and getting input streams that are fed by the message body. The main body part of a message can contain other parts. This is used to handle attachments, message bodies that are available in multiple formats, and other multipart emails. Since the Message class is abstract and needs to be subclassed by concrete classes such as MimeMessage, most of these methods are not actually redeclared in Message but can be invoked by any actual instance of Message. We’ll begin by discussing the methods actually declared in Message, then move on to those declared in Part.

Creating Messages

The Message class has three constructors:

protected Message(  )
protected Message(Folder folder, int messageNumber)
protected Message(Session session)

Since all the constructors are protected, these are primarily for the use of subclasses such as MimeMessage. If you’re sending a message, you’ll use one of the constructors in the subclass instead. If you’re reading messages, then the Folder or Session you’re reading from will create the Message objects and pass them to you.

Replying to messages

If you already have a Message object, one way to create a new Message object is to reply to the existing one using the reply( ) method:

public abstract Message reply(boolean replyToAll) 
 throws MessagingException

This method creates a new Message object with the same subject prefixed with “Re: " and addressed to the sender of the original message. If replyToAll is true, then the message is addressed to all known recipients of the original message. The content of the message is empty. If you want to quote the original message, you’ll have to do that yourself.

Getting messages from folders

You’ve already seen that when you’re reading email, the JavaMail API creates Message objects to represent the messages it finds on the server. The primary means of doing this are the getMessage( ) and getMessages( ) methods in the Folder class:

public abstract Message getMessage(int messageNumber) 
 throws MessagingException
public Message[] getMessages(int start, int end) 
 throws MessagingException
public Message[] getMessages(int[] messageNumbers) 
 throws MessagingException
public Message[] getMessages(  ) throws MessagingException

The first three methods allow the caller to specify which messages it wants. The last simply returns all messages in the folder. What’s actually returned are stubs holding the places of the actual messages. The text and headers of the message won’t necessarily be retrieved until some method of the Message class is invoked that requires this information.

Basic Header Info

A typical RFC 822 message contains a header that looks something like this:

From [email protected] Fri Aug  5 10:57:08 1994
Date: Fri, 5 Aug 1994 10:57:04 +0700
From: [email protected] (Denise Levi)
To: [email protected]
Subject: Apologies
Content-Length: 517
Status: RO
X-Lines: 13

The exact fields can vary, but most messages contain at least a From: field, a To: field, a Date: field, and a Subject: field. Other common fields include Cc: (carbon copies) and Bcc: (blind carbon copies). In general, these will be accessible through getter and setter methods.

The From address

These four methods allow you to get and set the From: field of a message:

public abstract Address[] getFrom(  ) throws MessagingException
public abstract void setFrom(  ) throws MessagingException, 
 IllegalWriteException, IllegalStateException 
public abstract void setFrom(Address address) 
 throws MessagingException, IllegalWriteException, IllegalStateException
public abstract void addFrom(Address[] addresses) 
 throws MessagingException, IllegalWriteException, IllegalStateException

The getFrom( ) method returns an array of Address objects, one for each address listed in the From: header. (In practice, it’s rare for a message to be from more than one address. It’s quite common for a message to be addressed to more than one address.) It returns null if the From: header isn’t present in the message. It throws a MessagingException if the From: header is malformed in some way.

The noargs setFrom( ) and addFrom( ) methods set and modify the From: headers of outgoing email messages. The noargs setFrom( ) method sets the header to the current value of the mail.user property or, as a fallback, the user.name property. The setFrom( ) method with arguments sets the value of the From: header to the listed addresses. The addFrom( ) method adds the listed addresses to any addresses that already exist in the header. All three of these methods can throw a MessagingException if one of the addresses they use isn’t in the right format. They can also throw an IllegalWriteException if the From: field of the given Message object cannot be changed or an IllegalStateException if the entire Message object is read only.

The Reply-to address

Some messages contain a Reply-to: header indicating that any replies should be sent to a different address than the one that sent the message. There are two methods to set and get these addresses:

public Address[] getReplyTo(  ) throws MessagingException
public void setReplyTo(Address[] addresses) throws MessagingException, 
 MethodNotSupportedException, IllegalWriteException, 
 IllegalStateException

The semantics of these methods are the same as for the equivalent getFrom( ) and setFrom( ) methods—in fact, the default implementation of getReplyTo( ) simply returns getFrom( )--with the single caveat that an implementation that doesn’t support separate Reply-to: addresses may throw a MethodNotSupportedException when setReplyTo( ) is invoked.

The recipient addresses

Whereas the sender of the message is generally found only in the From: header, the recipients of the message are often split across the To:, Cc:, and Bcc: fields. Rather than providing separate methods for each of these fields, the various getRecipients( ) and setRecipients( ) methods rely on a Message.RecipientType argument to determine which field’s value is desired. RecipientType is a public inner class in javax.mail.Message whose private constructor limits it to exactly these three static objects:

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

There are two methods to find the addressees of the Message:

public abstract Address[]getRecipients(Message.RecipientType type) 
 throws MessagingException
public Address[] getAllRecipients(  ) throws MessagingException

The getRecipients( ) method returns an array of Address objects, one for each address listed in the specified header. It returns null if the specified header isn’t present in the message. It throws a MessagingException if the specified header is malformed in some way. The getAllRecipients( ) method does the same except that it combines the contents of the To:, Cc:, and Bcc: headers.

There are two methods to set the recipients of the message while replacing any previous recipients and two methods to add recipients to the message:

public abstract void setRecipients(Message.RecipientType type, 
 Address[] addresses) throws MessagingException, IllegalWriteException, 
 IllegalStateException
public void setRecipient(Message.RecipientType type, Address address) 
 throws MessagingException, IllegalWriteException
public abstract void addRecipients(Message.RecipientType type, 
 Address[] addresses) throws MessagingException,  
 IllegalWriteException, IllegalStateException
public void addRecipient(Message.RecipientType type, Address address) 
 throws MessagingException, IllegalWriteException

All four of these methods can throw a MessagingException, typically because one of the addresses used isn’t in the right format. They can also throw an IllegalWriteException if the specified field of the given Message object cannot be changed or an IllegalStateException if the entire Message object is read-only.

The subject of the message

Since the subject is simply a single string of text, it’s very easy to set and get with these two methods:

public abstract String getSubject(  ) throws MessagingException
public abstract void   setSubject(String subject) throws 
 MessagingException, IllegalWriteException, IllegalStateException

As with earlier setter methods, null is returned if the subject field isn’t present in the message. An IllegalWriteException is thrown if the program isn’t allowed to set the value of the Subject: field, and an IllegalStateException is thrown if the program isn’t allowed to change the message at all.

The date of the message

Messages also have sent and received dates. Three methods allow programs to access these fields:

public abstract Date getSentDate(  ) throws MessagingException
public abstract void setSentDate(Date date) throws MessagingException, 
 IllegalWriteException, IllegalStateException
public abstract Date getReceivedDate(  ) throws MessagingException

The underlying implementation is responsible for converting the textual date format found in a message header like “Fri, 5 Aug 2000 10:57:04 +0700” to a java.util.Date object. As usual, a MessagingException indicates some problem with the format of the underlying message; an IllegalWriteException indicates that the field cannot be changed; and an IllegalStateException indicates that the entire message cannot be changed.

Example 19.8 is a simple example program that follows the basic pattern of the last several mail-reading programs. However, this one no longer uses writeTo( ). Instead, it uses the methods in this section to print just the headers. Furthermore, it prints them in a particular order regardless of their order in the actual message on the server. Finally, it ignores the less important headers such as X-UIDL: and Status:. The static InternetAddress.toString( ) method converts the arrays that most of these methods return into simple, comma-separated strings.

Example 19-8. A Program to Read Mail Headers

import javax.mail.*;
import javax.mail.internet.*;
import java.util.*;

public class HeaderClient {

  public static void main(String[] args) {
    if (args.length == 0) {
      System.err.println(
       "Usage: java HeaderClient protocol://username@host/foldername");
      return; 
    }
    
    URLName server = new URLName(args[0]);

    try {

      Session session = Session.getDefaultInstance(new Properties(  ), 
       new MailAuthenticator(server.getUsername(  )));

      // Connect to the server and open the folder
      Folder folder = session.getFolder(server);
      if (folder == null) {
        System.out.println("Folder " + server.getFile(  ) + " not found.");
        System.exit(1);
      }  
      folder.open(Folder.READ_ONLY);
      
      // Get the messages from the server
      Message[] messages = folder.getMessages(  );
      for (int i = 0; i < messages.length; i++) {
        System.out.println("------------ Message " + (i+1) 
         + " ------------");
        // Here's the big change...
        String from = InternetAddress.toString(messages[i].getFrom(  ));
        if (from != null) System.out.println("From: " + from);
        String replyTo = InternetAddress.toString(
         messages[i].getReplyTo(  ));
        if (replyTo != null) System.out.println("Reply-to: " 
         + replyTo);
        String to = InternetAddress.toString(
         messages[i].getRecipients(Message.RecipientType.TO));
        if (to != null) System.out.println("To: " + to);
        String cc = InternetAddress.toString(
        messages[i].getRecipients(Message.RecipientType.CC));
        if (cc != null) System.out.println("Cc: " + cc);
        String bcc = InternetAddress.toString(
         messages[i].getRecipients(Message.RecipientType.BCC));
        if (bcc != null) System.out.println("Bcc: " + to);
        String subject = messages[i].getSubject(  );
        if (subject != null) System.out.println("Subject: " + subject);
        Date sent = messages[i].getSentDate(  );
        if (sent != null) System.out.println("Sent: " + sent);
        Date received = messages[i].getReceivedDate(  );
        if (received != null) System.out.println("Received: " + received);
        
        System.out.println(  );
      } 

      // Close the connection 
      // but don't remove the messages from the server
      folder.close(false);
      
    } 
    catch (Exception e) {
      e.printStackTrace(  );
    }  
          
    // Since we may have brought up a GUI to authenticate,
    // we can't rely on returning from main(  ) to exit
    System.exit(0);     
    
  }
}

Here’s some typical output. Several of the requested strings were null because the fields simply weren’t present in the messages in the INBOX; for instance, Cc: and Bcc:. HeaderClient checks for that and simply omits the fields if they’re not present.

% java HeaderClient pop3://[email protected]/INBOX
------------ Message 1 ------------
From: Elliotte Harold <[email protected]>
Reply-to: Elliotte Harold <[email protected]>
To: [email protected]
Subject: test
Sent: Tue Nov 30 13:14:29 PST 1999

------------ Message 2 ------------
From: Elliotte Rusty Harold <[email protected]>
Reply-to: Elliotte Rusty Harold <[email protected]>
To: [email protected]
Subject: New system
Sent: Wed Dec 01 10:55:40 PST 1999

------------ Message 3 ------------
From: Dr. Mickel <[email protected]>
Reply-to: Dr. Mickel <[email protected]>
To: [email protected]
Subject: Breath RX Products now available Online!
Sent: Thu Dec 02 03:45:52 PST 1999

Notice that none of these messages have received dates. That’s because the receive time is not part of the message envelope itself. It has to be provided by the server, and POP servers don’t provide it. An IMAP server would be much more likely to include a received date, as will be shown in Example 19.9.

Saving changes

When you invoke one of the previous set or add methods, some implementations will store the changes immediately. Others, however, may not. The saveChanges( ) method commits the changes made to a Message object:

public abstract void saveChanges(  ) throws MessagingException,
 IllegalWriteException, IllegalStateException

This is not quite a flush. The actual changes may not be committed to disk until the folder containing the message is closed. However, this method does ensure that the changes are stored in the folder and that they will be saved when the folder is saved.

Flags

Mail programs can save extra information about the messages that are not part of the messages themselves. For instance, Pine lets me know whether I’ve replied to a message, whether I’ve read a message, and so on. As Figure 19.5 shows, these are indicated by symbols and letters in the lefthand column. D means a message has been deleted; A means it’s been answered; N is a new message that hasn’t been read yet; and so forth. In the JavaMail API, these are all represented as flags. A flag is an instance of the javax.mail.Flags class:

public class Flags extends Object implements Cloneable

Seven flags are predefined as instances of the public static inner class Flags.Flag. These are:

Flags.Flag.ANSWERED 
Flags.Flag.DELETED 
Flags.Flag.DRAFT
Flags.Flag.FLAGGED 
Flags.Flag.RECENT 
Flags.Flag.SEEN 
Flags.Flag.USER

In addition, some implementations may allow arbitrary user-defined flags. If so, the USER flag will be set.

Pine shows flags as letters in the lefthand column

Figure 19-5. Pine shows flags as letters in the lefthand column

The getFlags( ) method returns the flags of a particular message:

public abstract Flags getFlags(  ) throws MessagingException

The isSet( ) method tests whether a specified flag is set for the given message:

public boolean isSet(Flags.Flag flag) throws MessagingException

Finally, the setFlags( ) and setFlag( ) methods set or unset (depending on the second argument) the flag indicated by the first argument:

public abstract void setFlags(Flags flag, boolean set) 
 throws MessagingException, IllegalWriteException, 
 IllegalStateException 
public void setFlag(Flags.Flag flag, boolean set) throws 
 MessagingException, IllegalWriteException, IllegalStateException

You delete messages by setting their Flags.Flag.DELETED flag to true. For example, to delete message:

message.setFlag(Flags.Flag.DELETED, true);

This only marks the message as deleted. It does not actually expunge it from the file on the server. Until the message is expunged, it can still be undeleted by setting Flags.Flag.DELETED back to false.

Example 19.9 is a slight modification of Example 19.8, HeaderClient, that prints the flags as well. As a general rule, POP servers won’t report flags. Only a protocol that stores messages and forwards them, such as IMAP or mbox, will report flags.

Example 19-9. A Program to Read Mailbox Flags

import javax.mail.*;
import javax.mail.internet.*;
import java.util.*;

public class FlagsClient {

  public static void main(String[] args) {
    
    if (args.length == 0) {
      System.err.println(
       "Usage: java FlagsClient protocol://username@host/foldername");
      return; 
    }
    
    URLName server = new URLName(args[0]);

    try {

      Session session = Session.getDefaultInstance(new Properties(  ), 
       new MailAuthenticator(server.getUsername(  )));

      // Connect to the server and open the folder
      Folder folder = session.getFolder(server);
      if (folder == null) {
        System.out.println("Folder " + server.getFile(  ) + " not found.");
        System.exit(1);
      }  
      folder.open(Folder.READ_ONLY);
      
      // Get the messages from the server
      Message[] messages = folder.getMessages(  );
      for (int i = 0; i < messages.length; i++) {
        System.out.println("------------ Message " + (i+1) 
         + " ------------");
        // Get the headers
        String from = InternetAddress.toString(messages[i].getFrom(  ));
        if (from != null) System.out.println("From: " + from);
        String replyTo = InternetAddress.toString(
         messages[i].getReplyTo(  ));
        if (replyTo != null) System.out.println("Reply-to: " 
         + replyTo);
        String to = InternetAddress.toString(
         messages[i].getRecipients(Message.RecipientType.TO));
        if (to != null) System.out.println("To: " + to);
        String cc = InternetAddress.toString(
        messages[i].getRecipients(Message.RecipientType.CC));
        if (cc != null) System.out.println("Cc: " + cc);
        String bcc = InternetAddress.toString(
         messages[i].getRecipients(Message.RecipientType.BCC));
        if (bcc != null) System.out.println("Bcc: " + to);
        String subject = messages[i].getSubject(  );
        if (subject != null) System.out.println("Subject: " + subject);
        Date sent = messages[i].getSentDate(  );
        if (sent != null) System.out.println("Sent: " + sent);
        Date received = messages[i].getReceivedDate(  );
        if (received != null) System.out.println("Received: " + received);
        
        // Now test the flags:
        if (messages[i].isSet(Flags.Flag.DELETED)) {
          System.out.println("Deleted");
        }
        if (messages[i].isSet(Flags.Flag.ANSWERED)) {
          System.out.println("Answered");
        }
        if (messages[i].isSet(Flags.Flag.DRAFT)) {
          System.out.println("Draft");
        }
        if (messages[i].isSet(Flags.Flag.FLAGGED)) {
          System.out.println("Marked");
        }
        if (messages[i].isSet(Flags.Flag.RECENT)) {
          System.out.println("Recent");
        }
        if (messages[i].isSet(Flags.Flag.SEEN)) {
          System.out.println("Read");
        }
        if (messages[i].isSet(Flags.Flag.USER)) {
          // We don't know what the user flags might be in advance 
          // so they're returned as an array of strings
          String[] userFlags = messages[i].getFlags().getUserFlags(  );
          for (int j = 0; j < userFlags.length; j++) {   
            System.out.println("User flag: " + userFlags[j]);
          }
        }      
        
        System.out.println(  );
      } 

      // Close the connection 
      // but don't remove the messages from the server
      folder.close(false);
      
    } 
    catch (Exception e) {
      e.printStackTrace(  );
    }  
          
    // Since we may have brought up a GUI to authenticate,
    // we can't rely on returning from main(  ) to exit
    System.exit(0);     
    
  }
}

Here’s a sample run. The first message has been read and deleted. The second message has no set flags. It hasn’t been read, deleted, or answered. The third message has been read and answered but not deleted. Notice that I’m using an IMAP server instead of a POP server:

% java FlagsClient imap://[email protected]/INBOX
------------ Message 1 ------------
From: Mike Hall <[email protected]>
Reply-to: Mike Hall <[email protected]>
To: [email protected]
Subject: Re: dialog box, parents & X-platform
Sent: Mon Dec 13 05:24:38 PST 1999
Received: Mon Dec 13 06:33:00 PST 1999
Deleted
Read

------------ Message 2 ------------
From: Kapil Madan <[email protected]>
Reply-to: [email protected]
To: [email protected]
Subject: Re: first mail to the list!
Sent: Mon Dec 13 06:19:46 PST 1999
Received: Mon Dec 13 06:40:00 PST 1999

------------ Message 3 ------------
From: Jim Jackl-Mochel <[email protected]>
Reply-to: Jim Jackl-Mochel <[email protected]>
To: [email protected]
Subject: CPreProcessorStream
Sent: Mon Dec 13 07:14:00 PST 1999
Received: Mon Dec 13 07:08:00 PST 1999
Answered
Read
               

Folders

Messages received from the network (as opposed to being sent to the network) will generally belong to some Folder. The getFolder( ) method returns a reference to the Folder object that contains this Message:

public Folder getFolder(  )

It returns null if the message isn’t contained in a folder.

Within a folder, messages are organized from first (message 1) to last. The getMessageNumber( ) method returns the relative position of this Message in its Folder:

public int getMessageNumber(  )

Messages that aren’t in any folder have number 0. Message numbers may change while a program is running if other messages are added to or deleted from a folder.

There’s also a protected setMessageNumber( ) method, but it’s only for service providers, not for user code:

protected void setMessageNumber(int number)

We’ll talk more about folders and what they can do at the end of this chapter. One of the things you can do with a folder is expunge messages from it. This physically deletes the message if it’s already been marked deleted. (A merely deleted message can be “undeleted”, whereas an expunged message cannot be.) If a message is expunged, there may still be a Message object pointing to the message but almost all methods on the message will throw a MessagingException. Thus, it may be important to check whether a message has been expunged before working with it. The isExpunged( ) method does that:

public boolean isExpunged(  )

There’s also a protected setExpunged( ) method, but it’s only for service providers, not for user code:

protected void setExpunged(boolean expunged)

Searching

The final method left in the Message class is match( ) . The match( ) method is used to determine whether a Message satisfies particular search criteria. We’ll discuss this more in a bit when we talk about searching folders:

public boolean match(SearchTerm term) throws MessagingException
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.129.13.201