Skip Headers
Oracle® Mail Application Developer's Guide
10g Release 1 (10.1.1)

Part Number B15789-01
Go to Documentation Home
Home
Go to Book List
Book List
Go to Table of Contents
Contents
Go to Index
Index
Go to Master Index
Master Index
Go to Feedback page
Contact Us

Go to previous page
Previous
Go to next page
Next
View PDF

2 Oracle Mail Java API

This chapter describes the Oracle Mail Java APIs that can be used to create customized clients, integrate applications, and support certain extensions.

Introduction to the Oracle JavaMail API

The Oracle Javamail API (OJMA) Service Provider implements the abstract JavaMail 1.2 API (JMA) provided by Sun Microsystems, Inc., and is designed to integrate directly with the mail store in the Oracle database. This approach does not depend upon a standards-based protocol server and calls PL/SQL APIs in the mail store over JDBC.

JMA provides a set of abstract classes that model a mail system. The API provides a platform independent and protocol independent framework to build Java technology-based mail and messaging applications. The JMA implementations typically go over a standards-based protocol such as IMAP or POP3. The JMA is implemented as a Java platform optional package and is also available as part of the Java 2 platform, Enterprise Edition. More details are available at the following URL:

http://java.sun.com/products/javamail

Within JMA, a user connects to a message store. The store contains a list of folders, and a user can perform folder and message operations based on the IMAP Protocol (RFC 2060).

In addition to the standard functionality available with JMA operating over an IMAP protocol service provider, the Oracle Javamail API Service Provider supports several extensions to the IMAP protocol and JMA. These enhancements do not interfere with the basic JMA interface, and clients using basic JMA can seamlessly integrate with the Oracle Javamail API Service Provider.

Oracle Javamail API Service Provider supports the following enhancements:

Also, because the Oracle Javamail API Service provider works directly with the Oracle database, system requirements are reduced since there is no overhead involved in conversing with a standards-based server, such as IMAP or POP3, and tasks such as sorting, lookups, and message sharing are efficiently handled by the Oracle database.

Directory Management API

The directory management API is a set of Java classes that can be used to create, access, and manage various entries, such as mail users, public distribution lists, and private address book entries (contact information and private distribution lists). The entries are stored in Oracle Internet Directory for a given domain.

Directory Components

In Oracle Email, an e-mail system can contain more than one domain. Mail users and public distribution lists exist for a particular domain. A mail user for a given domain is a valid user in that domain who can send and receive e-mail and use all of the exposed e-mail server functionality.

A public distribution list is a mailing list that has its own e-mail ID and contains a group of e-mail IDs or other mailing lists. When an e-mail is sent to a public distribution list, all the members of the list receive the e-mail. A valid mail user can subscribe to any public distribution list.

Private address book entries consist of private contacts and private mailing lists belonging to a particular mail user.

A private distribution list consists of private contact information, such as the contact's phone number, e-mail ID, and address. Users can use the private address book entries from WebMail to send and receive e-mails. These entries are also used by the Calendar application.

Authentication

Before a caller can access any of the directory components, they must be authenticated with the Oracle Internet Directory using the oracle.mail.OESContext class. Once authenticated, the oracle.mail.OESContext instance representing a trusted session must be passed to all of the directory APIs.

The following example shows how to authenticate an application with the debug option turned off:

OESContext oesctx = new OESContext(DirectoryConstants.DS_CALLERTYPE_APP, false);

// Authenticate to the directory
oesctx.authenticate(null, args[0]);

Retrieving the Metadata and Validation

Before an entry is created in the directory, the caller needs to retrieve the metadata for that particular entry from the directory. The metadata for a particular entry consists of the mandatory and optional attributes the caller must set in order to create an entry. It also contains information about all the attributes, such as the syntax, multiplicity of the attributes, and default values for attributes (if any defaults are set in the directory).

When the caller sets the attribute value on the metadata object, validation is performed to ensure that the caller sets the value of an attribute that is present in that particular entry. In UI-based applications using the metadata, the caller can perform any input validations for the data entered.

The following example shows how to retrieve the metadata. It assumes that ldapobj is an instance of the DirectoryObject class.

// Getting the mandatory attributes from the metadata
if (ldapobj.getMandatoryAttribs() != null)
{ 
 Enumeration enum = ldapobj.getMandatoryAttribs().elements(); 
 while (enum.hasMoreElements())
 {
 String attr = enum.nextElement().toString(); // Name of the attribute 
 
 // Retrieve the metadata for this attribute 
 DirectoryAttributeMetaData mdata = ldapobj.getMetaData(attr); 

 // The multiplicity of the attribute returns "SINGLE" or "MULTIPLE" 
 String mult = mdata.getMultiplicity(); 

 // Returns the syntax of the string, "String", "byte", "boolean" or "int" 
 String syntax = mdata.getAttributeType(); 

 // Returns a vector of String values if any default has been set,
 // else returns null 
 Vector defaultvals = mdata.getDefaultValues(); 
 }
} 

Similarly, the ldapobj.getOptionalAttribs() method returns the list of optional attributes and in a similar manner, the optional attributes and the metadata can be retrieved. After retrieving the metadata, the user can set the value of an attribute in the following manner. When creating an entry, the attribute value can be set using the setAttributeValue method of the DirectoryObject class.

This example sets the value for the telephonenumber attribute to the default values provided mdata.getDefaultValues() is not null.

ldapobj.setAttributeValue("telephonenumber", mdata.getDefaultValues());
 
Vector newVals = new Vector(); 
newVals.add("408 7394050"); 
newVals.add("650 7394050"); 
ldapobj.setAttributeValue("telephonenumber", newVals);

While modifying an entry, the attribute value can be set using the modifyAttributeValue method of the DirectoryObject class. The caller needs to specify the type of modification.

The permitted modifications are:

  • DirectoryConstants.DS_MODIFY_ADD: This adds the given set of values to the existing values

  • DirectoryConstants.DS_MODIFY_DELETE: This deletes the given set of values from the existing values

  • DirectoryConstants.DS_MODIFY_REPLACE: This replaces all the existing values with a new set of values

This example adds two new values for the telephonenumber attribute.

Vector newVals = new Vector(); 
newVals.add("408 7394050"); 
newVals.add("650 7394050"); 
ldapobj.modifyAttributeValue
   ("telephonenumber", newVals, DirectoryConstants.DS_MODIFY_ADD);

Rule Management API

The rule management API is a set of Java classes that can be used to create, access and manage server side rules. Rules are represented as Java objects and can be saved persistently in the Oracle Internet Directory as an attribute of a user.

Server Side Rules

A mail rule is a potential action that, when a certain event happens and a certain condition is satisfied, is taken upon an e-mail message on behalf of the owner of the rule. Rules can be created and stored persistently on the mail server.

The following is an example of a rule, expressed in English:

If an e-mail message arrives in my inbox and its subject contains the phrase "Get paid to surf" then delete the message.

In this example:

  • The event is the arrival of an e-mail message in the inbox

  • The condition is the presence of the phrase in the subject

  • The action is the deletion of the message

Each event represents a change of state of a particular message during its lifecycle in the mail server. In the above example, the event changes the state of the message from To be delivered to Delivered.

Conditions are similar to Boolean expressions, in which relational and logical operations test message attributes. In the example, the subject is the mail attribute to be tested, and the conditional expression is a relational operation that tests whether the attribute contains "Get paid to surf".

Optionally, multiple conditions can be combined using logical operators such as And and Or to form compound conditions. Additionally, a condition can be an external function call that returns a Boolean value.

Actions are operations that can act upon a message, such as the deletion of the message. In addition, an action can be any external procedure that is callable in PL/SQL from within the mail server.

Rule Components

Rules are owned by either individual users or a group of users collectively. The top-level entity owning the rules can therefore be either a mail user, a domain, or an entire e-mail system, which can contain more than one domain. The top-level entities are referred to as accounts.

For every account, one can have rules defined under a set of events, such as when new mail is delivered or when the message is read. Each event is associated with a rule list, and an account can have several rule lists, with at most one per event. For any event, a rule list can contain a list of rules that are executed sequentially when the event occurs.

A rule is defined by a condition and a list of actions. A rule with no condition is said to be unconditional, therefore the actions are always carried out.

Conditions can be simple and complex. For example, a condition that compares an attribute with a literal value using the relational operator "contains" is a simple condition. A complex condition can combine several sub-conditions. A condition can be also be a user-defined procedure, referred to as an external condition. There is also a special kind of condition, called an InSection condition, which performs a content-based search on a message.

When a rule's conditions are met, actions are taken. Actions are defined by the rule's commands, such as "move message to a folder" or "forward message to a recipient," and associated parameters, such as the name of the folder to which the message is moved or the address of the recipient to whom the message is forwarded. Once all the rules for a user are constructed in Java objects, the RuleParser object can be used to save it.

Rule Authentication

Before a caller can access a user's rules, it must be authorized. The caller must authenticate with Oracle Internet Directory using either the oracle.mail.OESContext class or oracle.mail.OESUser class. The OESContext class should be used when the caller needs to manage system-wide or domain-wide rules, as this class provides application-level authentication. The OESUser class should be used when the caller needs to manage user-level rules. Once authenticated, the OESContext object or OESUser object must be passed to the RuleParser object before calling any other RuleParser methods.

Here is an example of system- or domain-level rule authentication:

appCtx.authenticate("admin_loginname", "admin_password", "ldaphost", ldapport);
OESContext appCtx = new OESContext(ESDSConstants.DS_CALLERTYPE_APP);
RuleParser parser = new RuleParser(appCtx);

Here is an example of user-level rule authentication:

OESUser ou = OESUserFactory.getInstance().getEmailUser                 ("ldaphost", ldapport, "user_loginname", "password");
RuleParser parser = new RuleParser(ou);

Rule Validation

Before a rule is created on the server, the content of the rule is validated, preventing illegal rules from being executed at runtime. You can disable validation using the RuleParser.setValidation() method, which is useful if you want to temporarily save an incomplete rule. A non-validated rule can be saved persistently, but cannot be executed during runtime.

Rule Visibility, Activeness, and Group Affiliation

A rule has several attributes that are classified as follows:

  • Visibility

  • Activeness

  • Group Affiliation

The following example sets the attributes of a rule:

RuleType rule_t = new RuleType(); 
rule_t.setVisible("no"); 
rule_t.setActive("no"); 
rule_t.setGroup("group1");

Visibility

A rule can be visible or invisible. An invisible rule functions as a normal rule, except that it is not shown to the user. The actual implementation of hiding a rule is left to the caller. The API is able to retrieve both visible and invisible rules.

Visibility is set using the setVisible() RuleType class method.

Activeness

A rule can be active or inactive. An inactive rule exists on the server but is not executed at runtime.

Activeness is set using the setActive() RuleType class method.

Group Affiliation

A rule can belong to a group. All rules belonging to the same group can be retrieved, activated, and disabled together in one call.

Group affiliation is set using the setGroup() RuleType class method.

Message Templates

Some rules require an action to generate a new message as a reply or a notification. The reply or notification can be stored in the rule content as templates containing substitutable parameters denoted by a parameter name enclosed by two percent (%) signs.

For example, an auto-reply template can be "Your e-mail regarding %rfc822subject% sent on %rfc822date% has been received." When the rule engine generates the reply message, the %rfc822subject% and %rfc822date% variables are replaced by the actual subject and date sent information obtained from the incoming message. The set of supported parameters is the same as the set of supported message attributes.

Message template text is used as parameter values for rule actions such as Notify, Reply, Replyall, and Forward. The following example uses message templates as desscribed above:

ActionType action_t = new ActionType(); 
action_t.addCommand("notify"); 
action_t.addParameter("jdoe@acme.com"); 
action_t.addParameter("Message Alert"); 
action_t.addParameter("You have received email from %rfc822from% regarding
%rfc822subject%");

Auto-Reply Effective Duration

To prevent auto-reply messages from flooding user inboxes, there is an effective duration for a specific reply action. The duration is specified as a number of days. If an auto-reply is sent to a particular address using a particular message template, the same reply is not sent to the same user again for the period of the effective duration, starting from the time when the first reply is sent. The value is required in rule actions Reply and Replyall. The following example sets the duration to seven days:

ActionType action_t = new ActionType(); 
action_t.addCommand("reply"); 
action_t.addParameter("7"); 
action_t.addParameter("Message received"); 
action_t.addParameter("Your email regarding %rfc822subject% sent on %rfc822date% has been received.");

XML Representation of Rules

Rule data can be serialized, or converted into plain text format using XML. It can then be easily transported between applications or stored off line. In fact, the rule API internally uses XML as the format to store in the Oracle Internet Directory. To flatten rule Java objects into XML text, use the print() method from the Account class as follows:

XMLOutputStream out = new XMLOutputStream(System.out); 
account.print(out); 
out.writeNewLine(); 
out.flush();

Code Sample

The following example demonstrates a simple rule:

import oracle.xml.classgen.InvalidContentException;
import oracle.xml.parser.v2.XMLOutputStream;
import java.util.*;
import java.io.*;
import oracle.mail.*;
import oracle.mail.sdk.rule.*;
import oracle.mail.sdk.ldap.*;
 
public class Demo {
 
  public static main (String args[]) throws Exception {
 
    // authenticate as user
    System.setProperty("oracle.mail.ldap.admin_dn", "cn=orcladmin");
    System.setProperty("oracle.mail.ldap.admin_password", "adminpwd");
    OESUser ou = OESUserFactory.getInstance().getEmailUser
        ("ldap_server_host", 389, "testuser1@oracle.com", "user1_pwd");
    parser = new RuleParser(ou);
 
    // first create the top level user account type object
    AccountType acnt_t = new AccountType();
 
    // set ownerType, either system, domain or user (default)
    acnt_t.setOwnerType("user");
 
    // for system rules, this is the string "UM_SYSTEM",
    // for domain rules this is the domain
    // name, such as "oracle.com", for user rules this is the
    // fully qualified username, such as testuser1@oracle.com
    acnt_t.setQualifiedName("testuser1@oracle.com");
 
    // create a rulelist type object, set the event
    RuleListType rlist_t = new RuleListType();
    rlist_t.setEvent("deliver");
 
    // create a rule type object
    RuleType rule_t = new RuleType();
    rule_t.setDescription("a new rule");
    rule_t.setGroup("group1");
 
    // create a condition type object
    ConditionType cond_t = new ConditionType();
 
    // create a simple attribute:
    cond_t.addAttribute("rfc822subject");
    // or create an attribute object with parameters:
    //
    // AttributeType attr_t = new AttributeType("xheader");
    // attr_t.setParam("X-Priority");
    // cond_t.addAttribute(attr_t);
 
    // create a simple operator:
    cond_t.addOperator("contains");
    cond_t.addOperand("Hello");
 
    // create an external condition
    ConditionType cond_t2 = new ConditionType();
    cond_t2.addProcCall("extern_cond");
 
    // create a negation of disjunction of above two conditions
    // (i.e. not (cond1 or cond2) )
    ConditionType cond_t3 = new ConditionType();
    cond_t3.setJunction("or");
    cond_t3.setNegation("yes");
    cond_t3.addCondition(cond_t);
    cond_t3.addCondition(cond_t2);
 
    // add the condition object to the rule type object
    rule_t.addCondition(cond_t3);
 
    // create an action type object
    ActionType action_t = new ActionType();
    action_t.addCommand("moveto");
    action_t.addParameter("/testuser1/folder1");
 
    // add the action to the rule object
    rule_t.addAction(action_t);
 
    // create a second action object and add it in the rule type
    ActionType action2_t = new ActionType();
    action2_t.addCommand("call");
    action2_t.addParameter("extern_action");
    action2_t.addParameter("param1");
    action2_t.addParameter("param2");
    rule_t.addAction(action2_t);
 
    // add the rule object in the rulelist type object
    rlist_t.addRule(rule_t);
 
    // add the rulelist object in the account type object
    acnt_t.addRulelist(rlist_t);
 
    // create an account object on based the type object
    Account acnt = new Account(acnt_t);
    parser.setRuleObjects(acnt);
    }
}

Wireless Filters and Profiles API

To efficiently access e-mail over mobile devices or over a slow link, it is necessary to have filters on folders that enable only a small subset of e-mails to be downloaded. The wireless filters and profiles feature enables the user to define search criteria on folders. When a search criteria is defined and the folder is opened, only messages that meet the criteria are selected and are visible to the client. In addition, it also enables the user to define multiple criteria on a folder, through the use of profiles for accessing different sets of messages.

The different wireless filters and profiles components are:

The various interfaces supporting virtual folders are:

Listing Wireless Filters

The following example shows how to list wireless filters:

import java.util.*;
import javax.mail.*;
import javax.mail.internet.*;
import java.io.*;
 
import javax.mail.search.*;
 
import oracle.mail.sdk.esmail.OracleEsProfile;
import oracle.mail.sdk.esmail.OracleEsFilter;
import oracle.mail.sdk.esmail.OracleStore;
public class ListFilter {

    static String password = null;
    static String user = null;
    static String host = null;
    static int port = -1;
    static String mbox = "INBOX";
    static String root = null;
    static boolean recursive = false;
    static String pattern = "*";
    static boolean verbose = false;
    static String namespace = null;
}
 
public static void main (String argv[]) throws Exception {

    for (int i = 0; i < argv.length; i++) {
        if (argv[i].equals("-U")) user = argv[++i];
        else if (argv[i].equals("-P")) password = argv[++i];
        else if (argv[i].equals("-D")) host = argv[++i];
        else if (argv[i].equals("-I")) port = Integer.parseInt(argv[++i]);
        else if (argv[i].equals("--")) {
            i++;
            break;
        }
        else if (argv[i].startsWith("-")) {
            System.out.println("Usage: ListFilter [-D ldap_host] [-I ldap_port] [-U user] [-P password]");
            System.exit(1);
        }
        else {
            break;
        }
    }
 
    Properties props = System.getProperties();
    Session session = Session.getDefaultInstance(props,null);
    session.setDebug(true);

    Store store = null;
    store = session.getStore("esmail"); 
 
    if (user != null && password != null && port != 0 && host != null) {
        store.connect(host, port, user, password);
 
        OracleEsProfile wp2 =
        new OracleEsProfile(store, "wp2", "Wireless Profile 2");
        wp2.create();
        OracleEsProfile[] profiles = ((OracleStore)store).listProfile();
        System.out.println("Number of profiles = " + profiles.length);
 
        for (int i = 0; i < profiles.length; i++) {
            System.out.println("PROFILE " + (i+1));
            System.out.println("profile name = " + profiles[i].getName());
            System.out.println("profile description = " + 
                                profiles[i].getDescription()+ "\n");
            System.out.println("List the filters:");
            OracleEsFilter[] filtersList = profiles[i].listFilters();
            System.out.println("Number of filters : " + filtersList.length);
            for (int j = 0; j < filtersList.length; j++) {
                System.out.println("filter folder = " +
                filtersList[j].getFolder().getFullName());
                System.out.println("filter description = " +
                filtersList[j].getDescription());
                SearchTerm st = filtersList[j].getCriteria();
                if (st instanceof FromTerm) System.out.println("from term");
            }
        }
    }
    store.close();
}
}

Adding Filters to a Profile

The following example shows how to add a wireless filter to a profile:

import java.util.*;
import javax.mail.*;
import javax.mail.internet.*;
import java.io.*;
 
import javax.mail.search.*;
import javax.mail.Address;
import javax.mail.internet.InternetAddress;
 
import oracle.mail.sdk.esmail.OracleEsProfile;
import oracle.mail.sdk.esmail.OracleEsFilter;
import oracle.mail.sdk.esmail.OracleStore;

public class AddFilter {
    static String password = null;
    static String user = null;
    static String host = null;
    static int port = -1;
    static String mbox = "INBOX";
    static String root = null;
    static boolean recursive = false;
    static String pattern = "*";
    static boolean verbose = false;
    static String namespace = null;
 
public static void main (String argv[]) throws Exception {
    for (int i = 0; i < argv.length; i++)
    {
    if (argv[i].equals("-U")) user = argv[++i];
    else if (argv[i].equals("-P")) password = argv[++i];
    else if (argv[i].equals("-D")) host = argv[++i];
    else if (argv[i].equals("-I")) port = Integer.parseInt(argv[++i]);
    else if (argv[i].equals("--"))
    {
        i++;
        break;
    }
    else if (argv[i].startsWith("-"))
    {
    System.out.println(
        "Usage: AddFilter [-D ldap_host] [-I ldap_port] [-U user] [-P password]");
    System.exit(1);
    }
    else
    {
    break;
    }
}
 
    Properties props = System.getProperties();
    Session session = Session.getDefaultInstance(props,null);
    session.setDebug(false);
    
    Store store = null;
    
    store = session.getStore("esmail"); 
    if (user != null && password != null && port != 0 && host != null)
    {
        store.connect(host, port, user, password);
        OracleEsProfile wp2 =
            new OracleEsProfile(store, "wp2", "Wireless Profile 2");
        wp2.create();
 
        OracleEsProfile[] profiles = ((OracleStore)store).listProfile();
        System.out.println("Number of profiles = " + profiles.length);

        for (int i = 0; i < profiles.length; i++)
        {
            System.out.println("PROFILE " + (i+1));
            System.out.println("profile name = " + profiles[i].getName());
            System.out.println("profile description = " +
            profiles[i].getDescription()+ "\n");
        }
        Folder folder = store.getFolder("xyz");
        OracleEsFilter filter =
        new OracleEsFilter
                (folder, "F2",
                 new FromTerm(new InternetAddress("tuser1@us.oracle.com")));
        profiles[0].addFilter(filter);
    }
    store.close();
}
}

External Condition

An external condition is a PL/SQL function that takes the following format:

function <func_name> (p_sessionid in integer,
                      p_msgobj in mail_message_obj) return integer;

Given the session ID and a message object, the function should return a number that indicates whether the condition is met.

If the return value is 0, the server regards it as a positive condition match, and if the return value is non-zero, it is regarded as a failed condition match. If a rule uses an external condition function, it must be manually loaded to the database server where the user resides before the condition can take effect.

To set a condition to be an external condition, use the ConditionType class method addProcCall() as follows:

ConditionType cond_t = new ConditionType();
cond_t.addProcCall("ext_func_name");

Invoking an External Action

An external action is a PL/SQL procedure that takes the following format:

procedure <proc_name>(p_event in number,
                      p_sessionid in number,
                      p_msgobj in mail_message_obj,
                      p_param1 in varchar2,
                      p_param2 in varchar2,
                      p_status out number);

The event ID parameter takes the following possible values:

es_rule.c_copy 
es_rule.c_deliver 
es_rule.c_expunge 
es_rule.c_flagchange 

The procedure also takes a session ID, current message object and two user-defined parameters set at rule creation time. After the procedure is completed, it should put a execution result value in the status parameter. A zero value in status indicates a normal execution, and a positive status indicates an abnormal execution.

To set an external action using server-side rules, use the ActionType class addCommand() method, then call addParameter() three times, with the first added parameter being the procedure name, and the second and third parameters being the user-defined parameters p_param1 and p_param2 above. The following example sets an external action using server-side rules:

ActionType action_t = new ActionType(); 
action_t.addCommand("call"); 
action_t.addParameter("ext_proc_name"); 
action_t.addParameter("param1"); 
action_t.addParameter("param2");