Scala, IMAP, SearchTerm, AndTerm, FromStringTerm, SentDateTerm, FlagTerm, and FetchProfile

If you're looking for a simple Scala IMAP client tutorial/example, please follow that link, but if you're interested in some Scala source code that demonstrates IMAP searching with Scala, JavaMail, SearchTerm, AndTerm, FromStringTerm, SentDateTerm, FlagTerm, and FetchProfile, this source code may be for you.

In short, here's what the following Scala IMAP client does:

  • Connects to the Yahoo IMAP email server. (Use imap.gmail.com for Gmail.)
  • Combines the SearchTerm, AndTerm, FromStringTerm, SentDateTerm, and FlagTerm values as shown to search for only the desired emails.
  • Uses FetchProfile to limit the actual data that is pulled back from the IMAP server. Since I only need the fields shown, I only pull those back from the server. This should be faster and save bandwidth, as compared to pulling every email message back completely.

Without any more introduction, here's the source code for this Scala email client example:

package imaptests

import javax.mail._
import javax.mail.internet._
import javax.mail.search._
import java.util.Properties

/**
 * Shows terms at bottom of page:
 *   http://java.sun.com/developer/onlineTraining/JavaMail/contents.html#JavaMailFetching
 * SentDateTerm and operators:
 *   http://geronimo.apache.org/maven/specs/geronimo-javamail_1.4_spec/1.6/apidocs/javax/mail/search/SentDateTerm.html
 */
object ScalaImapSslReader2 {

  // a search term for all "unseen" messages
  def getUnseenTerm: FlagTerm = {
    return new FlagTerm(new Flags(Flags.Flag.SEEN), false);
  }
  
  def getRecentTerm: FlagTerm = {
    return new FlagTerm(new Flags(Flags.Flag.RECENT), true);
  }
  
  def connectToStore(store: Store, imapUrl: String, username: String, password: String) {
    store.connect(imapUrl, username, password)
  }
  
  def getFolder(store: Store, folderName: String): Folder = {
    return store.getFolder(folderName)
  }
  
  def main(args: Array[String]) {
    val props = System.getProperties()
    props.setProperty("mail.store.protocol", "imaps")
    val session = Session.getDefaultInstance(props, null)

    // declare these before the 'try' so i can close them in the finally clause
    var store: Store = null
    var inbox: Folder = null
    try {
      store = session.getStore("imaps")
      connectToStore(store, "imap.gmail.com", "al@gmail.com", "PASSWORD")
      inbox = getFolder(store, "INBOX")
      inbox.open(Folder.READ_ONLY)

      val unseenFlagTerm = getUnseenTerm
      val recentFlagTerm = getRecentTerm
      val unseenAndRecentTerm = new AndTerm(unseenFlagTerm, recentFlagTerm);

      val fromTerm = new FromStringTerm("joe@example.com")
      val sentDateTerm = new SentDateTerm(ComparisonTerm.EQ, new java.util.Date)

      val newFromAndDateTerm = new AndTerm(fromTerm, sentDateTerm)
      val newFromAndDateAndUnseenTerm = new AndTerm(newFromAndDateTerm, unseenFlagTerm)

      // do the search
      val messages = inbox.search(newFromAndDateAndUnseenTerm)
      if (messages.length == 0) println("No messages found.")
      // note: you can stop the script here if there are no messages

      // get only the message info we need
      // @see http://www.zdnetasia.com/receiving-in-javamail-39304762.htm
      // @see http://javamail.kenai.com/nonav/javadocs/javax/mail/FetchProfile.html
      val fp = new FetchProfile
      fp add "Subject"
      fp.add("From")
      fp.add("SentDate")
      //fp.add("Content")
      inbox.fetch(messages, fp)
      
      // note: you might want to limit the number of messages printed here, in case
      // you end up with a large list of email messages
      for (message <- messages) {
        println(message.getSubject())
      }
    } catch {
      case e: NoSuchProviderException =>  e.printStackTrace()
                                          System.exit(1)
      case me: MessagingException =>      me.printStackTrace()
                                          System.exit(2)
    } finally {
      inbox.close(true)
      store.close
    }
  }  
}

One thing I need to note is that this code works with the Java JavaMail API. If you're using the J2SE, you'll need to download the JavaMail API jar files for this code to work.

I could also clean this code up a little more, but if you're new to Scala and the JavaMail API, I think it may be easier to read the code as is, so I've left it this way.