Programmer's Guide



Chapter 27   Using Mail Business Objects

This chapter introduces the SilverStream classes that support receiving and sending e-mail messages. It describes the following:

SilverStream e-mail support   Top of page

SilverStream lets you specify, at design time, that a business object is triggered when the application server is notified of the receipt of Post Office Protocol 3 (POP3) mail for a particular mailbox address. When the application server receives a mail message it passes an event object to the triggered business object. The event object provides the complete e-mail message (including headers) as well as the methods required to read and respond to its contents.

The AgoMailSend class provides a mechanism for composing e-mail that complies with Simple Mail Transfer Protocol (SMTP) and Multipurpose Internet Mail Extensions (MIME), which can be sent from any SilverStream business object or page.

The following diagram shows how the SilverStream Application Server sends and receives standard Internet e-mail from the native subsystem.

About sending and receiving mail    Top of page

To send e-mail, you call the AgoMailSend object's submitMail() method, passing in the name of an SMTP mail server to use to send the message.

Receiving e-mail involves the following steps:

  1. You must configure the SilverStream Server to check the POP3 server for e-mail.

  2. Once configured, the server gets e-mail messages for specific mailboxes from one or more POP3 servers.

  3. The server passes the e-mail messages to any business objects that are set up to process mail for that mailbox.

  4. If there are no business objects defined to process the mail, the server deletes it.

    If you have multiple business objects set up to process mail for a single mailbox, the server passes a unique instance to each business object.

Mail processing on the server is described in detail under Working with received messages.

About the SMTP and MIME standards   Top of page

SMTP-compliant e-mail messages are composed following the standards outlined in the Internet Request for Comment (RFC) document 822. They can also include extensions to RFC 822 to support MIME standards documented in RFC2045 through RFC2049 (inclusive).

RFC822 supplies a simple standard for the basic structure of an e-mail message that includes a standard header format followed by a message body comprising US-ASCII text. The MIME extensions allow Internet e-mail to support an extensible set of formats, including:

MIME messages can include applications, audio, image, text, and video. SilverStream's e-mail objects let you receive and construct any simple or complex SMTP/MIME compliant e-mail. All Internet mail servers and most other mail servers (including Exchange, Notes, and cc:Mail) are SMTP/MIME-compliant.

About MIME   Top of page

Originally, Internet mail consisted of only US-ASCII text. However, as information management became more varied and complex, Internet mail needed to handle more sophisticated formats, including text in different languages, rich text (such as fonts, bold, and italics), images, and sound clips. MIME became the standard to support sending and receiving e-mail with richer content. MIME is simply an encoding scheme that lets you:

About MIME Content-Type

In the MIME standard, you label the content of a message by specifying a Content-Type. The Content-Type contains both a type and a subtype. The MIME standard specifies the following types: text, video, audio, application, multipart, image, and message. Each of these types has a set of subtypes, for example, text/plain, text/html, or image/gif, or multipart/mixed.

An e-mail message can contain multiple parts, each of which has a different Content-Type (for example, some text, an image, some more text, another image, and a caption for the image). The ones that contain multiple parts (of different types) are Content-Type multipart/mixed. Each individual part of a message can also be a multipart message. For example, you might want to put the picture with its caption in one part. So you might have a structure that is:

A single e-mail can be more complex than this. For this reason, a MIME message is a tree structure of parts. The SilverStream Mail API provides several classes to handle the tree structure, allowing you to access the MIME parts of each e-mail message.

    For more information, see the SilverStream API help page for AgoMIME.

About POP3   Top of page

SMTP and MIME define the format of mail and the way it is sent over the Internet. Mail is delivered to a mail server. It is more convenient to have mail automatically sent to the server, then let users retrieve it, much like an actual post office box. The standard for communicating with this server to get your mail is POP3.

How the mail system works   Top of page

The SilverStream Application Server is configured to check for e-mail for particular mailboxes at specific intervals. When the interval is reached, the server checks for mail. If it receives e-mail for a particular mail box, it checks the list of registered listeners (objects that implement AgiMailListener) for that mailbox.

If objects are registered, the server creates and passes an AgoMailEvent object to those registered listeners. The listeners respond to the event in whatever way they have been programmed. SilverStream does not guarantee the order in which the registered listeners are notified of the event.

Mail system components   Top of page

The following table describes the function of each component in the mail system.

Component

Description

SilverStream Server

Acts as a POP3 client.

You must configure the server before you can create or save any mail-triggered business objects using the Mail Pane of the SilverStream Management Console (SMC).

See the chapter on Maintaining the Server in the Administrator's Guide for information on configuring the server for mail accounts.

Mail object

A class created by the SilverStream Business Object Designer.

The class is composed of Java code that you write in the Programming Editor for the business object that you created with the Business Object Designer. It implements the AgiMailListener interface.

The Business Object can call methods and respond to e-mail events.

AgoMailEvent

The event object that is passed by the server to the registered listener. It contains the AgoMailMessage object and a set of methods that let you obtain the mail message while also providing access to other parts of the server.

AgoMailMessage

The object that represents the actual mail message. It is passed to the business object via the AgoMailEvent object. You can access it using the AgoMailEvent's evt.getMessage() method.

It provides methods that let you access the component parts of an e-mail message.

For example, you can create a mail object to read e-mail messages that contain images and then store the images in a database.

The following diagram illustrates how these components work together to process e-mail.

Mail system data flow   Top of page

The following describes what happens if the SilverStream Server is configured to check for mail every 10 minutes. (This is time is configurable using the SilverStream Management Console.)

  1. Every 10 minutes, the server instantiates any mail objects (that you specified as event-lifetime objects in the Designer) and fires the beforeMailReceived event for those objects (both server-lifetime and event-lifetime).

  2. The Server checks for e-mail. If there is mail:

  3. The Server fires the afterMailReceived event for each object.

Mail events

The events (before, after, and mailReceived) are methods on the AgiMailListener interface. They are invoked by the application server when it is appropriate to do so. The following table describes the events.

Event

When it fires

beforeMailReceived

Just before the server checks with a POP3 server for e-mail.

mailReceived

Each time it processes an e-mail message.

Within the mailReceived event, you will probably call the getMessage() method that returns the message.

afterMailReceived

Just after the server checks with a POP3 server for e-mail.

The SilverStream Server passes the messages to the object synchronously, in the order in which they are received from the POP3 server. For example, if the server receives three messages, it passes three AgoMailEvent objects to the business object, which fires the mailReceived event three times (once for each message).

The beforeMailReceived event and the afterMailReceived event will each fire only once, regardless of the number of messages processed.

Creating a mail-triggered business object   Top of page

A mail-triggered business object is a type of SilverStream business object that implements the AgiMailListener interface. Objects that implement this interface are registered with the application server to listen for mail events. To be a registered listener means that the object requests that it be notified when the server receives mail for a specific mailbox.

Mail triggers should not be viewed as e-mail clients. The Mail Listener objects are intended to automate simple tasks, such as updating an e-mail alias list or forwarding e-mail to a particular party.

Creating a mail business object   Top of page

Follow these steps to create a mail object.

  1. Choose the mailbox that you want the mail object to respond to and configure the SilverStream Server to get mail for that address.

  2. Use the Business Object Designer Wizard to create a business object with a mail trigger.

When you create a mail-triggered business object using the SilverStream Business Object Designer, SilverStream adds the implements AgiMailListener clause to the object's class definition and registers the object as a mail listener. It also stores metadata on the server that identifies the mailbox with which the object is associated.

A single instance of the business object can respond to multiple e-mail messages that are addressed to a single e-mail address. You can use the business object to create applications that read incoming e-mail messages, looking for items such as "unsubscribe" in the subject or body of the message.

NOTE   The message is consumed by the business object and cannot be retrieved from the POP3 server by someone else once the business object processes it.

SilverStream provides a Mail API that includes high-level methods to obtain the commonly used parts of an e-mail message, as well as support for low-level access to specific MIME parts.

    See AgoMIME in the SilverStream API help for more information about the available classes.

Importing a mail triggered object created externally   Top of page

In an external editor you can create a Java class that implements AgiMailListener, then import the source or class file using the SilverCmd ImportSource and ImportClass commands. The import command must include an input file containing mail listener attributes.

    For information see SilverCmd Reference in the online Tools Guide.

Working with received messages   Top of page

Before creating the mail object, you must determine what type of mail you expect the object to receive and how you want to process that mail. This involves addressing the following questions:

When you have addressed these issues, you can get the message from the AgoMailEvent object and parse the message using the AgoMailMessage class methods. The AgoMailMessage object provides access to every part of an e-mail message. You can get at the headers and body easily, and, if the message contains MIME parts, you can handle them as well.

Obtaining the message from the AgoMailEvent object   Top of page

The application server passes the received message to the business object through the AgoMailEvent object. You obtain the message using the event object's getMessage() method in the mailReceived event:

  AgoMailMessage msg = evt.getMessage(); 

If you try to obtain the message in any event other than mailReceived, the getMessage() method returns null.

Methods for accessing header information

This table describes the AgoMailMessage methods available for reading the header information from any message (text or MIME part).

    For more information see the SilverStream API help page for AgoMailMessage.

Header field

AgoMailMessage method to access

From address (single)

fieldFrom()

From address (enumeration)

fieldFromElements()

Sender's address

fieldSender()

Address(es) message was sent to

fieldToElements()

Carbon copy addresses

fieldCcElements()

Blind carbon copy addresses

fieldBccElements()

Reply To address

fieldReplyToElements()

Message subject

fieldSubject()

Message date

fieldDate()

Organization of the sender
(for example, SilverStream)

fieldOrganization()

Message ID

fieldMessageID()

File attachments

fileAttachments()

Accessing the message body   Top of page

You can access the message body using the AgoMailMessage.messageText() method. This is an example of how you might use AgoMailMessage methods to obtain the parts of a message in the AgoMailEvent.

  public void mailReceived(AgoMailEvent evt) 
{
 AgoMailMessage message;
 AgoMailAddressMailbox from;
 AgoMailAddressMailbox sender;
 String subject;
 String date;
 String messageText;
 String organization;
 String messageID;
 Enumeration to;
 Enumeration cc;
 Enumeration bcc;
 Enumeration replyTo;
 Enumeration files;

 // Get the message
 message=evt.getMessage();
 messageCount++;

  try
  {
   // Extract fields from the message
   from=message.fieldFrom();
   sender=message.fieldSender();
   subject=message.fieldSubject();
   date=message.fieldDate();
   messageText=message.messageText();
   organization=message.fieldOrganization();
   messageID=message.fieldMessageID();
   to=message.fieldToElements();
   cc=message.fieldCcElements();
   bcc=message.fieldBccElements();
   replyTo=message.fieldReplyToElements();
   files=message.fileAttachments();

   //Do something with these fields...
  }
  catch
  {
   // if exception occurs, do some processing...
  }
return;
}

The following notes explain the code.

NOTE   If the message also contains MIME parts, you can use getMIMEPart() method to access them.

Accessing file attachments

If you are receiving mail that contains file attachments, you have two options for accessing and manipulating the file attachment portion of the message:

The following example illustrates how to retrieve the file attachment using the fileAttachments() method. In the example, the server receives e-mail, passes the event object to a business object which parses the message, extracts file attachments, in this case resumes, and puts these resumes in a database table.

The example uses a database table that has this structure.

If you want to try this example, be sure to add this table using the Add Dataset button in the Business Object Designer.

Note that this example assumes that each mail message will only contain a single file attachment.

  public void mailReceived(AgoMailEvent evt) 
{
 AgaData resumeData;
 AgoMailAddressMailbox from;
 AgoMailMessage message;
 String subject;
 String filename="";
 String date;
 Enumeration files;
 AgoFileAttachmentInputStream attachment=null;
 ByteArrayOutputStream resumeContentStream=new
   ByteArrayOutputStream();
 byte[] resumeContent=null;
 String messageText;

 // Get the message and increment the count
 message=evt.getMessage();
 messageCount++;
 // Get the agaData for the attachment log
 resumeData=evt.getAgaData("resumeData");
 try
 {
  // Get the components that we need from the message
  from=message.fieldFrom();
  subject=message.fieldSubject();
  date=message.fieldDate();
  messageText=message.messageText();
  files=message.fileAttachments();

  // For each attachment we find, store it in the database
  while (files.hasMoreElements())
  {
   // Get the attachment
   attachment=(AgoFileAttachmentInputStream) files.nextElement();
   filename=attachment.filename();
   // In order to store the attachment in the database, we need to
   // get its contents into a byte array. To do this, use the
   // AgoStreamer.streamFromTo method to copy the contents of the
   // attachment to a ByteArrayOutputStream, and then use the
   // toByteArray method on that output stream to get the byte
   // array.
   AgoStreamer.streamFromTo(attachment, resumeContentStream);
   resumeContent=resumeContentStream.toByteArray();
   // Insert into the table
   resumeData.gotoLast();
   resumeData.insertAfter();
   resumeData.setProperty("senderName", from.toString());
   resumeData.setProperty("subject", subject);
   resumeData.setProperty("attachmentName", filename);
   resumeData.setProperty("dateReceived", date);
   resumeData.setProperty("messageText", messageText);
   resumeData.setProperty("attachment", resumeContent);
   resumeData.updateRows();
  }
 }
 catch (Exception e)
 {
  // If we get an exception print it and it's stack
  // trace on the server console
  System.out.println("***** Got exception: *****");
  System.out.println(e.toString());
  e.printStackTrace();
 }
return;
}

File attachments (regardless of their MIME-Type) should be put into byte arrays before being inserted into a database table. If the file attachment contains binary data (for example, video), it will not be corrupted. By converting to a byte[], the data will be stored as a BLOB in the database.

Working with MIME part messages

The SilverStream AgoMIMEPart is an abstract class whose subclasses can handle each part of a MIME message, based on that part's MIME-Type. SilverStream, by default, retrieves messages as AgoMIMEPart objects. This means that if you only want to access the text part of a message, then the AgoMailMessage methods described previously provide the appropriate amount of functionality. However, if you want to work with the actual MIME parts of a message, then you need to know more about the AgoMIMEPart object. The following diagram illustrates the AgoMIMEPart hierarchy.

Each AgoMIMEPart subclass makes available the appropriate methods to work with that type. Refer to the appropriate class in the SilverStream API section of online help.

Example of coding the mailReceived event

The following example shows a Mail Listener that parses a mail message with an image and puts the image in a database table. You need to import the java.io.* package in the General Declarations section for this code sample.

The example shows the code for the mailReceived event.

  public void mailReceived(AgoMailEvent evt) 
{
 AgaData imageData;
 AgoMailAddressMailbox from;
 AgoMailMessage message;
 String subject;
 String date;
 String messageText;
 AgoMIMEPart mimePart;
 Enumeration parts;
 AgoMIMEPart subPart;
 AgoByteStore byteStore;
 byte[] imageContents;
 InputStream inputStream;
 ByteArrayOutputStream imageContentStream;
 String mimeType;
 String mimeSubType;

 // Get the agaData
 imageData=evt.getAgaData("imageData");

 // Get the message
 message=evt.getMessage();

 try
 {
  // Get the components that we need
  from=message.fieldFrom();
  subject=message.fieldSubject();
  date=message.fieldDate();
  messageText=message.messageText();
  mimePart=message.getMIMEPart();
  // Enumerate over mime parts...
  parts=((AgoMIMEPartMultipart) mimePart).parts();
  while (parts.hasMoreElements())
  {
   subPart=(AgoMIMEPart) parts.nextElement();
   if (subPart instanceof AgoMIMEPartImage)
   {
    // Get the mime type and subtype
    mimeType=subPart.type();
    mimeSubType=subPart.subtype();
    
    // Get the image, and put in a byte[]
    byteStore=((AgoMIMEPartByteStream) subPart).getValue();
    inputStream=byteStore.getInputStream();
    imageContentStream=new ByteArrayOutputStream();
    AgoStreamer.streamFromTo(inputStream, imageContentStream);
    imageContents=imageContentStream.toByteArray();
    
    // Insert the image into a table
    imageData.gotoLast();
    imageData.insertAfter();
    imageData.setProperty("senderName", from.toString());
    imageData.setProperty("subject", subject);
    imageData.setProperty("dateReceived", date);
    imageData.setProperty("messageText", messageText);
    imageData.setProperty("mimeType", mimeType);
    imageData.setProperty("mimeSubType", mimeSubType);
    imageData.setProperty("contents", imageContents);
    imageData.updateRows();
   }
   else
   {
    system.out.prinln("Didn't get an image");
    system.out.prinln("Type: " + subPart.type() + " SubType: " +
       subPart.subtype());
   }
  }
 }
 catch (Exception e)
 {
  // If exception occurs, do some processing ...
 }
return;
}

These notes explain the code.

Notes about mail listeners   Top of page

Sending e-mail   Top of page

The AgoMailSend class is a SilverStream class that lets you compose SMTP/MIME-compliant e-mail messages. You can then send the e-mail from any SilverStream business object to any Internet mail server (and most other mail servers including Exchange, Notes, and cc: Mail). For example, the AgoMailSend class lets you create applications that:

About the SilverStream AgoMailSend    Top of page

Once you have composed a message, you can send it from a form using an Invoked triggered business object. As the following diagram illustrates, the AgoMailSend object is used to compose the message and to send it.

This table describes the function of the SilverStream components that allow you to send e-mail.

Component

Service provided

AgoMailSend

Allows you to compose the e-mail message.

It provides high-level methods that let you compose a simple ASCII-text message and its accompanying header information. It also provides methods that let you compose a MIME-part message.

SilverStream Server

Submits the mail message to the mail delivery subsystem. (Does not require any special configuration.)

Invoked business object

Allows you to send e-mail.

The AgoMailSend object's submitMessage() method submits the message to the specified SMTP server. Messages are passed to the SMTP server synchronously. If the SMTP server cannot be reached, the invoked business object throws an AgoMailSendException.

Composing an e-mail message   Top of page

Before you create the AgoMailSend object, determine what type of mail you want to send:

When you determine the message type you can compose your message using the appropriate AgoMailSend methods. The AgoMailSend API allows you to compose a simple, text-based e-mail message including file attachments, or a complex message of MIME parts.

For more information, see the SilverStream API help page for AgoMailSend.

Constructing a header

This table lists the AgoMailSend methods that are available to construct the message header.

NOTE   The only required methods are those that set the "To:" and "From:" values.

Constructing a message that contains MIME parts

The following table highlights some of the AgoMailSend methods that you might use to send an e-mail message that includes MIME parts.

Message part

Use this method to add it

An HTML text part from a reader

addHTMLTextPart()

An HTML text part from a string buffer

addHTMLTextPart()

An HTML text part from a file

addHTMLTextPartFromFile()

A plain text part from a reader

addPlainTextPart()

A plain text part from a string buffer

addPlainTextPart()

A plain text part from a file

addPlainTextpartFromFile()

Constructing a message that contains MIME parts   Top of page

The following example illustrates how to construct and send e-mail with an HTML part that contains HTML text.

  AgoMailSend message; 
String toName, toAddress;
String senderName, senderAddress;
String subject;
String organization;
String fileName;
fileName="c:\\TestMailFiles\\MailAttachTest.htm";
AgoMailSend message=new AgoMailSend();
senderName="Your Name";
senderAddress="Sender-name@yourcompany.com";
organization="Sender Company Name";
toAddress="recipient-name@companyname.com";
toName="recipient";
organization="Company Name";
subject="Mail with HTML Attachment";

try
{
 message.setFrom(senderName, senderAddress);
 message.setSubject(subject);
 message.addToAddress(toName, toAddress);
 message.setOrganization(organization);
 message.addPlainTextPart("This is a test message");
 message.addHTMLTextPartFromFile(fileName);
 message.submitMessage("mail");
 statusField.setText("--> Sent to " + toAddress + " " + subject);
}
catch (Exception e)
{
 // If exception occurs, do some processing ...
}

These notes explain the code:

About the SMTP and MIME standards   Top of page

SMTP-compliant e-mail messages are composed following the standards outlined in the Internet Request for Comment (RFC) document 822. They can also include extensions to RFC 822 to support MIME standards documented in RFC2045 through RFC2049 (inclusive).

RFC822 supplies a simple standard for the basic structure of an e-mail message that includes a standard header format followed by a message body comprising US-ASCII text. The MIME extensions allow Internet e-mail to support an extensible set of formats, including:

MIME messages can include applications, audio, image, text, and video. SilverStream's e-mail objects let you receive and construct any simple or complex SMTP/MIME compliant e-mail. All Internet mail servers and most other mail servers (including Exchange, Notes, and cc:Mail) are SMTP/MIME-compliant.

About MIME   Top of page

Originally, Internet mail consisted of only US-ASCII text. However, as information management became more varied and complex, Internet mail needed to handle more sophisticated formats, including text in different languages, rich text (such as fonts, bold, and italics), images, and sound clips. MIME became the standard to support sending and receiving e-mail with richer content. MIME is simply an encoding scheme that lets you:

About MIME Content-Type

In the MIME standard, you label the content of a message by specifying a Content-Type. The Content-Type contains both a type and a subtype. The MIME standard specifies the following types: text, video, audio, application, multipart, image, and message. Each of these types has a set of subtypes, for example, text/plain, text/html, or image/gif, or multipart/mixed.






Copyright © 2000, SilverStream Software, Inc. All rights reserved.