Search code examples
outlookoffice-jsoutlook-addinoffice-addinsoutlook-web-addins

Outlook on-send add-in is firing twice


<?xml version="1.0" encoding="utf-8"?>
<OfficeApp
  xmlns="http://schemas.microsoft.com/office/appforoffice/1.1"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:bt="http://schemas.microsoft.com/office/officeappbasictypes/1.0"
  xmlns:mailappor="http://schemas.microsoft.com/office/mailappversionoverrides"
  xsi:type="MailApp">

  <Id>baf2dcf2-21c6-41ac-9c06-1ea235844d9b</Id>
  <Version>3.15.2.7</Version>
  <ProviderName>TeamsAssist</ProviderName>
  <DefaultLocale>en-us</DefaultLocale>
  <DisplayName DefaultValue="TeamsAssist Notifications" />
  <Description DefaultValue="TeamsAssist On-Send Notifications" />
  <IconUrl DefaultValue="~remoteAppUrl/Images/TeamsAssistLogo64x64.png" />
  <HighResolutionIconUrl DefaultValue="~remoteAppUrl/Images/TeamsAssistLogo128x128.png" />
  <SupportUrl DefaultValue="https://cloudassist.co/" />
  
  <!-- Domains that will be allowed when navigating. For example, if you use ShowTaskpane and then have an href link, navigation will only be allowed if the domain is on this list. -->
  <AppDomains>
    <AppDomain>https://teamsassistoutlookserver.azurewebsites.net</AppDomain>
  </AppDomains>

  <Requirements>
    <Sets DefaultMinVersion="1.1">
      <Set Name="Mailbox" />
    </Sets>
  </Requirements>

  <FormSettings>
    <Form xsi:type="ItemRead">
      <DesktopSettings>
        <SourceLocation DefaultValue="~remoteAppUrl/index.html?serverURL=https://teamsassistoutlookserver.azurewebsites.net/" />
        <RequestedHeight>250</RequestedHeight>
      </DesktopSettings>
    </Form>
  </FormSettings>

  <Permissions>ReadWriteItem</Permissions>

  <Rule xsi:type="RuleCollection" Mode="Or">
    <Rule xsi:type="ItemIs" ItemType="Message" FormType="Read" />
  </Rule>

  <VersionOverrides xmlns="http://schemas.microsoft.com/office/mailappversionoverrides" xsi:type="VersionOverridesV1_0">
    <!-- On Send requires VersionOverridesV1_1 -->
    <VersionOverrides xmlns="http://schemas.microsoft.com/office/mailappversionoverrides/1.1" xsi:type="VersionOverridesV1_1">
      <Description resid="residAppDescription" />
      <Requirements>
        <bt:Sets DefaultMinVersion="1.3">
          <bt:Set Name="Mailbox" />
        </bt:Sets>
      </Requirements>
      <Hosts>
        <Host xsi:type="MailHost">
          <DesktopFormFactor>
            <!-- The functionfile and function name to call on message send.  -->
            <!-- In this particular case the function validateBody will be called within the JavaScript code referenced in residUILessFunctionFileUrl. -->
            <FunctionFile resid="residUILessFunctionFileUrl" />
            <ExtensionPoint xsi:type="Events">
              <Event Type="ItemSend" FunctionExecution="synchronous" FunctionName="validateEmail" />
            </ExtensionPoint>
          </DesktopFormFactor>
        </Host>
      </Hosts>
      <Resources>
        <bt:Urls>
           <!-- The JavaScript code is hosted on a secure and trusted web server. -->
          <bt:Url id="residUILessFunctionFileUrl" DefaultValue="~remoteAppUrl/index.html?serverURL=https://teamsassistoutlookserver.azurewebsites.net/" ></bt:Url>
        </bt:Urls>
      </Resources>
    </VersionOverrides>
  </VersionOverrides>
</OfficeApp>

I have an Outlook on-send add-in that checks a composed email and under certain conditions, blocks it, per https://learn.microsoft.com/en-us/office/dev/add-ins/outlook/outlook-on-send-addins?tabs=windows

Sometimes - and it seems to be when a block condition is not found i.e. the email is OK to send - it fires again, which messes up the logic

Cut down here to the minimum ...

'use strict'

console.log('\nVersion 3.4')

// entry point function, called 'On Send'; see Manifest(s)
function validateEmail(event) {
    Office.onReady(function (info) {
        let mailboxItem = Office.context.mailbox.item

        mailboxItem.body.getAsync('html', { asyncContext: event }, function (asyncResult) {
            var allowSend = true
            asyncResult.asyncContext.completed({ allowEvent: allowSend })
        })
    })

}

Console log, showing run twice

YouTube clip of "double On-Send

// TeamsAssist Outlook OnSend App
// Based ***initially*** on https://github.com/OfficeDev/Outlook-Add-in-On-Send
//
//    Date     Who Version  Comment
// ----------- --- -------  -----------------------------------------------------------------------------------------------------------------------------------

// ----------------------------------------------------------------------------------------------------------------------
'use strict'

const version = '3.13.1' // see also version in Manifest

// set both to false for Production
const testing = {
    EnableConsoleLog    : true,     // true for detailed console log
    NeverSend           : false     // true to prevent sending, even if no Notification or Block, for testing purposes only
}

if (testing.EnableConsoleLog) console.log('\nVersion (OnSend): ' + version)

// entry point function, called 'On Send'; see Manifest(s)
async function validateEmail(event) {
    // if (testing.EnableConsoleLog) console.log('validateEmail')

    await getEmailProperties()

    user.MailboxItem.body.getAsync('html', { asyncContext: event }, function (asyncResult) {
        // Trim user FirstName, if necessary
        const userFirstName = user.FirstName.length > global.MaxUserFirstNameLength
            ? user.FirstName.substring(0, global.MaxUserFirstNameLength) + ' ...'
            : user.FirstName

        // Define Notification Message
        email.Notification.Message = 'Hi ' + userFirstName + '; a Notification has occurred; this Email is Blocked. Go to TeamsAssist Help to assist you'

        // Trim Message anyway, if necessary
        if (email.Notification.Message.length > global.MaxNotificationMessageLength)
            email.Notification.Message = email.Notification.Message.substring(0, global.MaxNotificationMessageLength)

        OutlookLog('OnSend', email)

        if (email.Notification.Type === 'NoNotification' || !email.IsBlocked) {
            if (testing.EnableConsoleLog) console.log('Send Allowed')
            user.MailboxItem.notificationMessages.removeAsync(global.NotificationMessageID);
            // asyncResult.asyncContext.completed({ allowEvent: testing.NeverSend ? false : true })
            asyncResult.asyncContext.completed({ allowEvent: true })
        } else {
            if (testing.EnableConsoleLog) console.log('Send Blocked')
            user.MailboxItem.notificationMessages.replaceAsync(global.NotificationMessageID, { type: 'errorMessage', message: email.Notification.Message })
            asyncResult.asyncContext.completed({ allowEvent: false })
        }
    })
}


Solution

  • The resolution to this issue is indeed that there were two deployments; in case this is useful to anyone else; here's a bit more detail: the "double deployment" was not visible in M/S 365 / Integrated Apps, as one deployment was made there, but the other was sideloaded, so only appears in Manage Add-ins, within Outlook - AFAIK. This accounts for the observed "double send" behaviour OK; but there is more: I had another deployment, in another Tenant, and this manifested itself with a different error, Outlook: "We're sorry, we couldn't access .... Make sure you have a network connection ...". Confusing. Thanks all for input