Søren Boisen
Søren Boisen

Reputation: 1706

Append to meeting invite body with or without Redemption

We are developing an Outlook VSTO add-in.

Right now I am trying to append some information to a meeting invite the user is in the process of composing. I want the content to appear in the body like what clicking the Teams-meeting button would do, where formatted text and links are appended to the end of the body.

Since the content is HTML and the Outlook Object Model does not expose an HTMLBody property for AppointmentItems, I try to set it via Redemption:

// Dispose logic left out for clarity but everything except outlookApplication and outlookAppointment is disposed after use
Application outlookApplication = ...;
AppointmentItem outlookAppointment = ...;  // taken from the open inspector
NameSpace outlookSession = outlookApplication.Session;

RDOSession redemptionSession = RedemptionLoader.new_RDOSession();
redemptionSession.MAPIOBJECT = outlookSession.MAPIOBJECT;
var rdoAppointment = (RDOAppointmentItem)redemptionSession.GetRDOObjectFromOutlookObject(outlookAppointment);

string newBody = transform(rdoAppointment.HTMLBody);  // appends content right before HTML </body> tag
rdoAppointment.BodyFormat = (int)OlBodyFormat.olFormatHTML;
rdoAppointment.HTMLBody = newBody;

Problem

The Outlook inspector window is not updating with the appended content. If I try to run the code again, I can see the appended content in the debugger, but not in Outlook.

Things I have tried:

  1. Saving the RDOAppointmentItem
  2. Also adding the content to Body property
  3. Using SafeAppointmentItem instead of RDOAppointmentItem; didn't work because HTMLBody is a read-only property there
  4. Setting PR_HTML via RDOAppointment.Fields
  5. Paste the HTML via WordEditor (see below)

Attempt to use WordEditor

Per suggestion I also attempted to insert the HTML via WordEditor:

// Dispose logic left out for clarity but everything except inspector is disposed after use
string htmlSnippet = ...;
Clipboard.SetText(htmlSnippet, TextDataFormat.Html);
Inspector inspector = ...;
Document wordDoc = inspector.WordEditor;
Range range = wordDoc.Content;
range.Collapse(WdCollapseDirection.wdCollapseEnd);
object placement = WdOLEPlacement.wdInLine;
object dataType = WdPasteDataType.wdPasteHTML;
range.PasteSpecial(Placement: ref placement, DataType: ref dataType);

... but I simply receive the error System.Runtime.InteropServices.COMException (0x800A1066): Kommandoen lykkedes ikke. (= "Command failed").

Instead of PasteSpecial I also tried using PasteAndFormat:

range.PasteAndFormat(WdRecoveryType.wdFormatOriginalFormatting);

... but that also gave System.Runtime.InteropServices.COMException (0x800A1066): Kommandoen lykkedes ikke..

What am I doing wrong here?

EDIT: If I use Clipboard.SetText(htmlSnippet, TextDataFormat.Text); and then use plain range.Paste();, the HTML is inserted at the end of the document as intended (but with the HTML elements inserted literally, so not useful). So the general approach seems to be okay, I just can't seem to get Outlook / Word to translate the HTML.

Version info

Outlook 365 MSO 32-bit Redemption 5.26

Upvotes: 0

Views: 237

Answers (2)

S&#248;ren Boisen
S&#248;ren Boisen

Reputation: 1706

Per Dmitrys suggestion, here is a working solution that:

  1. Shows the inserted content in the inspector window.
  2. Handles HTML content correctly with regards to both links and formatting (as long as you stay within the limited capabilities of Words HTML engine).
using System;
using System.IO;
using System.Text;
using Outlook = Microsoft.Office.Interop.Outlook;
using Word = Microsoft.Office.Interop.Word;

namespace VSTO.AppendHtmlExample
{
    public class MyExample
    {
        public void AppendAsHTMLViaFile(string content)
        {
            // TODO: Remember to release COM objects range and wordDoc and delete output file in a finally clause
            Outlook.Inspector inspector = ...;
            string outputFolderPath = ...;
            string outputFilePath = Path.Combine(outputFolderPath, "append.html");

            Word.Document wordDoc = inspector.WordEditor;
            File.WriteAllText(outputFilePath, $"<html><head><meta charset='utf-8'/></head><body>{content}</body></html>", Encoding.UTF8);

            Word.Range range = wordDoc.Content;
            range.Collapse(Word.WdCollapseDirection.wdCollapseEnd);

            object confirmConversions = false;
            object link = false;
            object attachment = false;

            range.InsertFile(fileName,
                ConfirmConversions: ref confirmConversions,
                Link: ref link,
                Attachment: ref attachment);
        }
    }
}

Upvotes: 2

Dmitry Streblechenko
Dmitry Streblechenko

Reputation: 66276

Since the appointment is being displayed, work with the Word Object Model - Inspector.WordEditor returns the Document Word object.

Upvotes: 1

Related Questions