Thursday, July 15, 2010

JavaMail's Internal Workings


  • JavaMail supports simultaneous multiple sessions and each session can access multiple message stores and transports. In a JVM, multiple applications can share the same default mail session. This way, only one application needs to have the information and code necessary to connect to a mail server and authenticate the user. Other applications then simply call send or fetch methods.
  • Session object's getInstance(...), getDefaultInstance(...), getStore(...) and getTransport(...) methods look for your configured javaMail implementations in two text files named javamail.providers and javamail.default.providers.

    Usually, you don't need to do anything because the default providers in mail.jar file are sufficient.

  • The lines in these files specify which Java class to use for which protocol. Sample javamail.providers file:
    protocol=imap; type=store; class=com.sun.mail.imap.IMAPStore; vendor=SunMicrosystems,Inc;
    protocol=smtp; type=transport;class=com.sun.mail.smtp.SMTPTransport;
  • It searches for configured implementations as follows:
    1. First, using the java.home system property, it looks for the wanted protocol's configuration in the java.home/lib/javamail.providers file. There can be one such file per JVM.
    2. If the above file does not exist or the wanted protocol is not found in the above file, it looks for the wanted protocol's configuration in the META-INF/javamail.providers file in your application's directory or JAR file. There can be one such file per application.
    3. If the above file does not exist or the wanted protocol is not found in the above file, it looks for the wanted protocol's configuration in the META-INF/javamail.default.providers file in JavaMail's mail.jar file. There can be one such file per JavaMail installation.
  • For a specific protocol, the first provider listed wins and is used by default. You can change the default by setting the mail.protocol.class property to the class name you want when you create the Session object.
    props.put("mail.smtp.class", "com.acme.SMTPTRANSPORT");
    Session session = Session.getInstance(props, null);

    Or, you can change it later using Session's getProviders(), getProvider() and setProvider() methods.

    // Find out which implementations are available
    Provider[] providers = session.getProviders();
    // Pick a provider
    Provider yourPick = providers[5]; // For example
    // Then, set a provider
    session.setProvider(yourPick);

    A Provider object cannot be explicitly created; it must be retrieved using the session.getProviders() method and it must be one of those configured in the resource files.

    The providers in your files are added before the ones that come in mail.jar's default files. All are available from your code via the session.getProviders() method.

  • JavaMail can instantiate the correct Transport object implementing the correct protocol based on the recipient's address. How does it do that? It looks for address-type-to-protocol mapping in two text files named javamail.address.map and javamail.default.address.map.

    Usually, you don't need to do anything because the default mappings in mail.jar file are sufficient.

  • Each line of these files maps an address type to a transport protocol. To determine an address type, use javax.mail.Address.getType() method to get the address type. For example,
    Address a = new InternetAddress("your@buddy.com");
    String addrType = a.getType(); // Returns "rfc822"

    Two common address types are "rfc822" (InternetAddress class) and "news" (NewsAddress class).

  • Sample javamail.address.map:
    rfc822=smtp
    news=nntp
  • It searches for configured mappings as follows (This is the same search order as for the providers file above):
    1. First, using the java.home system property, it looks for the wanted address type's mapping in the java.home/lib/javamail.address.map file. There can be one such file per JVM.
    2. If the above file does not exist or the wanted address type is not found in the above file, it looks for the wanted address type's mapping in the META-INF/javamail.address.map file in your application's directory or JAR file. There can be one such file per application.
    3. If the above file does not exist or the wanted address type is not found in the above file, it looks for the wanted address type's mapping in the META-INF/javamail.default.address.map file in JavaMail's mail.jar file. There can be one such file per JavaMail installation.
  • Folders can also be accessed using URLNames which may be constructed from strings specifying protocol, host, port, file, username, password. RFC 1738 specifies the URL syntax for IP-based protocols such as IMAP4 and POP3. Specify -1 as port number to use the default port.
    // Get a Store using the "scheme" part of the URL string
    Store s = session.getStore(URLName);
    // Or, directly
    // First gets a Store which uses the rest of URLName
    // to locate and instantiate Folder
    Folder f = session.getFolder(URLName);
  • Proper ways to expunge a folder:
    1. Expunge the folder, close it. Reopen and refetch messages from that Folder.
    2. Issue the "close" method with the "expunge" parameter set to "true".
  • You can search a folder (and, recursively, the entire store database) for the messages you are looking for. The abstract SearchTerm class represents search terms. It has a single method: public boolean match(Message msg); There are concrete subclasses of this class to search on subject, from, to etc. and to specify AND and OR criteria.

    The Folder class supports searches on messages:

    public Message[] search(SearchTerm term)
    public Message[] search(SearchTerm term, Message[] msgs)
  • The content of a message is a collection of bytes. There is no built-in knowledge in JavaMail of the data type or format of the message content. Instead, the "Message" class object interacts with its own content through an intermediate layer - the JavaBeans Activation Framework (JAF). So, JavaMail uses JAF to handle access to data based on data-type. The out-of-the-box JAF provides two very simple JAF-aware viewer beans: Text Viewer and Image Viewer. These beans handle data where content-type has been set to text/plain or image/gif. JavaMail implementation providers (not you) need to write additional viewers that support some of the basic content types seen on the Internet such as text/html, multipart/mixed and message/rfc822.

No comments:

Post a Comment