Kicker for incoming POP3 mail

http://www.projectzero.org/bugzilla/show_bug.cgi?id=5448

New modules

  • zero.mail - contains a JavaMail implementation and some zero.mail.* utility classes.
  • zero.mail.kicker - contains a kicker to poll a mail store and POST to the receiver when a message arrives (depends on zero.mail).
  • zero.mail.receiver - contains a receiver to retrieve a message from a mail store and fire an emailMessage event (depends on zero.mail).

Mail store configuration

Mail stores are be represented as named artifacts in zero.config, under the key /config/mail/stores/*. A store configuration is similar to ZRM configuration under /config/db/* identifies the full connection properties for the mail store, including the required user ID and password.

/config/mail/stores/myInbox = {
    "hostname" : "pop3.myhost.com",
    "port" : 110,
    "userid" : "user1",
    "password" : "pass1",
    "sessionProperties" : {
        // optional properties
    }
}

Notes:

  1. We are using a named artifact to represent a mail store so a kicker and receiver can share a common name for it, and the kicker does not have to transmit full details (including the password) to the receiver.
  2. sessionProperties allows the optional specification of arbitrary properties to be passed into Javamail when creating the session.
  3. Both the password and sessionProperties values can be XOR encoded.
  4. The store config includes a set of user credentials, like /config/db/* but unlike /config/connection/messaging/*. This makes it suitable for kicker/receiver but unsuitable for a potential "pop3" protocol for the Connection API, which would probably want the user credentials to be part of the connection request. If we have a "pop3" protocol in the future, I think it would be appropriate to place all the properties in the request, leaving /config/mail/stores/* for the kicker/receiver.
  5. POTENTIAL ENHANCEMENT: If we want to support other Javamail stores, such as IMAP, we could add an additional property to the /config/mail/stores/* map:
    • prototocol (defaulting to "pop3")
  6. POTENTIAL ENHANCEMENT: If we intend to support direct use of JavaMail APIs by applications in the future, a utility API could be included to create a JavaMail store session based on a named store defined by /config/mail/stores/*.

Kicker configuration

An application using zero.mail.kicker would be configured as follows, where mailStore names a store defined by /config/mail/stores/*:

/config/timer/tasks/myMailKicker = { "delay" : 2 }
/config/handlers += [{
    "events" : "timer",
    "handler" : "zero.mail.kicker.MailKicker.class",
    "conditions" : "/event/_taskName =~ myMailKicker",
    "instanceData": {
        "mailStore" : "myInbox",
        "receiverURL" : "http://localhost:8081/zero/receiver/mail",
        "config" : {
            # HTTP or HTTPS protocol configuration can be placed here
        }
    }
}]

When the polled mail store contains one or more unread messages, the kicker POSTs the named receiver URL, including the name of the mail store configuration.

POTENTIAL ENHANCEMENT: If we want to support other Javamail stores, such as IMAP, we could add an additional property to the instanceData map:

  • folder (defaulting to "INBOX")

Receiver configuration and behaviour

An application using zero.mail.receiver would require a mail store configuration under, /config/mail/stores/*, matching that used by associated kicker.

The receiver application requires one or more POST handler configurations similar to:

/config/handlers += [{
    "events" : "POST",
    "handler" : "zero.mail.receiver.MailReceiver.class",
    "conditions" : "/request/path =~ /zero/receiver/mail(/.*)?"
}]

The mail receiver will behave in a similar manner to zero.messaging.receiver, as follows:

  1. Check receiver not already running for named kicker (to avoid replay after HTTP time out).
  2. Open session to mail store named in kick message.
  3. If no messages, then close store with success code.
  4. If one or more messages then:
    • Read message from remote store
    • Populate /request zone with details of message
    • Fire mailMessage event
    • Delete message on remote store and close session to purge
    • Return success code (unless something went very wrong along the way)

The mailMessage event will include the following to enable handler selection:

  • /event/kickerName - the name of the kicker
  • /event/appName - the name of the application hosting the kicker
  • /event/mailStore - the name of the mail store from which the message was read
  • /event/folder - the name of the folder from which the message was read

The message will be placed in the /request zone as follows:

  • /request/mail/headers/ headerName - headers unpacked from the message, each in FirstElementList
  • /request/mail/body - a List<Map<String, Object>> containing a flattened list of all body parts, including any alternates. Each body part is represented as a map containing the following properties:
    • contentType - content type extracted from properties
    • headers - raw header properties associated with the individual body part, in Map<String, FirstElementList< String >>
    • inputStream - the body contents, as InputStream
  • /request/mail/attachments - a List<Map<String, Object>> containing a flattened list of all attachments in mail message, regardless of where they appeared in the structure of the multipart-message, in particular both inline content and attachments. Each attachment represented as a map containing the following properties:
    • name - derived from properties, e.g. file name
    • contentType - content type extracted from properties
    • headers - raw header properties associated with the attachment, in Map<String, FirstElementList< String >>
    • inputStream - the attachment contents, as InputStream

Note that each part of a multi-part message will be placed in either /request/mail/body or /request/mail/attachments, in the order they are discovered when walking the message.

Flow activities and support

The zero.mail.receiver component will contain the following artifacts for use with the flow engine:

  • A supplied mailMessage event handler that can be used to trigger a flow on receipt of an email.
  • A receiveMail activity which can be used to accept the contents of an incoming email into a flow triggered by the mailMessage event.

TODO Attachements and alternative bodies?

Key limitations of function planned for Silverstone

  • No zero.* API to poll/delete messages in mail store (no "pop3" protocol for the Connection API).
  • No explicit SSL support for POP3 connections that can be configured using zero.config (have to resort to JVM SSL configuration).

r11 - 15 Aug 2008 - 19:23:22 - rushall
Syndicate this site RSS ATOM
Copyright 2007 © IBM Corporation | Privacy | Terms of Use | About this site