2
votes

Office JavaScript API Reference: Body

I would expect to be able to pass in the value received from Body#getAsync directly into Body#setAsync (with the same coercion type), and for the value of the body to remain the same. In practice, this is not the case.

Demonstration

const { body } = Office.context.mailbox.item;
const coercionType = Office.CoercionType.Html;

// First, let's get the current body of the mailbox item.
body.getAsync(coercionType, {}, (firstResult) => {
  const previousBodyHtml = firstResult.value;

  // Now, let's set the body to the value we received.
  body.setAsync(previousBodyHtml, { coercionType }, () => {

    // Now, let's get the body again.
    body.getAsync(coercionType, {}, (secondResult) => {
      const nextBodyHtml = secondResult.value;

      // The values do not match.
      console.error(previousBodyHtml, 'does not equal', nextBodyHtml);
    });
  });
});

Instead of being idempotent as expected, Body#setAsync runs through quite a bit of filtering.

Observed Behavior

  • Any element in the HTML string with an id or class attribute has that attribute's value prefixed with x_.

    • Some elements in the string returned from Body#getAsync include id and class attributes which appear to have semantic meaning to Outlook (and also to our add-in). Affected elements include indicators for quoted replies, signatures, and the wrapper element for the body HTML itself. When setting the body, these indicators become munged.

    • If an affected attribute already has an x_ prefix, Outlook adds another one. Thus, each time an add-in set the body, these attribute values can grow to have a sizable quantity of x_ prefixes (e.g: x_x_x_x_x_x_x_x_x_x_divtagdefaultwrapper).

  • The value returned from Body#getAsync may include images with Data URIs (this is true in Office 365). Body#setAsync causes the src attributes of these images to be cleared, which causes the images to appear to the user as broken images.

    • Images in the body should never have Data URIs to begin with -- most email clients will not render inline images with Data URIs; they appear in those emails as broken images.

      • Outlook renders most inline images with a src attribute of a proxied image, and with an originalsrc attribute of a cid: URI referencing an attachment on the email with the corresponding Content-ID header. This seems reasonable.

What we have discovered when developing our add-in is that, in practice, Body#setAsync expects to receive an HTML string representing what is inside the first element with an id attribute of divtagdefaultwrapper in Office 365, or the first element with class WordSection1 in Outlook 2016.

Workaround

Thus, to work around this issue, when calling Body#getAsync, we must first parse the string and rebase to the appropriate root element before persisting any changes we make to the body via Body#setAsync. We also ended up having to remove all id and class attributes from elements within the body, add our own sentinel elements to mark semantically important parts of the body (quoted replies, signatures, etc), and implementing our own proxy for images we encounter with Data URIs.

1
What client versions are you observing this in? OWA? Desktop Outlook? Can you provide specific version numbers?Outlook Add-ins Team - MSFT
Oh could you also provide a sample URL/HTML snippet that you are getting/inserting that isn't round tripping?Outlook Add-ins Team - MSFT
This is a general observation that applies to Office 365, Outlook 2016 (Windows and Mac), Outlook 2013 (Windows), on both hosted O365 and in on-premise Exchange deployments. The sample code provided can be exercised in any client, with any input, including an "empty" email body.Devin Canterberry
Can you provide specific version numbers for Outlook Desktop Windows 2016 and 2013? The behavior on Set/Get Body for Desktop Client changed a lot recently, and depending on the build you have it will affect how we investigate.Outlook Add-ins Team - MSFT

1 Answers

0
votes

Due to restraints on the Word rendering engine, we cannot guarantee body.getAsync and body.setAsync are idempotent. The issue you are seeing in Office 365 with inline images in the body that use a data URI is a known issue that we are currently investigating.