0

I’m working on developing my first Add-In for Outlook 365/Windows 10. In theory, it’s quite simple—it’s a drop-down menu with two options. Each option opens a new email and loads a different template, depending on the selection.

So far, the menu is functioning smoothly. Selecting option A displays the corresponding template, and the same goes for option B.

However, I’m facing a problem: I can’t get the user’s signature to load automatically as expected, even though the signature is properly configured and set as the default for new emails.

Attached you will find my manifest.xml and commands.ts

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<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/1.0" xsi:type="MailApp">
<Id>2eb95a7a-bc4a-4f53-bc6f-ba64b72d8663</Id>
<Version>1.0.0.0</Version>
<ProviderName>Contoso</ProviderName>
<DefaultLocale>en-US</DefaultLocale>
<DisplayName DefaultValue="NewClientMatter"/>
<Description DefaultValue="A template to get started."/>
<IconUrl DefaultValue="https://localhost:3000/assets/icon-64.png"/>
<HighResolutionIconUrl DefaultValue="https://localhost:3000/assets/icon-128.png"/>
<SupportUrl DefaultValue="https://www.contoso.com/help"/>
<AppDomains>
<AppDomain>https://www.contoso.com</AppDomain>
</AppDomains>
<Hosts>
<Host Name="Mailbox"/>
</Hosts>
<Requirements>
<Sets>
<Set Name="Mailbox" MinVersion="1.5"/>
</Sets>
</Requirements>
<FormSettings>
<Form xsi:type="ItemRead">
<DesktopSettings>
<SourceLocation DefaultValue="https://localhost:3000/taskpane.html"/>
<RequestedHeight>250</RequestedHeight>
</DesktopSettings>
</Form>
</FormSettings>
<Permissions>ReadWriteItem</Permissions>
<Rule xsi:type="RuleCollection" Mode="Or">
<Rule xsi:type="ItemIs" ItemType="Message" FormType="Read"/>
<Rule xsi:type="ItemIs" ItemType="Message" FormType="Edit"/>
</Rule>
<DisableEntityHighlighting>false</DisableEntityHighlighting>
<VersionOverrides xmlns="http://schemas.microsoft.com/office/mailappversionoverrides" xsi:type="VersionOverridesV1_0">
<Requirements>
<bt:Sets DefaultMinVersion="1.5">
<bt:Set Name="Mailbox"/>
</bt:Sets>
</Requirements>
<Hosts>
<Host xsi:type="MailHost">
<DesktopFormFactor>
<FunctionFile resid="Commands.Url"/>
<ExtensionPoint xsi:type="MessageReadCommandSurface">
<OfficeTab id="TabDefault">
<Group id="msgReadGroup">
<Label resid="GroupLabel"/>
<Control xsi:type="Menu" id="DropdownMenu">
<Label resid="DropdownMenu.Label"/>
<Supertip>
<Title resid="DropdownMenu.Label"/>
<Description resid="DropdownMenu.Tooltip"/>
</Supertip>
<Icon>
<bt:Image size="16" resid="MenuIcon.16x16"/>
<bt:Image size="32" resid="MenuIcon.32x32"/>
<bt:Image size="80" resid="MenuIcon.80x80"/>
</Icon>
<Items>
<Item id="InternalAction">
<Label resid="InternalAction.Label"/>
<Supertip>
<Title resid="InternalAction.Label"/>
<Description resid="InternalAction.Tooltip"/>
</Supertip>
<Icon>
<bt:Image size="16" resid="InternalIcon.16x16"/>
<bt:Image size="32" resid="InternalIcon.32x32"/>
<bt:Image size="80" resid="InternalIcon.80x80"/>
</Icon>
<Action xsi:type="ExecuteFunction">
<FunctionName>handleInternalAction</FunctionName>
</Action>
</Item>
<Item id="ExternalAction">
<Label resid="ExternalAction.Label"/>
<Supertip>
<Title resid="ExternalAction.Label"/>
<Description resid="ExternalAction.Tooltip"/>
</Supertip>
<Icon>
<bt:Image size="16" resid="ExternalIcon.16x16"/>
<bt:Image size="32" resid="ExternalIcon.32x32"/>
<bt:Image size="80" resid="ExternalIcon.80x80"/>
</Icon>
<Action xsi:type="ExecuteFunction">
<FunctionName>handleExternalAction</FunctionName>
</Action>
</Item>
</Items>
</Control>
</Group>
</OfficeTab>
</ExtensionPoint>
</DesktopFormFactor>
</Host>
</Hosts>
<Resources>
<bt:Images>
<bt:Image id="MenuIcon.16x16" DefaultValue="https://localhost:3000/assets/menu-icon-16.png"/>
<bt:Image id="MenuIcon.32x32" DefaultValue="https://localhost:3000/assets/menu-icon-32.png"/>
<bt:Image id="MenuIcon.80x80" DefaultValue="https://localhost:3000/assets/menu-icon-80.png"/>
<bt:Image id="InternalIcon.16x16" DefaultValue="https://localhost:3000/assets/int-16.png"/>
<bt:Image id="InternalIcon.32x32" DefaultValue="https://localhost:3000/assets/int-32.png"/>
<bt:Image id="InternalIcon.80x80" DefaultValue="https://localhost:3000/assets/int-80.png"/>
<bt:Image id="ExternalIcon.16x16" DefaultValue="https://localhost:3000/assets/ext-16.png"/>
<bt:Image id="ExternalIcon.32x32" DefaultValue="https://localhost:3000/assets/ext-32.png"/>
<bt:Image id="ExternalIcon.80x80" DefaultValue="https://localhost:3000/assets/ext-80.png"/>
</bt:Images>
<bt:Urls>
<bt:Url id="Commands.Url" DefaultValue="https://localhost:3000/commands.html"/>
<bt:Url id="Taskpane.Url" DefaultValue="https://localhost:3000/taskpane.html"/>
<bt:Url id="CommandsJs.Url" DefaultValue="https://localhost:3000/commands/commands.js"/>
</bt:Urls>
<bt:ShortStrings>
<bt:String id="GroupLabel" DefaultValue="New Client/Matter"/>
<bt:String id="DropdownMenu.Label" DefaultValue="Choose Action"/>
<bt:String id="InternalAction.Label" DefaultValue="Internal"/>
<bt:String id="ExternalAction.Label" DefaultValue="External"/>
</bt:ShortStrings>
<bt:LongStrings>
<bt:String id="DropdownMenu.Tooltip" DefaultValue="Select an action to perform."/>
<bt:String id="InternalAction.Tooltip" DefaultValue="Opens an internal email template."/>
<bt:String id="ExternalAction.Tooltip" DefaultValue="Opens an external email template."/>
</bt:LongStrings>
</Resources>
</VersionOverrides>
</OfficeApp>

commands.ts

/* global Office */

Office.onReady(function (info) {
  if (info.host === Office.HostType.Outlook) {
    Office.actions.associate("handleInternalAction", handleInternalAction);
    Office.actions.associate("handleExternalAction", handleExternalAction);
  }
});

/**
 * Handles the "Internal" action.
 * @param event The Office Add-in event.
 */
function handleInternalAction(event: Office.AddinCommands.Event): void {
  openEmailTemplate("internal", event);
}

/**
 * Handles the "External" action.
 * @param event The Office Add-in event.
 */
function handleExternalAction(event: Office.AddinCommands.Event): void {
  openEmailTemplate("external", event);
}

/**
 * Opens an email template with the user's signature.
 * @param templateType The type of template ("internal" or "external").
 * @param event The Office Add-in event.
 */
function openEmailTemplate(templateType: string, event: Office.AddinCommands.Event): void {
  let templateBody: string;
  let subject: string;
  
  if (templateType === "internal") {
    templateBody = `
      My fields<br/><br/>
    `;
    subject = "(Internal)";
  } else if (templateType === "external") {
    templateBody = `
      My fields<br/><br/>
    `;
    subject = "(External)";
  } else {
    console.error("Invalid template type specified:", templateType);
    event.completed();
    return;
  }

  // Open a new email draft
  Office.context.mailbox.displayNewMessageForm({
    subject,
    htmlBody: templateBody,
  });

  // Function to check draft readiness and insert the signature
  const checkDraftReady = () => {
    Office.context.mailbox.item.body.getAsync(Office.CoercionType.Html, (result) => {
      if (result.status === Office.AsyncResultStatus.Succeeded) {
        const userSignature = result.value || "";
        if (userSignature) {
          const combinedBody = `
            <html>
              <head>
                <meta charset="utf-8">
              </head>
              <body>
                ${templateBody}  <!-- Template Body -->
                <br/><br/>
                ${userSignature}  <!-- User Signature -->
              </body>
            </html>
          `;

          Office.context.mailbox.item.body.setAsync(
            combinedBody,
            { coercionType: Office.CoercionType.Html },
            (setResult) => {
              if (setResult.status !== Office.AsyncResultStatus.Succeeded) {
                console.error("Failed to set email body:", setResult.error);
              }
              event.completed();  // Ensure event is completed after the set operation
            }
          );
        } else {
          console.warn("User's signature not available.");
          event.completed();
        }
      } else {
        console.error("Failed to get user's signature. Retrying...", result.error);
        setTimeout(checkDraftReady, 500); // Retry after a short delay
      }
    });
  };

  setTimeout(checkDraftReady, 500); // Initial retry delay
}

Thank you so much for your support!

10
  • Do you mean userSignature comes up empty? Commented Dec 5, 2024 at 21:12
  • Hello @DmitryStreblechenko, Thank you for your reply. The signature is not visible, I think it comes empty. Commented Dec 6, 2024 at 17:42
  • Try to verify under the debugger. Outlook inserts the signature asynchronously after the message is shown as long as the message body is not modified. Also keep in mind that you cannot concatenate two well-formed HTML documents and expect a valid HTML document as the result; the two must be merged. Commented Dec 6, 2024 at 22:15
  • Hello, Thank you for replying. Your perspective is very valid, and I hadn’t really thought about it. Maybe that’s the problem? I’m essentially working with two HTML objects: the email template, which is created as you can see in real time inside the commands.TS, and the signature, which is another HTML object. Could you guide me on how you think I could merge the template with the signature into a single object? Thank you very much, Commented Dec 10, 2024 at 15:59
  • Firstly, try to verify in the debugger that you do get the signature HTML. The easiest way to merge two HTML strings is to find the position of the <body> tag (or </body> depending on where you are inserting) in one HTML string, then insert the value between the <body> and </body> tags of the second HTML string. You'll lose the styles defined in the header, but you can deal with that too. Commented Dec 10, 2024 at 16:14

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.