OfficeDev / office-js

A repo and NPM package for Office.js, corresponding to a copy of what gets published to the official "evergreen" Office.js CDN, at https://appsforoffice.microsoft.com/lib/1/hosted/office.js.
https://learn.microsoft.com/javascript/api/overview
Other
669 stars 95 forks source link

Classic Outlook on Windows 16.0.18006.20000 (beta channel) does not fire the launch event onMessageCompose (and maybe others) #4780

Closed GruberMarkus closed 4 days ago

GruberMarkus commented 1 month ago

Provide required information needed to triage your issue

Your Environment

Expected behavior

Outlook triggers onMessageCompose launch event, so that event-based add-ins work.

Current behavior

Classic Outlook on Windows "Version 2409 Build 16.0.18006.20000 64-bit" does not fire the launch event onMessageCompose (and maybe others). This beta version is required to test nested app authentication (NAA) for launch events. NAA is working fine outside launch events.

When switching the update channel to current channel, launch events work again - but the current channel release does not yet support NAA.

Steps to reproduce

  1. Switch to a non-beta update channel
  2. Download the manifest file https://github.com/OfficeDev/Office-Add-in-samples/blob/main/Samples/outlook-set-signature/manifest.xml. and sideload it.
  3. Restart Outlook create a new email, open the taskpane of the sideloaded add-in and configure it to automatically set signatures
  4. Create another new email. The launch event will fire and the add-in will set the signature.
  5. Switch to the Office current channel update channel
  6. Create a new email. The launch event will not fire and the add-in will not set the signature.
  7. Switch back to a non-beta update channel. Launch event will fire again.

Link to live example(s)

https://github.com/OfficeDev/Office-Add-in-samples/blob/main/Samples/outlook-set-signature

Provide additional details

Using the sample add-in from Microsoft mentioned above (https://github.com/OfficeDev/Office-Add-in-samples/blob/main/Samples/outlook-set-signature), the taskpane works fine on all Classic Outlook on Windows installations. Setting the signature with the taskpane buttons works fine.

I also tested with other event based add-ins, self-created and downloaded, but the behavior does not change.

Context

Event based add-ins can not use NAA on Classic Outlook on Windows "Version 2409 Build 16.0.18006.20000 64-bit".

Useful logs

RuntimeLogging is enabled (https://learn.microsoft.com/en-us/office/dev/add-ins/testing/runtime-logging).

Log for "Version 2409 Build 16.0.18006.20000 64-bit":

12.08.2024 09:20:49 Medium  Web Add-In Runtime Logging Session Started          
12.08.2024 09:20:49 Verbose Runtime [Console] [Log] Platform Bundle - Office exists!        
12.08.2024 09:20:49 Verbose Runtime [Console] [Log] Platform Bundle - Office.actions exists!        
12.08.2024 09:20:49 Verbose Runtime [Console] [Log] Platform Bundle - Office.actions.associate exists!      
12.08.2024 09:20:49 Verbose Runtime [Console] [Log] Outlook Batch JS loaded!        
12.08.2024 09:20:49 Verbose Runtime [Console] [Log] Outlook LaunchEvent JS loaded!      

Log for version from current channel update channel:

12.08.2024 09:36:52 Medium  Web Add-In Runtime Logging Session Started          
12.08.2024 09:36:52 Unexpected  Resource    The resource you are trying to use does not exist.      
12.08.2024 09:36:52 Unexpected  Resource    The resource you are trying to use does not exist.      
12.08.2024 09:36:52 Unexpected  Resource    The resource you are trying to use does not exist.      
12.08.2024 09:37:12 Verbose Runtime [Console] [Log] Platform Bundle - Office exists!        
12.08.2024 09:37:12 Verbose Runtime [Console] [Log] Platform Bundle - Office.actions exists!        
12.08.2024 09:37:12 Verbose Runtime [Console] [Log] Platform Bundle - Office.actions.associate exists!      
12.08.2024 09:37:12 Verbose Runtime [Console] [Log] Outlook Batch JS loaded!        
12.08.2024 09:37:12 Verbose Runtime [Console] [Log] Outlook LaunchEvent JS loaded!      
12.08.2024 09:37:12 Verbose Runtime [Console] [Log] InvokeMailboxCreateOM was invoked!["{\"hostVersion\":\"16.0.17830.20138\", \"itemType\":4, \"permissionLevel\":2, \"userEmailAddress\":\"xxx@example.com\", \"userDisplayName\":\"XXX\", \"userProfileType\":\"office365\", \"userTimeZone\":\"W. Europe Standard Time\", \"conversationId\":null, \"ewsUrl\":\"https://outlook.office365.com/EWS/Exchange.asmx\", \"restUrl\":\"https://outlook.office.com/api\", \"itemNumber\":1073741825, \"roamingSettings\":\"{\\\"user_info\\\":\\\"\\\\\\\"{\\\\\\\\\\\\\\\"name\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"XXX\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"email\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"xxx@example.com\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"job\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"phone\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"greeting\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"pronoun\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\"}\\\\\\\"\\\",\\\"newMail\\\":\\\"\\\\\\\"templateA\\\\\\\"\\\",\\\"reply\\\":\\\"\\\\\\\"templateA\\\\\\\"\\\",\\\"forward\\\":\\\"\\\\\\\"templateA\\\\\\\"\\\",\\\"override_olk_signature\\\":\\\"true\\\"}\", \"extensionPointType\":8, \"enableBetaAPIs\":false, \"displayLanguage\":\"en-US\", \"contentLanguage\":\"de-AT\", \"officeVersion\":\"16.0.17830.20138\", \"requirementSets\":\"{\\\"Mailbox\\\":\\\"1.14\\\",\\\"OutlookTelemetry\\\":\\\"1.2\\\",\\\"IdentityAPI\\\":\\\"1.3\\\"}\", \"inReplyTo\":null, \"urls\":\"{\\\"javascriptRuntimeUrl\\\":\\\"https://officedev.github.io/Office-Add-in-samples/Samples/outlook-set-signature/src/runtime/Js/autorunshared.js\\\"}\", \"isFromSharedFolder\":false, \"shouldRunNewCodeForFlags\":1, \"nativeFlights\":{\"Ripcord_7935469\":true,\"NestedAppAuthEnabled\":false,\"ReplyFormBase64Support\":true}}"]     
12.08.2024 09:37:12 Verbose Runtime [Console] [Log] SDX Control is ready!       
12.08.2024 09:37:12 Verbose Runtime [Console] [Log] MailboxHostExecuteApi invoked!      
12.08.2024 09:37:12 Verbose Runtime [Console] [Log] RunLaunchEventHandlerFunctionWithData was invoked with funcName = checkSignature        
12.08.2024 09:37:12 Verbose Runtime [Console] [Log] MailboxHostExecuteApi invoked!      
12.08.2024 09:37:12 Verbose Runtime [Console] [Log] MailboxHostExecuteApi invoked!      
12.08.2024 09:37:12 Verbose Runtime [Console] [Log] LaunchEventObj.completed was invoked: 1     
12.08.2024 09:37:12 Verbose Runtime [Console] [Log] Event completed message sent to host!       
Oleg-O commented 1 month ago

My own add-in that uses onMessageCompose appears to be working well on the same channel/build (16.0.18006.20000 on win11). There may be something with this sample. We'll look into it.

BTW in Step 5, did you mean to say "switch to Beta channel"?

Oleg-O commented 4 weeks ago

@GruberMarkus so far we're unable to reproduce this with your steps on the same build. I and at least another person in my team tried it and the sample appears to be working well. Are you still having this issue consistently?

GruberMarkus commented 4 weeks ago

BTW in Step 5, did you mean to say "switch to Beta channel"?

Yes, that should read "switch to Beta channel".

GruberMarkus commented 4 weeks ago

@GruberMarkus so far we're unable to reproduce this with your steps on the same build. I and at least another person in my team tried it and the sample appears to be working well. Are you still having this issue consistently?

It was constant the day I created the issue.

In the meantime, I extended the tests to multiple clients: It seems that there is either something machine specific involed, or it is about timing. The error can no longer be reproduced consistently on any of my test machines, but when it happen, the runtime log is the same as in the first post.

When the error occurs, the fastest way to solve the problem seems to be to switch back to a non-Beta channel and then back (sometimes this needs to be done two or three times).

GruberMarkus commented 3 weeks ago

I think I found the reason. The problem is still somewhere in Outlook itself, but the choice of the add-in used to test can lead to completely different behaviors.

Reproduction steps:

  1. Download the official Microsoft add-in sample from https://github.com/OfficeDev/Office-Add-in-samples/tree/main/Samples/outlook-set-signature
  2. Stop Outlook
  3. End pross msoadfsb.exe, if it exists
  4. Clear "%LOCALAPPDATA%\Microsoft\Office\16.0\Wef\", "%userprofile%\AppData\Local\Packages\Microsoft.Win32WebViewHost_cw5n1h2txyewy\AC#!123\INetCache\" and "%userprofile%\AppData\Local\Microsoft\Outlook\HubAppFileCache"
  5. Switch to the root of "outlook-set-signature"
  6. npm run start:xml
  7. Outlook starts
  8. Confige the add-in once (the config is stored in the mailbox for later use): Create a new email, click on "Set my signature" in the ribbon, Save, assign on of the template to "New mail", click on Save, close the new email
  9. Create a new email: The signature will be added.
  10. npm stop
  11. Repeat steps 2-10 as often as you wish, it will always work (there is no need to repeat step 8)

Now to the tricky part:

  1. Repeat steps 2-5
  2. in webpack.config.js, delete or comment the following lines:
    {
     from: "src/runtime/Js/autorunshared.js",
     to: "[name]" + "[ext]",
    },
  3. npm run start:xml
  4. Outlook starts
  5. Create a new email: The signature will NOT be added

What happens is that the Outlook launch event is bound to code running in autorunshared.js. In the original configuration of the sample, autorunshared.js is just copied to the distribution folder as is, without webpack even touching it.

When you do the comment/delete stuff in step 13, this copy is disabled and the webpack modified version of autorunshared.js is used. You can see that when looking at your dist folder after building, or when looking at the associated bundle.js file in the "%LOCALAPPDATA%\Microsoft\Office\16.0\Wef\" folder structure.

Webpack and/or Babel do something to the code that the JS engine used by the OnMessageCompose launch event in Classic Outlook on Windows is not able to work with. At the same time, the very same Webpack/Babel modified code works fine on Outlook Web/Android/iOS/Mac.

How is this supposed to work with production code being deployed to customers? Webpack offers at least some sort of code protection, and Outlook Web/Android/iOS/Mac can even handle JS code being obfuscated by multiple tools.

Even more important: Microsoft wants us all to switch from legacy tokens to Nested App Authentication (NAA) in add-ins as soon as possible (I am aware that the timelines have been moved from October 2024 shortly). Using NAA requires import { createNestablePublicClientApplication } from "@azure/msal-browser";, even for launch events.

So, I am looking for answers to two questions:

davidchesnut commented 3 weeks ago

Hi @GruberMarkus, Wow! Thanks for putting in all that detective work!

Yes, if webpack adds the hot reload code, it will break when loaded in the JS only runtime of Outlook on Windows. So, you just need to be sure that the hot reload isn't there. The initial webpack config ensures that is not there. If you want additional webpack features in the autorunshared.js I believe it's fine however you configure as long as any included updates or libraries are not HTML or DOM dependent. JS-only.

There is a webpack config to include @azure/msal-browser that I'm hoping to get uploaded to our samples repo (hopefully any day now). So, you can just import it and it should work.

Cheers, David

GruberMarkus commented 3 weeks ago

@davidchesnut: I may be on a wrong way here, but isn't hot reload a dev-server-only feature?

I see the behavior described above also when using code that was built for production deployment.

davidchesnut commented 3 weeks ago

@GruberMarkus does https://github.com/OfficeDev/Office-Add-in-samples/pull/832 solve this issue? If so we can probably close this. Thanks!

GruberMarkus commented 2 weeks ago

@GruberMarkus does OfficeDev/Office-Add-in-samples#832 solve this issue? If so we can probably close this. Thanks!

We are working on it. The test may be done tomorrow evening or early next week.

GruberMarkus commented 2 weeks ago

The sampe from the pull request works fine every single time on Classic Outlook on Windows.

When I replace your launchevent with my own full-featured code, it runs fine everywhere but not as launchEvent on Classic Outlook for Windows. The very same code in the taskpane works fine.

When the lauch event does not work, RuntimeLogging loggs nothing but the following:

23.08.2024 09:29:08 Medium  Web Add-In Runtime Logging Session Started          
23.08.2024 09:29:08 Verbose Runtime [Console] [Log] Platform Bundle - Office exists!        
23.08.2024 09:29:08 Verbose Runtime [Console] [Log] Platform Bundle - Office.actions exists!        
23.08.2024 09:29:08 Verbose Runtime [Console] [Log] Platform Bundle - Office.actions.associate exists!      
23.08.2024 09:29:08 Verbose Runtime [Console] [Log] Outlook Batch JS loaded!        
23.08.2024 09:29:08 Verbose Runtime [Console] [Log] Outlook LaunchEvent JS loaded!      

The interesting part is: When I reduce features, it works - but the problem is obviously not bound to a specific feature, but it seems to be the number of features or the amount of code.

How can I find out what the problem is?

davidchesnut commented 2 weeks ago

Outlook classic is using the V8 JavaScript engine as the runtime so my guess is something is incompatible. This can happen if you try to load a library that expects there to be a DOM for example. The approach I've used is to back the code down to where it will load, then gradually introduce function by function the new code until you spot what causes it to fail. Then see if it is a particular library, or some more modern EcmaScript syntax that v8 won't load. Unfortunately there isn't a way to pinpoint exactly what line of code causes the fail.

GruberMarkus commented 2 weeks ago

So I will have to dig through the code.

Can I directly edit the bundle.js file downloaded by Classic Outlook for Windows, or will this trigger an update?

GruberMarkus commented 2 weeks ago

I found the problematic code: The atob() function makes launch event code fail in Classic Outlook on Windows.

Replacing it with the following code solves the problem:

function atobPolyfill(input) {
  const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

  let str = String(input).replace(/=+$/, "");

  if (str.length % 4 === 1) {
    throw new Error("'atobPolyfill' failed: The string to be decoded is not correctly encoded.");
  }

  let output = "";

  for (
    let bc = 0, bs, buffer, idx = 0;
    (buffer = str.charAt(idx++));
    ~buffer && ((bs = bc % 4 ? bs * 64 + buffer : buffer), bc++ % 4)
      ? (output += String.fromCharCode(255 & (bs >> ((-2 * bc) & 6))))
      : 0
  ) {
    buffer = chars.indexOf(buffer);
  }

  return output;
}

One question remains: Why is there no logging about this?

The launch event code is simply not executed, without any hint to why it is not working. As using try/catch in the code does not help, it seems that the code is somehow checked before being executed. And the output of this check does not seem to be logged.

Oleg-O commented 2 weeks ago

@GruberMarkus great job identifying the cause of this issue. Yes, insufficient logging in this case is a known issue but the good news is that there is work currently in progress to improve that.

Regarding atob() - where was the problematic implementation coming from?

GruberMarkus commented 1 week ago

I was just calling atob() to decode the JWT token provided by NAA, so that the scopes can be checked.

While calling atob() leads to the situation described above that the launch event does not even start the associated function, it works fine when calling atobPolyfill() (defined in https://github.com/OfficeDev/office-js/issues/4780#issuecomment-2311870073).

The root cause could be that atob() is a member of the Window interface, and maybe there is no Window interface in a launch event on Classic Outlook on Windows as the code is not executed in a browser. That would also explain why atob() works fine when used in a taskpane, which runs in a browser environment with a Window interface.

davidchesnut commented 4 days ago

Glad to hear this is working for you! I'll go ahead and close the issue. Thanks!

emmasab commented 5 hours ago

The fix so that atob can work with Nested App Auth is now in the beta channel.

Note that the V8 engine does not support atob, so it will not be supported in the JS runtime outside of the Nested App Auth scenario and we recommend developers that have a dependency on atob add their own polyfill.