====== Error 287 on Reply ======
^ Field ^ Value ^
| Product | Lime desktop client, all versions |
| Component | Outlook integration, customer VBA |
| Diagnosed against | Desktop client 11.2, Outlook 16.0.0.17932 (Office 2024) |
| Product change required | None |
A VBA customization replies to a mail document stored in Lime. After the upgrade to Office 2024 the action fails with error 287 and no Outlook message window opens. The cause is a change in Outlook. The resolution is a change in the VBA customization.
===== Symptom =====
The user activates a reply action on a case card. The action fails immediately. An error dialog appears and names the procedure only. No Outlook message window opens.
The error number is 287. The description is //Application-defined or object-defined error//.
The failure appears to occur during sending. This impression is incorrect. The procedure has one error handler for the complete body, so every failure produces the same dialog. The actual failure occurs much earlier, before Outlook is asked to display anything.
===== Where the failure occurs =====
The reply procedure performs this sequence. Step 3 raises the error.
^ # ^ Call ^ Result ^
| 1 | ''oRecord.document("document").Save(sMailSourcePath)'' | Writes the stored mail to a temporary .msg file. |
| 2 | ''oNameSpace.OpenSharedItem(sMailSourcePath)'' | Succeeds. Returns a message object that is not located in a mailbox store. |
| 3 | ''oMailSource.Reply()'' | **Raises error 287.** |
| 4 | ''oMailReply.HTMLBody = ...'' | Never executed. |
| 5 | ''oMailer.SendTemplate(...)'' | Never executed. |
''ReplyAll'' and ''Forward'' occupy the same position in the sequence and use the same source object.
===== Cause =====
''OpenSharedItem'' reads a .msg file from disk. The message object it returns has no mailbox store behind it.
''MailItem.Reply'' requires the source message to be located in a store. Earlier Outlook versions accepted a message without one. Outlook 16.0.0.17932 raises error 287 instead.
Error 287 is a generic COM failure. It does not identify the member that failed. This is the reason the problem is difficult to locate without instrumentation at the level of individual calls.
===== Which code is affected =====
**Affected.** Customer VBA customizations that call ''Namespace.OpenSharedItem'' and then call ''Reply'', ''ReplyAll'' or ''Forward'' on the result.
**Not affected.** The Lime Outlook integration. ''NewMail.MakeReplyItem'' saves the item into the mailbox and reads it again before it calls ''Reply'', so the message always has a store. ''OpenSharedItem'' does not occur in the product source.
No product update is required. The correction belongs in the customer VBA, which can be deployed centrally in a few hours.
===== Affected versions =====
The failure occurs on every desktop client version. The client is not involved. The failing calls go from the customer VBA directly to Outlook.
The resolution is available on every desktop client version. Redemption is installed with the client under the identifier ''LLOutRed.LLRDOSession''.
^ Client version ^ Redemption build date ^
| 10.18 | 2020-08-04 |
| 11.0 | 2021-09-01 |
| 11.1 | 2024-04-03 |
| 11.2 | 2026-01-20 |
| 11.3 | 2026-01-20 |
The members used by the resolution are long-standing parts of Redemption. Confirm availability on the customer installation before deployment:
? TypeName(Application.CreateObject("LLOutRed.LLRDOSession"))
===== How to confirm the diagnosis =====
Run this in the Immediate window of the Lime VBA editor. Use a .msg file saved from the affected case.
Public Sub Confirm287(ByVal sMsgPath As String)
Dim oOutlook As Object, oNameSpace As Object, oSource As Object, oReply As Object
Dim sStep As String
On Error GoTo Failed
sStep = "CreateObject"
Set oOutlook = VBA.CreateObject("outlook.application")
Debug.Print "Outlook.Version = " & oOutlook.Version
sStep = "OpenSharedItem"
Set oNameSpace = oOutlook.GetNameSpace("MAPI")
Set oSource = oNameSpace.OpenSharedItem(sMsgPath)
sStep = "HTMLBody read"
Debug.Print "HtmlLen = " & VBA.Len(oSource.HTMLBody)
sStep = "Reply"
Set oReply = oSource.Reply()
Debug.Print "no error"
Exit Sub
Failed:
Debug.Print "FAILED at [" & sStep & "] " & Err.Number & " - " & Err.Description
End Sub
The diagnosis is confirmed when the output reports the failure at ''Reply'':
Outlook.Version = 16.0.0.17932
HtmlLen = 2049
FAILED at [Reply] 287 - Application-defined or object-defined error
The ''HTMLBody'' read is included deliberately. ''HTMLBody'' is protected by the Outlook Object Model Guard. A successful read demonstrates that the security configuration is not the cause, so no change to the Trust Center or to group policy is necessary.
===== Resolution =====
Read the message with Redemption instead of the Outlook object model, and move it to the Drafts folder before the reply is created. The move provides the store that ''Reply'' requires.
==== Before ====
Set oOutlook = VBA.CreateObject("outlook.application")
Set oNameSpace = oOutlook.GetNameSpace("MAPI")
Set oMailSource = oNameSpace.OpenSharedItem(sMailSourcePath)
Set oMailReply = oMailSource.Reply()
==== After ====
Const OL_FOLDER_DRAFTS As Long = 16
Const OL_MSG As Long = 3
Set oOutlook = VBA.CreateObject("outlook.application")
Set oSession = Application.CreateObject("LLOutRed.LLRDOSession")
oSession.MAPIOBJECT = oOutlook.Session.MAPIOBJECT
Set oDrafts = oSession.GetDefaultFolder(OL_FOLDER_DRAFTS)
Set oMailSource = oSession.GetMessageFromMsgFile(sMailSourcePath)
Set oMailSource = oMailSource.Move(oDrafts)
colDraftIds.Add oMailSource.EntryID
Set oMailReply = oMailSource.Reply()
oMailReply.Save
colDraftIds.Add oMailReply.EntryID
The remainder of the procedure requires one further change. Redemption requires an explicit format argument when the reply is written to disk:
Call oMailReply.SaveAs(sMailReplyPath, OL_MSG)
===== Required cleanup =====
The move places two messages in the user's Drafts folder: the copy of the source message and the new reply. Both must be deleted on every exit path, including the error handler. Without this the folder accumulates one pair of messages for each failure.
Private Sub CleanupDrafts(ByVal oSession As Object, ByVal colEntryIds As Collection)
Dim vEntryID As Variant
On Error Resume Next
If oSession Is Nothing Or colEntryIds Is Nothing Then
Exit Sub
End If
For Each vEntryID In colEntryIds
oSession.GetMessageFromID(VBA.CStr(vEntryID)).Delete
Next vEntryID
End Sub
''Delete'' moves the message to Deleted Items. It does not remove the message permanently.
===== Limitations of the resolution =====
* ''GetMessageFromMsgFile'' reads .msg files only. Procedures that also accept .htm or .rtf need an explicit check and a clear message for those types. ''OpenSharedItem'' is documented for .msg, .ics and .vcf, so those branches were unlikely to function previously.
* Attachments are copied by a separate loop. Delete the temporary attachment files after the reply is written to disk, not directly after each attachment is added.
===== What was measured =====
Eight runs on one machine, Outlook 16.0.0.17932, one source message with HTML body, codepage 28591 and no attachments. Action ''reply''. Two variables: the construction method, and whether the procedure performs the ''HTMLBody'' read and assignment.
^ Construction ^ HTMLBody assignment ^ Attachment loop ^ Result ^
| Outlook object model | No | No | Fails at Reply, 287 |
| Outlook object model | No | Yes | Fails at Reply, 287 |
| Outlook object model | Yes | No | Fails at Reply, 287 |
| Outlook object model | Yes | Yes | Fails at Reply, 287 |
| Redemption | No | No | Complete |
| Redemption | No | Yes | Complete |
| Redemption | Yes | No | Complete |
| Redemption | Yes | Yes | Complete |
==== Not covered by these measurements ====
* The source message contains no attachments. The attachment loop was therefore never exercised.
* Only ''reply'' was tested. ''replyall'' and ''forward'' were not.
* The runs stop before the Outlook message window is displayed. ''Display'' is an object model call and cannot be replaced by Redemption, because it requires an Outlook item.
* The length of the HTML body changes when the message passes through the file. This did not cause a failure. It is recorded here because the source codepage is 28591 rather than UTF-8.
* The description of the cause is an inference from the two construction methods. Microsoft has not published a statement about this change.
* The version table is read from source trees, not from installed builds.