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
orclass
attribute has that attribute's value prefixed withx_
.Some elements in the string returned from
Body#getAsync
includeid
andclass
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 ofx_
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 thesrc
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 anoriginalsrc
attribute of a cid: URI referencing an attachment on the email with the correspondingContent-ID
header. This seems reasonable.
- Outlook renders most inline images with a
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.