Consuming Exchange Web Services with Java using Glassfish and Metro: Creating an email message with MessageType

Moving in the “slowly but surely” spirit of my Exchange Web Services article series, my fourth article will address the most common task in messaging: creating an email message. My example below is mostly a translation of the C# example in an MSDN article titled Creating an Exchange Web Services Client Application.

Method Overloading createItem(...) in ExchangeServicePortType

Just as we did in my 3rd article, the first step is to overload another method in ExchangeServicePortType. This is to avoid passing in null parameters with the SOAP request, working around the the 'xsi:nil' attribute error described in my 2nd article. The method needing to be overloaded for sending an email message is createItem(...). In the interest of not being redundant, I will skip the extended description of how we're method overloading in ExchangeServicePortType. If you'd like that full description, please refer to the method overloading section of my 3rd article. Below is the end result of method overloading createItem(...)

    /**
     * 
     * @param request
     * @param serverVersion
     * @param createItemResult
     * @param impersonation
     * @param requestVersion
     * @param mailboxCulture
     * @param s2SAuth
     */
    @WebMethod(operationName = "CreateItem", action = "http://schemas.microsoft.com/exchange/services/2006/messages/CreateItem")
    public void createItem(
        @WebParam(name = "CreateItem", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/messages", partName = "request")
        CreateItemType request,
        @WebParam(name = "ExchangeImpersonation", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/types", header = true, partName = "Impersonation")
        ExchangeImpersonationType impersonation,
        @WebParam(name = "SerializedSecurityContext", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/types", header = true, partName = "S2SAuth")
        SerializedSecurityContextType s2SAuth,
        @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
        @WebParam(name = "MailboxCulture", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/types", header = true, partName = "MailboxCulture")
        String mailboxCulture,
        @WebParam(name = "RequestServerVersion", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/types", header = true, partName = "RequestVersion")
        RequestServerVersion requestVersion,
        @WebParam(name = "CreateItemResponse", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/messages", mode = WebParam.Mode.OUT, partName = "CreateItemResult")
        Holder createItemResult,
        @WebParam(name = "ServerVersionInfo", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/types", header = true, mode = WebParam.Mode.OUT, partName = "ServerVersion")
        Holder serverVersion);
    
    /**
     * 
     * @param request
     * @param serverVersion
     * @param createItemResult
     * @param requestVersion
     * @param mailboxCulture
     */
    @WebMethod(operationName = "CreateItem", action = "http://schemas.microsoft.com/exchange/services/2006/messages/CreateItem")
    public void createItem(
        @WebParam(name = "CreateItem", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/messages", partName = "request")
        CreateItemType request,
        @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
        @WebParam(name = "MailboxCulture", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/types", header = true, partName = "MailboxCulture")
        String mailboxCulture,
        @WebParam(name = "RequestServerVersion", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/types", header = true, partName = "RequestVersion")
        RequestServerVersion requestVersion,
        @WebParam(name = "CreateItemResponse", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/messages", mode = WebParam.Mode.OUT, partName = "CreateItemResult")
        Holder createItemResult,
        @WebParam(name = "ServerVersionInfo", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/types", header = true, mode = WebParam.Mode.OUT, partName = "ServerVersion")
        Holder serverVersion);
    
    /**
     * 
     * @param request
     * @param serverVersion
     * @param createItemResult
     * @param impersonation
     * @param requestVersion
     * @param mailboxCulture
     */
    @WebMethod(operationName = "CreateItem", action = "http://schemas.microsoft.com/exchange/services/2006/messages/CreateItem")
    public void createItem(
        @WebParam(name = "CreateItem", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/messages", partName = "request")
        CreateItemType request,
        @WebParam(name = "ExchangeImpersonation", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/types", header = true, partName = "Impersonation")
        ExchangeImpersonationType impersonation,
        @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
        @WebParam(name = "MailboxCulture", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/types", header = true, partName = "MailboxCulture")
        String mailboxCulture,
        @WebParam(name = "RequestServerVersion", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/types", header = true, partName = "RequestVersion")
        RequestServerVersion requestVersion,
        @WebParam(name = "CreateItemResponse", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/messages", mode = WebParam.Mode.OUT, partName = "CreateItemResult")
        Holder createItemResult,
        @WebParam(name = "ServerVersionInfo", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/types", header = true, mode = WebParam.Mode.OUT, partName = "ServerVersion")
        Holder serverVersion);
    
    /**
     * 
     * @param request
     * @param serverVersion
     * @param createItemResult
     * @param requestVersion
     * @param mailboxCulture
     * @param s2SAuth
     */
    @WebMethod(operationName = "CreateItem", action = "http://schemas.microsoft.com/exchange/services/2006/messages/CreateItem")
    public void createItem(
        @WebParam(name = "CreateItem", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/messages", partName = "request")
        CreateItemType request,
        @WebParam(name = "SerializedSecurityContext", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/types", header = true, partName = "S2SAuth")
        SerializedSecurityContextType s2SAuth,
        @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
        @WebParam(name = "MailboxCulture", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/types", header = true, partName = "MailboxCulture")
        String mailboxCulture,
        @WebParam(name = "RequestServerVersion", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/types", header = true, partName = "RequestVersion")
        RequestServerVersion requestVersion,
        @WebParam(name = "CreateItemResponse", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/messages", mode = WebParam.Mode.OUT, partName = "CreateItemResult")
        Holder createItemResult,
        @WebParam(name = "ServerVersionInfo", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/types", header = true, mode = WebParam.Mode.OUT, partName = "ServerVersion")
        Holder serverVersion);

Now let's add a createItem(...) method to ItemTypeDAO(...) which will create the email message and send it.

Adding a createItem(...) method to ItemTypeDAO

This next code section assumes you have the classes ItemTypeDAO, ExchangeEnvironmentSettings, and the throwaway testing class ExchangeDevelopmentTest. The creation of these classes is outlined in my 2nd and 3rd articles. This next code example is a method to be added to ItemTypeDAO. As usual, I use code comments as an inline tutorial:

    /**
     * Method for creating a MessageType and sending the message to another 
     * email user. Eventually it would be best to abstract the hard-coded
     * sections of MessageDispositionType, TargetFolderIdType, and creating
     * the MessageType into another class (eg. a class named MessageTypeDAO). 
     * 
     * For this example, and for a more direct translation from the MSDN 
     * article, I've left the class poorly abstracted and encapsulated.
     * 
     * Method translated from an MSDN example:
     * http://msdn.microsoft.com/en-us/library/bb408521.aspx
     * 
     * @param port
     */
    public void createItem(ExchangeServicePortType port) {
        // Create the CreateItemType for SOAP request.
        CreateItemType createEmailRequest = new CreateItemType();

        // Specifiy how the e-mail will be handled.
        createEmailRequest.setMessageDisposition(MessageDispositionType.SEND_AND_SAVE_COPY);

        // Specify the location of sent items. 
        TargetFolderIdType targetFolderIdType = new TargetFolderIdType();
        DistinguishedFolderIdType distinguishedFolderIdType = new DistinguishedFolderIdType();
        distinguishedFolderIdType.setId(DistinguishedFolderIdNameType.SENTITEMS);
        targetFolderIdType.setDistinguishedFolderId(distinguishedFolderIdType);
        createEmailRequest.setSavedItemFolderId(targetFolderIdType);

        // Create the array of items.
        NonEmptyArrayOfAllItemsType nonEmptyArrayOfAllItemsType = new NonEmptyArrayOfAllItemsType();

        // Create a single e-mail message.
        MessageType messageType = new MessageType();
        messageType.setSubject("Test email from using JAX-WS");

        BodyType bodyType = new BodyType();
        bodyType.setBodyType(BodyTypeType.TEXT);
        bodyType.setValue("This is the body of the message in plaintext.");
        messageType.setBody(bodyType);
        
        EmailAddressType senderEmailAddressType = new EmailAddressType();
        senderEmailAddressType.setEmailAddress("sender@example.com");
        SingleRecipientType sender = new SingleRecipientType();
        sender.setMailbox(senderEmailAddressType);
        messageType.setSender(sender);
        
        ArrayOfRecipientsType toRecipientsArrayOfRecipientsType = new ArrayOfRecipientsType();
        EmailAddressType toEmailAddressType = new EmailAddressType();
        toEmailAddressType.setEmailAddress("recipient@example.com");
        toRecipientsArrayOfRecipientsType.getMailbox().add(toEmailAddressType);
        messageType.setToRecipients(toRecipientsArrayOfRecipientsType);

        messageType.setSensitivity(SensitivityChoicesType.NORMAL);

        // Add the MessageType to the array of items to be created.
        nonEmptyArrayOfAllItemsType.getItemOrMessageOrCalendarItem().add(messageType);
        createEmailRequest.setItems(nonEmptyArrayOfAllItemsType);

        try {
            // Send a CreateItem request and get the CreateItem response.
            CreateItemResponseType createItemResponseType = new CreateItemResponseType();
            Holder createItemResult = new Holder(createItemResponseType);
            
            // Send the SOAP request and a holder for the createItemResult
            port.createItem(createEmailRequest, 
                    exchangeEnvironmentSettings.getMailboxCulture(), 
                    exchangeEnvironmentSettings.getRequestServerVersion(), 
                    createItemResult, 
                    exchangeEnvironmentSettings.getServerVersionInfoHolder());
            
            
            ArrayOfResponseMessagesType responses = createItemResult.value.getResponseMessages();
            List> responsemessagetypelist = responses.getcreateitemresponsemessageordeleteitemresponsemessageorgetitemresponsemessage();

            // access the response messages.
            iterator> responsemessagetypelistiter = responsemessagetypelist.iterator();
            while (responsemessagetypelistiter.hasnext()){
                jaxbelement jaxbelement = responsemessagetypelistiter.next();
                
                if (jaxbelement.getvalue().getresponseclass() == responseclasstype.error){
                    throw new exception("error: " + jaxbelement.getvalue().getmessagetext());
                }
                else if (jaxbelement.getvalue().getresponseclass() == responseclasstype.warning){
                    throw new exception("warning: " + jaxbelement.getvalue().getmessagetext());
                }
                if(jaxbelement.getvalue() instanceof iteminforesponsemessagetype) {
                    iteminforesponsemessagetype iteminforesponsemessagetype = (iteminforesponsemessagetype) jaxbelement.getvalue();
                    arrayofrealitemstype arrayofrealitemstype = (arrayofrealitemstype) iteminforesponsemessagetype.getitems();

                    list itemtypelist = arrayofrealitemstype.getitemormessageorcalendaritem();
                    iterator itemtypelistiter = itemtypelist.iterator();
                    while(itemtypelistiter.hasnext()) {
                        itemtype itemtype = itemtypelistiter.next();
                        if (itemtype instanceof messagetype){
                            messagetype createdmessagetype = (messagetype) itemtype;
                            logger.getlogger(itemtypedao.class.getname()).log(level.info, "created item: " + createdmessagetype.getitemid().getid());
                        }

                        // todo: add logic to check and cast for all other types.
                    }
                }
            }
        }
        catch (exception ex) {
            logger.getlogger(itemtypedao.class.getname()).log(level.severe, null, ex);
        }
    }
    responsemessagetypelist = responses.getcreateitemresponsemessageordeleteitemresponsemessageorgetitemresponsemessage();

            // access the response messages.
            iterator> responsemessagetypelistiter = responsemessagetypelist.iterator();
            while (responsemessagetypelistiter.hasnext()){
                jaxbelement jaxbelement = responsemessagetypelistiter.next();
                
                if (jaxbelement.getvalue().getresponseclass() == responseclasstype.error){
                    throw new exception("error: " + jaxbelement.getvalue().getmessagetext());
                }
                else if (jaxbelement.getvalue().getresponseclass() == responseclasstype.warning){
                    throw new exception("warning: " + jaxbelement.getvalue().getmessagetext());
                }
                if(jaxbelement.getvalue() instanceof iteminforesponsemessagetype) {
                    iteminforesponsemessagetype iteminforesponsemessagetype = (iteminforesponsemessagetype) jaxbelement.getvalue();
                    arrayofrealitemstype arrayofrealitemstype = (arrayofrealitemstype) iteminforesponsemessagetype.getitems();

                    list itemtypelist = arrayofrealitemstype.getitemormessageorcalendaritem();
                    iterator itemtypelistiter = itemtypelist.iterator();
                    while(itemtypelistiter.hasnext()) {
                        itemtype itemtype = itemtypelistiter.next();
                        if (itemtype instanceof messagetype){
                            messagetype createdmessagetype = (messagetype) itemtype;
                            logger.getlogger(itemtypedao.class.getname()).log(level.info, "created item: " + createdmessagetype.getitemid().getid());
                        }

                        // todo: add logic to check and cast for all other types.
                    }
                }
            }
        }
        catch (exception ex) {
            logger.getlogger(itemtypedao.class.getname()).log(level.severe, null, ex);
        }
    }

To test this, modify ExchangeDevelopmentTest as follows:

package name.reidmiller.exchange.util;

import com.microsoft.schemas.exchange.services._2006.messages.ExchangeServicePortType;
import java.net.*;
import java.util.logging.*;
import name.reidmiller.exchange.dao.ItemTypeDAO;

/**
 * Throw-away class for doing quick tests of features and classes during 
 * development.
 * 
 * @author Reid Miller
 */
public class ExchangeDevelopmentTest {
    /**
     * Main method so we can quickly test things.
     * @param args
     */
    public static void main (String[] args) {
        ExchangeAuthenticator exchangeAuthenticator = new ExchangeAuthenticator();

        // Print statement so we can easily see where our statements start in the Java console.
        System.out.println("Let's get started!");

        try {            
            // Create a URL object which points at the .wsdl we deployed in the previous step.
            URL wsdlURL = new URL("http://localhost:8080/ExchangeWebServices/exchange.wsdl");
            
            // Call to the class we just created to return an ExchangeServicePortType with authentication credentials.
            ExchangeServicePortType port = exchangeAuthenticator.getExchangeServicePort("username", "password", "domain", wsdlURL);
            
            // Prints out the default toString() for the ExchangeServicePortType.
            System.out.println(port.toString());

            // Test out the new ItemTypeDAO functionality.
            ItemTypeDAO itemTypeDAO = new ItemTypeDAO();
            itemTypeDAO.createItem(port);

        } catch (MalformedURLException ex) {
            // Catch any errors that may occur.
            Logger.getLogger(ExchangeDevelopmentTest.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

Run your code

Just like the previous articles, to run the code:

  1. Using the “Projects” column on the left-hand side, find the package you created ExchangeDevelopmentTest in. Right-click on ExchangeDevelopmentTest.java and select “Run”.

In the Java console below you should see a few System.out.println(...) lines. Assuming you sent your test email to yourself, the real proof is in your inbox.

Conclusion

Certainly there are many other concerns with creating an email message like drafts, HTML messages, attachments, multiple recipients, etc. This example should clarify MSDN's documentation a bit more and get you down the path of creating email messages with Exchange Web Services. If you have questions about some of these additional operations, please leave a comment to my article. I've been having fun working with the commenter on my previous articles. Up next is an article on using RestrictionType to find items based on search criteria.

3 Comments

Add new comment