0N/AFollowing is a description of the new APIs that are being
0N/Aintroduced in JavaMail 1.1
0N/APlease send comments and feedback to javamail@sun.com
0N/AIn some cases it is desirable for the object representing the content
0N/Aof a BodyPart to know something about the "context" in which it is
0N/Aoperating,
e.g., what other data is contained in the same Multipart
0N/Aobject, who sent the message containing the data, etc. This allows
0N/Afor more interesting content types that know more about the message
0N/Acontaining them and the mail system in general.
0N/AFor instance, the handler for a
text/html body part contained in a
0N/Aobject in order to find the related image data needed to display the
0N/AThere is one particular case in the current implementation where
0N/Athis need arises. (This is a bug in the current release.) When
0N/Aconstructing a MimeMessage object for a nested message contained
0N/Ain another message, the DataContentHandler needs the Session
0N/Aobject in order to construct the new MimeMessage object.
0N/ATo solve these problems we introduce a new class, a new interface,
0N/Aand a number of new methods.
0N/AThe MessageContext class provides the basic information about the
0N/A"context" in which a content object is operating:
0N/A * The context in which a piece of Message content is contained. A
0N/A * <code>MessageContext</code> object is returned by the
0N/A * <code>getMessageContext</code> method of the
0N/A * <code>MessageAware</code> interface. <code>MessageAware</code> is
0N/A * typically implemented by <code>DataSources</code> to allow a
0N/A * <code>DataContentHandler</code> to pass on information about the
0N/A * context in which a data content object is operating.
0N/Apublic class MessageContext {
0N/A * Create a MessageContext object describing the context of the
0N/A public MessageContext(Part part)
0N/A * Return the Part that contains the content.
0N/A * @return the containing Part, or null if not known
0N/A public Part getPart()
0N/A * Return the Message that contains the content.
0N/A * Follows the parent chain up through containing Multipart
0N/A * objects until it comes to a Message object, or null.
0N/A * @return the containing Message, or null if not known
0N/A public Message getMessage()
0N/A * Return the Session we're operating in.
0N/A * @return the Session, or null if not known
0N/A public Session getSession()
0N/AA MessageContext object can be obtained by a DataContentHandler from a
0N/ADataSource that also implements the MessageAware interface:
0N/A * An interface optionally implemented by <code>DataSources</code> to
0N/A * supply information to a <code>DataContentHandler</code> about the
0N/A * message context in which the data content object is operating.
0N/Apublic interface MessageAware {
0N/A * Return the message context.
0N/A public MessageContext getMessageContext();
0N/AThis new interface and class provides the basic information needed by
0N/Athe DataContentHandler to use in constructing more "interesting" objects
0N/Arepresenting a particular type of data.
0N/ATo allow navigation up the chain of components contained in a Message,
0N/Awe add the following methods.
0N/AFirst, on BodyPart we add:
0N/A * The <code>Multipart</code> object containing this
0N/A * <code>BodyPart</code>, if known.
0N/A protected Multipart parent;
0N/A * Return the containing <code>Multipart</code> object,
0N/A * or <code>null</code> if not known.
0N/A public Multipart getParent()
0N/A * The <code>Part</code> containing this <code>Multipart</code>,
0N/A protected Part parent;
0N/A * Return the <code>Part</code> that contains this
0N/A * (cod<code>Multipart</c object, or <code>null</code> if not known.
0N/A public Part getParent()
0N/A * Set the parent of this <code>Multipart</code> to be the specified
0N/A * <code>Part</code>. Normally called by the <code>Message</code>
0N/A * or <code>BodyPart</code> <code>setContent(Multipart)</code>
0N/A * <code>parent</code> may be <code>null</code> if the
0N/A * <code>Multipart</code> is being removed from its containing
0N/A * <code>Part</code>.
0N/A public void setParent(Part parent)
0N/ATo enable this new functionality we change the implementations of
0N/AMimeBodyPart, MimeMessage, and MimeMultipart to maintain the "parent"
0N/Alinks where possible. We also change MimePartDataSource to implement
0N/Athe MessageAware interface.
0N/A===================================================================
0N/AThe MimeMessage class requires a getMessageID() method.
0N/AThe client can now fetch it as a header, but since this is a "standard"
0N/ARFC822 header, we want to provide an easier access method.
0N/AAn added benefit is that protocols like IMAP, which provide this info
0N/Aas part of the ENVELOPE structure, can implement this method much more
0N/A * Returns the value of the "Message-ID" header field. Returns
0N/A * null if this field is unavailable or its value is absent. <p>
0N/A * The default implementation provided here uses the
0N/A * <code>getHeader()</code> method to return the value of the
0N/A * "Message-ID" field.
0N/A * @return Message-ID
0N/A * @exception MessagingException, if the retrieval of this field
0N/A * causes any exception.
0N/A public String getMessageID() throws MessagingException;
0N/A===================================================================
0N/AThe following methods in the UIDFolder interface have certain problems.
0N/AWe are proposing changes that will fix these problems. These are
0N/Abinary incompatible changes, but we think these changes are necessary for
0N/Athis interface to work in a useful manner. We are also not aware of
0N/Aanyone that has shipped a Store Provider that implements this interface,
0N/Aso we are hoping that the effect of this change is minimal (non-existent).
0N/A(1) Message getMessageByUID(long uid)
0N/A Get the Message corresponding to the given UID. If no such
0N/A A disconnected client can have a stash of UIDs from a
0N/Aprevious session. Some of these UIDs may have been expunged from the
0N/Aserver, but the disconnected client does not know this. It is quite
0N/Areasonable (and expected) for a disconnected client to use this
0N/Amethod when reconnecting - to check whether a UID is valid or not at
0N/A Since failure is an expected result here, using a
0N/ARunTimeException to indicate it, seems wrong and counter-intuitive for
0N/A Our solution is to allow this method to return null to indicate
0N/Athat the requested UID is not valid anymore. Thus, this method will no
0N/A(2) Message[] getMessagesByUID(long start, long end)
0N/A Get the Messages corresponding to the given UID range. If any
0N/A Similar, but worse than (1). We think that disconnected clients
0N/A(or clients that prefer to use UIDs) may issue
0N/A getMessagesByUID(1, LASTUID)
0N/Ato get all the Messages at the server, especially when the client does
0N/Anot know the exact UIDs for this folder. In this case, we certainly
0N/Ado not want this method to fail if some id in the given range is
0N/Anot a valid UID; rather we want it to return all available Messages from
0N/A Our solution is to remove the NoSuchElementException exception
0N/Aand allow this method to return Message objects in the given range.
0N/A(3) Message[] getMessagesByUID(long[] uids)
0N/A Get the Messages corresponding to the given UID range. If any
0N/A A disconnected client can have a stash of UIDs from a
0N/Aprevious session. Some of these UIDs may have been expunged from the
0N/Aserver, but the disconnected client does not know this. It is quite
0N/Areasonable (and expected) for a disconnected client to use this
0N/Amethod when reconnecting - to check whether a set of UIDs are valid
0N/Aor not at the server.
0N/A Since failure can be an expected result, using a
0N/ARunTimeException to indicate it, seems wrong and counter-intuitive for
0N/A Our solution is to allow this method to return null entries
0N/Ato indicate that a requested UID is not valid anymore. Thus, the
0N/Amessage array returned by this method can have null entries for the
0N/Ainvalid UIDs; and this method will no longer throw the
0N/A Note that the size of the returned Message array is the same
0N/Aas the size of the request array of UIDs, and that each entry in the
0N/AMessage array corresponds to the same index entry in the UID array.
0N/A===================================================================
0N/AThe InternetAddress class needs the following protected field to
0N/Aproperly support encoding of the "personal name".
0N/A protected String encodedPersonal; // the encoded personal name
0N/ANo other API changes are associated with this.
0N/AThis is a binary compatible change to JavaMail 1.0. However, there is
0N/Aa potential problem for any existing InternetAddress subclasses, which
0N/Acan cause them to break. This typically will affect only providers,
0N/AThe InternetAddress implementation will use this field to store the
0N/Aencoded personal name.
0N/A The getPersonal() method will return the protected
0N/A'personal' field; if this field is null, it will check the 'encodedPersonal'
0N/Afield and decode its value and return it.
0N/A The toString() method will use the protected 'encodedPersonal'
0N/Afield to create the RFC2047 compliant address string. If this field is
0N/Anull, it will check the 'personal' field, encode that if necessary and
0N/AThis implies that, if an InternetAddress subclass changes either
0N/Athe 'personal' or 'encodedPersonal' fields, it should set the other
0N/Ato null to force its recomputation. Unfortunately, this also implies
0N/Athat existing subclasses of InternetAddress that directly set the
0N/A'personal' field can break in certain situations.
0N/A We feel that the risk of this happening is minimal, since we
0N/Adon't expect that our users have subclassed InternetAddress. Also, this
0N/Ais necessary to properly support encoded personal names, so we feel that
0N/A================================================================
0N/AA utility method to convert java charsets into MIME charsets is
0N/AThe JDK supports a variety of charsets. The JDK has names for these
0N/Acharsets, unfortunately they dont always match to their MIME or IANA
0N/AIt is necessary in some cases, (especially for providers) to map the
0N/AJDK charset names into their MIME or IANA equivalents. This method does
0N/A * Convert a java charset into its MIME charset name. <p>
0N/A * Note that a future version of JDK (post 1.2) might provide
0N/A * this functionality, in which case, we might deprecate this
0N/A * @param charset the JDK charset
0N/A * is not possible, the passed in charset itself
0N/A public static String mimeCharset(String charset);
0N/A====================================================================
0N/A(6) getDefaultJavaCharset()
0N/A============================
0N/AThis method returns the default charset for the platform's locale, as
0N/Aa Java charset. This is a new static method to the MimeUtility class.
0N/A * Get the default charset for this locale. <p>
0N/A * @return the default charset of the platform's locale,
0N/A * as a Java charset. (NOT a MIME charset)
0N/A public static String getDefaultJavaCharset()
0N/A====================================================================
0N/A(7) Method to print out the nested Exceptions
0N/A=============================================
0N/AThe MessagingException class currently allows nested exceptions. It
0N/Awould be nice to have one single method to dump out all the
0N/AOverride the getMessage() method from the superclass (Throwable), to
0N/Aappend the messages from all nested Exceptions. This is similar to
0N/A==================================================================
0N/AThe current address related search terms - AddressTerm, FromTerm and
0N/ARecipientTerm are limited in that they operate on Address objects, not
0N/AStrings. These terms use the equals() method to compare the addresses -
0N/Awhich is not useful for the common case of substring comparisons.
0N/AHence we introduce three new SearchTerms:
0N/Apublic AddressStringTerm extends StringTerm {
0N/A * @param pattern the address pattern to be compared
0N/A protected AddressStringTerm(String pattern);
0N/A * Check whether the address pattern specified in the
0N/A * constructor is a substring of the string representation of
0N/A * the given Address object.
0N/A * @param address the address to match against
0N/A protected boolean match(Address address);
0N/Apublic FromStringTerm extends AddressStringTerm {
0N/A * @param address the address to be compared.
0N/A public FromStringTerm(String string);
0N/A * Check whether the address specified in the constructor is
0N/A * a substring of the "From" attribute of this message.
0N/A * @param msg the address comparison is applied to this Message
0N/A public boolean match(Message msg);
0N/Apublic RecipientStringTerm extends AddressStringTerm {
0N/A * @param type the recipient type
0N/A * @param address the address to be compared.
0N/A * Return the type of recipient to match with.
0N/A * Check whether the address specified in the constructor is
0N/A * a substring of the given Recipient attribute of this message.
0N/A * @param msg the address comparison is applied to this Message
0N/A public boolean match(Message msg);
0N/A==================================================================
0N/A===========================================================
0N/AAs per RFC2047 (MIME), the length of a header field that contains
0N/Aencoded-words is limited to 76 characters.
0N/AThere are two methods in the InternetAddress class that generate
0N/ARFC822 style address strings:
0N/A - The toString() method on InternetAddress, which generates
0N/A the string for one InternetAddress object
0N/A - The toString() static method, which generates a comma separated
0N/A string for the given array of InternetAddress objects.
0N/ABoth these methods currently do not honor the 76 character limit.
0N/AActually, the former does to an extent, since the encodedWord
0N/Aencoded words into multiples, if they stretch beyond 76 characters.
0N/AFor the 1.1 release, we are planning to fix the the toString()
0N/Astatic method as follows:
0N/AAdd a new static method
0N/A static String toString(Address[] address, int used)
0N/AThis method takes an array of Address objects and an integer representing
0N/Athe number of "used" character positions for the first line of this
0N/Afield. The typical use of this method is when setting RFC822 headers,
0N/Alike the "From" header. 'used' can be set to sizeof("From: ") in
0N/AWhen generating the string, this method starts a new line if the
0N/Aline-length to go over 76.
0N/ANote that this algorithm does not work right if the length of a single
0N/AInternetAddress is itself more than 76 characters. Also, it does not
0N/Aoptimally break an address field, so that the maximum characters are
0N/Aaccommodated in a single line.
0N/ASo, essentially, this is an initial attempt to solve this problem. We
0N/Awill add more APIs in the next version to further refine this.
0N/A==================================================================
0N/A=====================
0N/AIt is currently not possible to tell whether a folder is open READ_ONLY
0N/Aor READ_WRITE without attempting to write it and catching the exception.
0N/AWe propose to add a protected field to Folder to store the open mode and
0N/Aa new method to Folder to return the open mode. Because existing
0N/Asubclasses will not use this new field, we can't guarantee that the
0N/Amethod will always return the correct value (although all Folder subclasses
0N/Ain the JavaMail package will be updated to return the correct value).
0N/A protected int mode = -1;
0N/A * Return the open mode of this folder. Returns
0N/A * or -1 if the open mode is not known (usually only because an older
0N/A * <code>Folder</code> provider has not been updated to use this new
0N/A * @exception IllegalStateException if this folder is not opened
0N/A * @return the open mode of this folder
0N/A public int getMode() {
0N/A throw new IllegalStateException("Folder not open");
0N/A====================================================================
0N/A========================
0N/AThe URLName support in the JavaMail 1.0 API's is incomplete and
0N/Ainadequately specified. While you can get a Folder from a Session
0N/Agiven a URLName for the folder, you can't find out the URLName
0N/Afor a given Folder object. We propose adding the following method
0N/A * Return a URLName representing this folder. The returned URLName
0N/A * does <em>not</em> include the password used to access the store.
0N/A * @return the URLName representing this folder
0N/A public URLName getURLName() throws MessagingException
0N/APreviously it was not specified whether the URLName returned from
0N/Anot, but sometimes it did. We propose to tighen the specification
0N/Aand fix the implementation so that the password field is not returned:
0N/A * Return a URLName representing this store. The returned URLName
0N/A * does <em>not</em> include the password field. <p>
0N/A * Subclasses should only override this method if their
0N/A * URLName does not follow the standard format.
0N/A * @return the URLName representing this store
0N/A public URLName getURLName()
0N/ASimilarly for Transport.
0N/APreviously it was unspecified how the Store and Transport connect
0N/Amethods interacted with the url field. In some cases it would be
0N/Aupdated and in other cases it would not. We propose to tighen the
0N/Aspecification as follows:
0N/A * Connect to the specified address. This method provides a simple
0N/A * authentication scheme that requires a username and password. <p>
0N/A * If the connection is successful, an "open" ConnectionEvent is
0N/A * delivered to any ConnectionListeners on this Store. <p>
0N/A * It is an error to connect to an already connected Store. <p>
0N/A * The implementation in the Store class will collect defaults
0N/A * for the host, user, and password from the session, prompting the
0N/A * user if necessary, and will then call the protocolConnect method,
0N/A * which the subclass must override. The subclass should also
0N/A * implement the <code>getURLName</code> method, or use the
0N/A * implementation in this class. <p>
0N/A * On a successful connection, the <code>setURLName</code> method is
0N/A * called with a URLName that includes the information used to make
0N/A * the connection, including the password. <p>
0N/A * If the password passed in is null and this is the first successful
0N/A * connection to this store, the user name and the password
0N/A * collected from the user will be saved as defaults for subsequent
0N/A * connection attempts to this same store. If the password passed
0N/A * in is not null, it is not saved, on the assumption that the
0N/A * application is managing passwords explicitly.
0N/A * @param host the host to connect to
0N/A * @param user the user name
0N/A * @param password this user's password
0N/A * @exception AuthenticationFailedException for authentication failures
0N/A * @exception MessagingException for other failures
0N/A * @exception IllegalStateException if the store is already connected
0N/A public void connect(String host, String user, String password)
0N/A throws MessagingException
0N/AAnd add this method to Store and Transport:
0N/A * Set the URLName representing this store.
0N/A * Normally used to update the <code>url</code> field
0N/A * after a store has successfully connected. <p>
0N/A * Subclasses should only override this method if their
0N/A * URLName does not follow the standard format. <p>
0N/A * The implementation in the Store class simply sets the
0N/A * <code>url</code> field.
0N/A protected void setURLName(URLName url)
0N/AAnd finally, to simplify the implementation of Store and Transport,
0N/Aand make the common design patterns between them more clear, we're
0N/Aconsidering introducing a new Service class as a superclass of
0N/AStore and Transport, and moving all common methods (the various
0N/Aconnnect methods, URLName methods, and some listener methods) to
0N/Athe superclass. Note that this is a binary compatible change.
0N/A=====================================================================
0N/A12) New Service class
0N/A======================
0N/ATo emphasize the commonality in behavior between the Store and
0N/ATransport classes, and to simplify maintenance of these classes, we
0N/Apropose moving many of the common methods to a new superclass called
0N/AThese existing methods currently have identical implementations in the
0N/AStore and Transport classes so moving them to a common superclass will
0N/Anot change the behavior of either Store or Transport.
0N/AThe Service class will contain all the methods and fields having to do
0N/Awith connecting, connection listeners, and naming via URLNames. The
0N/AStore class retains the methods for getting Folders and managing Store
0N/Aand Folder listeners. The Transport class retains the methods for
0N/Asending messages and managing Transport listeners.
0N/ANote that this is a binary compatible change both for existing users of
0N/Athe Store and Transport classes, as well as for existing subclasses of
0N/A======================================================================