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:
- 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.
- sessionProperties allows the optional specification of arbitrary properties to be passed into Javamail when creating the session.
- Both the password and sessionProperties values can be XOR encoded.
- 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.
- 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")
- 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:
- Check receiver not already running for named kicker (to avoid replay after HTTP time out).
- Open session to mail store named in kick message.
- If no messages, then close store with success code.
- 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).