Integrating a Lotus Notes application with Exchange

I recently finished a project with the purpose of integrating a Lotus Notes CRM application with Microsoft Outlook and Microsoft Exchange. The customer has moved their mail handling to Exchange and Outlook and still uses Lotus Notes for their application handling including this CRM application. The CRM application had functionality to import mails from Notes, send mail from Notes, and create and maintain meeting invitations. My task was to make this functionality work with Exchange and Outlook instead.

In order to integrate with Exchange I used the Exchange Web Services (EWS) Java API and created a Java class with the necessary jar files imported that is responsible for the interface between the existing Lotusscript logic and the EWS API. The Lotusscript logic then uses LS2J to use the methods in the Java class.

With Exchange Web Services installed on the Exchange server the Java API can access the web services using the WSDL at /EWS/Service.wsdl (through an endpoint called /EWS/exchange.asmx).

To allow the Lotus Notes client to communicate with the Exchange server I needed to change the java.policy file in order to add: permission java.net.NetPermission “setCookieHandler”, “write”;. To automate this I used this Lotusscript code by Darren Oliver that checks the java.policy file for a specific permission policy and if not found adds the permission policy.

At first I wanted to use Exchange Impersonation to allow a single Windows Active Directory account to be able to act on behalf of others users on a Exchange mailbox. This decision was later changed to use the individual users own credentials. The user is prompted for their password and this is stored encrypted for their use only in a profile document. The following code snippet shows how communication with the Exchange server is set up in Java using the EWS API:

service = new ExchangeService(ExchangeVersion.Exchange2010_SP1);
// service.setTraceEnabled(true); // enable to trace the web service communication in the Java debug console
service.setUrl(new java.net.URI(server));
ExchangeCredentials credentials = new WebCredentials(userid, password);
service.setCredentials(credentials);

A meeting is simply created using the Appointment class. Time zone support is achieved by using UTC as the time zone for date details. To format dates as UTC I used the LSGMTTime  property of the NotesDateTime class.

Appointment appointment = new Appointment(service);
appointment.setSubject(subject);
appointment.setBody(MessageBody.getMessageBodyFromText(body));
appointment.setStart(formatter.parse(startDate));
appointment.setEnd(formatter.parse(endDate));
appointment.setLocation(location);
// Save as appointment - and not as a meeting with participants
appointment.save(SendInvitationsMode.SendToNone);

Importing mails is done by presenting the user with a list of mails from the users Exchange mailbox. The list is retrieved by looping through the Inbox folder:

ItemView view = new ItemView(100);
view.getOrderBy().add(ItemSchema.DateTimeReceived, SortDirection.Ascending);
FindItemsResults<Item> findResults;
findResults = service.findItems(WellKnownFolderName.Inbox, view);
service.loadPropertiesForItems(findResults.getItems(), new PropertySet(BasePropertySet.IdOnly, EmailMessageSchema.Subject, EmailMessageSchema.DateTimeReceived, EmailMessageSchema.Sender));

The user then selects a mail from the list and the corresponding mail in Exchange is retrieved with the unique item id as identifier.

EmailMessage message = EmailMessage.bind(service, new ItemId(mailItemId));

Rich text support between Notes and Outlook is handled using Lotusscript stream and mime classes:

Set stream = session.CreateStream
Call stream.WriteText(mailBody)
Set mime = doc.CreateMIMEEntity("Body")
Call mime.SetContentFromText (stream, "text/html;charset=UTF-8",ENC_NONE)

When sending mails from the Notes CRM application the user can access their Outlook contacts. The list of Outlook contacts is retrieved by looping through the Contacts folder:

ItemView view = new ItemView(2000);
view.getOrderBy().add(ContactSchema.DisplayName, SortDirection.Ascending);
FindItemsResults<Item> findResults;
findResults = service.findItems(WellKnownFolderName.Contacts, view);

The Microsoft Outlook client is launched when a meeting invitation is created in order for the user to finish the meeting invitation in Outlook. This is achieved by using the Shell Lotusscript command together with the fact that Outlook can be launched with a parameter that indicates what item to open when launched:

Shell( getOutlookPath() + " /select outlook:" + Ucase(doc.OutlookUniqueId(0)) )

The use of LS2J led to some performance issues at the customer site in the form of 10-20 seconds load times before a document was opened. The reason for this is that the Java code is extracted to disk whereby the Antivirus program at use at the customer site started to check all files for virus before the document could be opened. The customer modified the Antivirus settings to remove this check whereby the documents opened within reasonable time again.

Excel automation on Windows Server 2008 x64: solution to SaveAs method problem

A customer of mine uses Lotusscript and the Microsoft Excel object to create Excel spreadsheets with scheduled agents. The code is based on the normal way of creating spreadsheets – e.g.:

Set ExcelApp = CreateObject("Excel.Application")
Set ExcelWorkbook = ExcelApp.Workbooks.Open("C:test.xls")
Set ExcelWorksheet = ExcelWorkbook.Application.Workbooks(1).Worksheets(1)

The scheduled agents worked fine on a Windows Server 2003. The application was then installed on a freshly installed Domino server running on a freshly installed Windows Server 2008 x64 (64 bit) and then the scheduled agents started failing with the following error message: “SaveAs method of Workbook class failed“.

After several tries of fixing the code I finally found the simple (but unexpected) solution to the problem: create a folder called “Desktop” in C:\Windows\SysWOW64\config\systemprofile\.

Yes, that’s it! just create the folder and then the code starts working again 🙂

I have somehow contributed to OpenNTF

I woke up this morning to a comment by David Jeyachandran to my blog post on Sorting a NotesDocumentCollection by multiple field values. David wanted to let me know that he is using the sort function in the Notes Reconn project at OpenNTF.

That is great news – and I am happy to know that I have contributed to a project on OpenNTF (although just a very small part).

Sorting a NotesDocumentCollection by multiple field values (Show’n Tell Thursday)

I have been using Joe Littons sortCollection function with success to sort a NotesDocumentCollection by the value in a specific field name. However the function can only sort by one field value and I recently had the requirement to be able to sort by multiple field values.

Max Flodén has created a function that does exactly that: sorts a NotesDocumentCollection by one or more field values. But the code from Max uses Evaluate and @Sort to do the actual sorting – and therefore has problems with quotes in the values and apparently also a problem with large collections (see comments to his post).

So I have combined the best from the two sort functions – the sortValues function from Joe Litton that uses Shell sort and the option to sort by multiple field values from Max Flodén – to get a function that sorts a NotesDocumentCollection by one or more field values.

Update: I have updated the sort function to use a fast and easy way of creating an empty NotesDocumentCollection introduced by Peter von Stöckel.

Update November 21: During testing I found an unnecessary loop in the sortCollection function. I have therefore updated the sort function.

Update December 9, 2011: The function is now available on the new OpenNTF XSnippets site.