在发送邮件之前自动检查附件

再也不会错过将重要文档或照片附加到邮件中。 使用基于事件的加载项时,邮件在发送前会自动检查附件,以便你可以放心地始终发送完整版本。

以下部分介绍如何开发实现 智能警报 来处理事件的 OnMessageSend 基于事件的外接程序。 在本演练结束时,加载项将自动检查邮件中提及的附加文档或图片,并在发送邮件之前提醒你是否缺少该文档或图片。

注意

OnMessageSendOnAppointmentSend 事件在要求集 1.12 中引入。 若要验证 Outlook 客户端是否支持这些事件,请参阅 支持的客户端和平台

设置环境

在开始演练之前,请验证 Outlook 客户端是否支持智能警报功能。 有关指导,请参阅 支持的客户端和平台

然后,完成 Outlook 快速入门,该快速入门使用 Office 加载项的 Yeoman 生成器创建加载项项目。

配置清单

若要配置清单,请选择要使用的清单类型的选项卡。

  1. 打开 manifest.json 文件。

  2. 将以下 对象添加到“extensions.runtimes”数组。 关于此标记,请注意以下几点:

    • 邮箱要求集的“minVersion”设置为“1.12”,因为 支持的事件表 指定这是支持该 OnMessageSend 事件的要求集的最低版本。
    • 运行时的“id”设置为描述性名称“autorun_runtime”。
    • “code”属性具有设置为 HTML 文件的子“page”属性,以及设置为 JavaScript 文件的子“script”属性。 稍后的步骤将创建或编辑这些文件。 Office 使用这些值之一或另一个值,具体取决于平台。
      • 经典 Outlook on Windows 在仅限 JavaScript 的运行时中执行事件处理程序,该运行时直接加载 JavaScript 文件。
      • Outlook 网页版、Mac 版和新 Outlook on Windows (预览版) 浏览器运行时执行处理程序,这将加载 HTML 文件。 该文件又包含一个 <script> 用于加载 JavaScript 文件的标记。 有关详细信息,请参阅 Office 外接程序中的运行时
    • “lifetime”属性设置为“short”,这意味着运行时在触发事件时启动,并在处理程序完成时关闭。 (在某些情况下,运行时在处理程序完成之前关闭。请参阅 Office Add-ins.) 中的运行时
    • 有一个操作可运行 OnMessageSend 事件的处理程序。 你将在后面的步骤中创建处理程序函数。
     {
        "requirements": {
            "capabilities": [
                {
                    "name": "Mailbox",
                    "minVersion": "1.12"
                }
            ]
        },
        "id": "autorun_runtime",
        "type": "general",
        "code": {
            "page": "https://localhost:3000/commands.html",
            "script": "https://localhost:3000/launchevent.js"
        },
        "lifetime": "short",
        "actions": [
            {
                "id": "onMessageSendHandler",
                "type": "executeFunction",
                "displayName": "onMessageSendHandler"
            }
        ]
    }
    
  3. 将以下“autoRunEvents”数组添加为“extensions”数组中的 对象的属性。

    "autoRunEvents": [
    
    ]
    
  4. 将以下 对象添加到“autoRunEvents”数组。 关于此代码,请注意以下几点:

    • 事件对象使用事件的统一清单名称“messageSending”将处理程序函数 OnMessageSend 分配给事件 (,如 支持的事件表) 中所述。 “actionId”中提供的函数名称必须与前面步骤中“actions”数组中对象的“id”属性中使用的名称匹配。
    • “sendMode”选项设置为“softBlock”。 这意味着,如果消息不符合加载项设置的发送条件,则用户必须先执行操作,然后才能发送邮件。 但是,如果加载项在发送时不可用,则会发送该项目。
      {
          "requirements": {
              "capabilities": [
                  {
                      "name": "Mailbox",
                      "minVersion": "1.12"
                  }
              ],
              "scopes": [
                  "mail"
              ]
          },
          "events": [
            {
                "type": "messageSending",
                "actionId": "onMessageSendHandler",
                "options": {
                    "sendMode": "softBlock"
                }
            }
          ]
      }
    

提示

实现事件处理

必须对所选事件实现处理。

在此方案中,你将添加用于发送邮件的处理。 加载项将在消息中检查某些关键字。 如果找到这些关键字中的任何一个,它将检查是否存在任何附件。 如果没有附件,外接程序将建议用户添加可能缺少的附件。

  1. 在同一个快速入门项目中,在 ./src 目录下创建名为 startvent 的新文件夹。

  2. ./src/startvent 文件夹中,创建一个名为 launchevent.js的新文件。

  3. 在代码编辑器中打开文件 ./src/startvent/launchevent.js 并添加以下 JavaScript 代码。

    /*
    * Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
    * See LICENSE in the project root for license information.
    */
    
    function onMessageSendHandler(event) {
      Office.context.mailbox.item.body.getAsync(
        "text",
        { asyncContext: event },
        getBodyCallback
      );
    }
    
    function getBodyCallback(asyncResult){
      const event = asyncResult.asyncContext;
      let body = "";
      if (asyncResult.status !== Office.AsyncResultStatus.Failed && asyncResult.value !== undefined) {
        body = asyncResult.value;
      } else {
        const message = "Failed to get body text";
        console.error(message);
        event.completed({ allowEvent: false, errorMessage: message });
        return;
      }
    
      const matches = hasMatches(body);
      if (matches) {
        Office.context.mailbox.item.getAttachmentsAsync(
          { asyncContext: event },
          getAttachmentsCallback);
      } else {
        event.completed({ allowEvent: true });
      }
    }
    
    function hasMatches(body) {
      if (body == null || body == "") {
        return false;
      }
    
      const arrayOfTerms = ["send", "picture", "document", "attachment"];
      for (let index = 0; index < arrayOfTerms.length; index++) {
        const term = arrayOfTerms[index].trim();
        const regex = RegExp(term, 'i');
        if (regex.test(body)) {
          return true;
        }
      }
    
      return false;
    }
    
    function getAttachmentsCallback(asyncResult) {
      const event = asyncResult.asyncContext;
      if (asyncResult.value.length > 0) {
        for (let i = 0; i < asyncResult.value.length; i++) {
          if (asyncResult.value[i].isInline == false) {
            event.completed({ allowEvent: true });
            return;
          }
        }
    
        event.completed({
          allowEvent: false,
          errorMessage: "Looks like the body of your message includes an image or an inline file. Attach a copy to the message before sending."
        });
      } else {
        event.completed({
          allowEvent: false,
          errorMessage: "Looks like you're forgetting to include an attachment."
        });
      }
    }
    
    // IMPORTANT: To ensure your add-in is supported in the Outlook client on Windows, remember to map the event handler name specified in the manifest to its JavaScript counterpart.
    if (Office.context.platform === Office.PlatformType.PC || Office.context.platform == null) {
      Office.actions.associate("onMessageSendHandler", onMessageSendHandler);
    }
    

重要

开发在 Outlook on Windows 中运行的智能警报加载项时,请记住以下几点。

  • 在 JavaScript 文件中,你实现基于事件的激活的处理,目前不支持导入。
  • 若要确保加载项在 Windows 版 Outlook 中发生 或 事件时OnMessageSend按预期运行,请在实现处理程序的 JavaScript 文件中调用 Office.actions.associateOnAppointmentSend 这会将清单中指定的事件处理程序名称映射到其 JavaScript 对应名称。 如果此调用未包含在 JavaScript 文件中,并且清单的发送模式属性设置为 软阻止 或未指定,则会阻止用户发送消息或会议。

自定义可选) (预览) (“不发送”按钮

注意

不发送 ”按钮自定义功能目前在 Outlook on Windows 中处于预览状态。 不应在生产加载项中使用预览版功能。我们邀请你在测试或开发环境中试用此功能,并欢迎通过 GitHub 提供有关体验的反馈 (请参阅本页末尾的 反馈 部分) 。

若要在 Outlook on Windows 中预览此功能,必须安装版本 2308 (内部版本 16731.20000) 或更高版本。 然后,加入 Microsoft 365 预览体验计划 ,并选择 “Beta 频道” 选项以访问 Office beta 版本。

如果邮件项不符合智能警报加载项的条件,则会向用户显示一个对话框,提醒他们在发送项目之前可能需要执行其他操作。 清单中指定的 发送模式选项 确定在对话框中向用户显示的选项。 无论选择哪种发送模式选项,对话框中都会出现“ 发送”选项。 默认情况下,选择“ 不发送” 会取消发送操作并关闭对话框。 若要为用户提供有关如何满足加载项条件的进一步指导,请自定义此按钮的文本并对其进行编程以打开任务窗格,可在其中提供其他信息和功能。

修改“不发送”按钮文本和功能

若要修改“ 不要发送 ”按钮的文本或为其分配任务窗格命令,必须在事件处理程序的 event.completed 方法中设置其他选项。

  • cancelLabel 选项自定义“不发送”按钮的文本。 自定义文本必须最多包含 20 个字符。

  • commandId 选项指定在选择“不发送”按钮时打开的任务窗格的 ID。 该值必须与外接程序清单中的任务窗格 ID 匹配。 标记取决于外接程序使用的清单类型。

    • XML 清单id 表示任务窗格的 <Control> 元素的属性。
    • Microsoft 365 (预览版的统一清单) :“controls”数组中任务窗格命令的“id”属性。
  • contextData 选项指定要在选中“不发送”按钮时传递给外接程序的任何 JSON 数据。 如果包含此选项,还必须设置 commandId 选项。 否则,将忽略 JSON 数据。

    提示

    若要检索选项的值,必须在任务窗格的 contextData JavaScript 实现中调用 Office.context.mailbox.item.getInitializationContextAsync

  1. 导航到 ./src/startvent 文件夹,然后打开 launchevent.js

  2. getAttachmentsCallback 函数替换为以下代码。

    function getAttachmentsCallback(asyncResult) {
      const event = asyncResult.asyncContext;
      if (asyncResult.value.length > 0) {
        for (let i = 0; i < asyncResult.value.length; i++) {
          if (asyncResult.value[i].isInline == false) {
            event.completed({ allowEvent: true });
            return;
          }
        }
    
        event.completed({
          allowEvent: false,
          errorMessage: "Looks like the body of your message includes an image or an inline file. Attach a copy to the message before sending.",
          cancelLabel: "Add an attachment",
          commandId: "msgComposeOpenPaneButton"
        });
      } else {
        event.completed({
          allowEvent: false,
          errorMessage: "Looks like you're forgetting to include an attachment.",
          cancelLabel: "Add an attachment",
          commandId: "msgComposeOpenPaneButton"
        });
      }
    }
    
  3. 保存所做的更改。

在运行时重写发送模式选项 (可选的) (预览)

注意

“发送模式”选项替代功能目前在 Outlook on Windows 中处于预览状态。 不应在生产加载项中使用预览版功能。我们邀请你在测试或开发环境中试用此功能,并欢迎通过 GitHub 提供有关体验的反馈 (请参阅本页末尾的 反馈 部分) 。

若要在 Outlook on Windows 中预览此功能,必须安装版本 2308 (内部版本 16731.20000) 或更高版本。 然后,加入 Microsoft 365 预览体验计划 ,并选择 “Beta 频道” 选项以访问 Office beta 版本。

当希望加载项实现不同的发送模式选项时,可能会出现一种情况。 例如,你可能希望外接程序对不符合组织信息保护策略的邮件项目强制实施 阻止 选项,但仅让用户应用 提示用户 选项,以便在用户添加不正确的收件人时提供建议。

若要在运行时替代发送模式选项,必须在事件处理程序的 方法中event.completed设置 sendModeOverride 选项。

  1. 导航到 ./src/startvent 文件夹,然后打开 launchevent.js

  2. getAttachmentsCallback 函数替换为以下代码。

    function getAttachmentsCallback(asyncResult) {
      const event = asyncResult.asyncContext;
      if (asyncResult.value.length > 0) {
        for (let i = 0; i < asyncResult.value.length; i++) {
          if (asyncResult.value[i].isInline == false) {
            event.completed({ allowEvent: true });
            return;
          }
        }
    
        event.completed({
          allowEvent: false,
          errorMessage: "Looks like the body of your message includes an image or an inline file. Would you like to attach a copy of it to the message?",
          cancelLabel: "Attach a copy",
          commandId: "msgComposeOpenPaneButton",
          sendModeOverride: Office.MailboxEnums.SendModeOverride.PromptUser
        });
      } else {
        event.completed({
          allowEvent: false,
          errorMessage: "Looks like you're forgetting to include an attachment.",
          cancelLabel: "Add an attachment",
          commandId: "msgComposeOpenPaneButton"
        });
      }
    }
    
  3. 保存所做的更改。

配置任务窗格 (可选)

如果在本演练中实现了自定义 “不发送 ”按钮或替代发送模式选项的可选步骤,则还需要配置任务窗格。 尽管此实现中需要任务窗格,但不需要自定义“ 不发送 ”按钮的文本或重写发送模式选项。

  1. 导航到 ./src/taskpane 文件夹,然后打开 taskpane.html

  2. 选择整个 <正文> 节点 (包括其打开和关闭标记) ,并将其替换为以下代码。

    <body class="ms-welcome ms-Fabric">
        <header class="ms-welcome__header ms-bgColor-neutralLighter">
            <img width="90" height="90" src="../../assets/logo-filled.png" alt="Contoso" title="Contoso" />
            <h1 class="ms-font-su">Try out the Smart Alerts sample</h1>
        </header>
        <section id="sideload-msg" class="ms-welcome__main">
            <h2 class="ms-font-xl">Please <a href="https://learn.microsoft.com/office/dev/add-ins/testing/test-debug-office-add-ins#sideload-an-office-add-in-for-testing">sideload</a> your add-in to see app body.</h2>
        </section>
        <main id="app-body" class="ms-welcome__main" style="display: none;">
            <p>
                This sample implements a Smart Alerts add-in that activates when you forget to attach a document or picture that you mention in your message.
                To learn more, see the <a href="https://learn.microsoft.com/office/dev/add-ins/outlook/smart-alerts-onmessagesend-walkthrough">Smart Alerts walkthrough</a>.
            </p>
            <h3 class="ms-font-l">Add an attachment</h3>
            <p>Add the URL of a file to add it as an attachment.</p>
            <div class="ms-TextField">
                <label class="ms-Label ms-font-l">URL of file:</label>
                <input id="attachment-url" class="ms-TextField-field" type="text" value="https://localhost:3000/assets/icon-128.png" placeholder="">
            </div>
            <br/>
            <button class="ms-Button ms-Button--primary">
                <span id="add-attachment" class="ms-Button-label">Add as attachment</span>
            </button>
            <br/>
            <h3 class="ms-font-l">Override the send mode option at runtime</h3>
            <p>Add an inline image to test overriding the send mode option at runtime.</p>
            <button class="ms-Button ms-Button--primary">
                <span id="add-inline-image" class="ms-Button-label">Add an inline image</span>
            </button>
        </main>
    </body>
    
  3. 保存所做的更改。

  4. 在同一 个 ./src/taskpane 文件夹中,打开 taskpane.js

  5. 将其内容替换为以下代码。

    /*
     * Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
     * See LICENSE in the project root for license information.
     */
    
    Office.onReady((info) => {
      if (info.host === Office.HostType.Outlook) {
        document.getElementById("sideload-msg").style.display = "none";
        document.getElementById("app-body").style.display = "flex";
        document.getElementById("add-attachment").onclick = addAttachment;
        document.getElementById("add-inline-image").onclick = addInlineImage;
      }
    });
    
    // Adds the specified URL as an attachment to the message.
    export async function addAttachment() {
      const attachmentUrl = document.querySelector("#attachment-url").value;
      Office.context.mailbox.item.addFileAttachmentAsync(attachmentUrl, getFileName(attachmentUrl), (asyncResult) => {
        console.log(asyncResult);
      });
    }
    
    // Gets the file name from a URL.
    function getFileName(url) {
      const lastIndex = url.lastIndexOf("/");
      if (lastIndex >= 0) {
        return url.substring(lastIndex + 1);
      }
    
      return url;
    }
    
    // Adds an inline image to the body of the message.
    export async function addInlineImage() {
      const mailItem = Office.context.mailbox.item;
      const base64String =
        "iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAMAAADVRocKAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAnUExURQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAN0S+bUAAAAMdFJOUwAQIDBAUI+fr7/P7yEupu8AAAAJcEhZcwAADsMAAA7DAcdvqGQAAAF8SURBVGhD7dfLdoMwDEVR6Cspzf9/b20QYOthS5Zn0Z2kVdY6O2WULrFYLBaLxd5ur4mDZD14b8ogWS/dtxV+dmx9ysA2QUj9TQRWv5D7HyKwuIW9n0vc8tkpHP0W4BOg3wQ8wtlvA+PC1e8Ao8Ld7wFjQtHvAiNC2e8DdqHqKwCrUPc1gE1AfRVgEXBfB+gF0lcCWoH2tYBOYPpqQCNwfT3QF9i+AegJfN8CtAWhbwJagtS3AbIg9o2AJMh9M5C+SVGBvx6zAfmT0r+Bv8JMwP4kyFPir+cswF5KL3WLv14zAFBCLf56Tw9cparFX4upgaJUtPhrOS1QlY5W+vWTXrGgBFB/b72ev3/0igUdQPppP/nfowfKUUEFcP207y/yxKmgAYQ+PywoAFOfCH3A2MdCFzD3kdADBvq10AGG+pXQBgb7pdAEhvuF0AIc/VtoAK7+JciAs38KIuDugyAC/v4hiMCE/i7IwLRBsh68N2WQjMVisVgs9i5bln8LGScNcCrONQAAAABJRU5ErkJggg==";
    
      // Gets the current body of the message.
      mailItem.body.getAsync(Office.CoercionType.Html, (bodyResult) => {
        if (bodyResult.status === Office.AsyncResultStatus.Failed) {
          console.log(bodyResult.error.message);
          return;
        }
    
        // Inserts the Base64-encoded image to the beginning of the body.
        const options = { isInline: true, asyncContext: bodyResult.value };
        mailItem.addFileAttachmentFromBase64Async(base64String, "sample.png", options, (attachResult) => {
          if (attachResult.status === Office.AsyncResultStatus.Failed) {
            console.log(attachResult.error.message);
            return;
          }
    
          let body = attachResult.asyncContext;
          body = body.replace("<p class=MsoNormal>", `<p class=MsoNormal><img src="cid:sample.png">`);
          mailItem.body.setAsync(body, { coercionType: Office.CoercionType.Html }, (setResult) => {
            if (setResult.status === Office.AsyncResultStatus.Failed) {
              console.log(setResult.error.message);
              return;
            }
    
            console.log("Inline image added to the body.");
          });
        });
      });
    }
    
  6. 保存所做的更改。

更新命令 HTML 文件

  1. ./src/commands 文件夹中,打开 commands.html

  2. 紧接 () 结束 标记 </head> 之前,为事件处理 JavaScript 代码添加脚本条目。

    <script type="text/javascript" src="../launchevent/launchevent.js"></script> 
    

重要

不发送 ”按钮自定义和发送模式选项替代功能目前在 Outlook on Windows 中处于预览状态。 如果要在外接程序项目中测试这些功能,则必须在 commands.html 文件中包含对 Office JavaScript API 预览版的引用。

<script type="text/javascript" src="https://appsforoffice.microsoft.com/lib/beta/hosted/office.js"></script>
<script type="text/javascript" src="../launchevent/launchevent.js"></script>
  1. 保存所做的更改。

更新 webpack 配置设置

  1. 打开在项目的根目录中找到的 webpack.config.js 文件,然后完成以下步骤。

  2. plugins在 对象中找到数组,config并将此新对象添加到数组的开头。

    new CopyWebpackPlugin({
      patterns: [
        {
          from: "./src/launchevent/launchevent.js",
          to: "launchevent.js",
        },
      ],
    }),
    
  3. 保存所做的更改。

试用

  1. 在项目的根目录中运行以下命令。 运行 npm start时,如果本地 Web 服务器尚未运行) 并且加载项将被旁加载,则本地 Web 服务器将启动 (。

    npm run build
    
    npm start
    

    注意

    如果加载项未自动旁加载,请按照 旁加载 Outlook 外接程序 中的说明进行测试,在 Outlook 中手动旁加载加载项。

  2. 在首选 Outlook 客户端中,创建新邮件并设置主题。 在正文中,添加一些文本。 例如,“下面是建议的徽标的图片。

  3. 发送消息。 此时会显示一个对话框,要求添加附件。 选择 “不发送 ”或 “添加附件”。 可用的选项取决于是否实现了可选步骤来自定义 “不发送 ”按钮。

    • 默认 “不发送 ”按钮。

      请求用户向邮件添加附件的对话框。

    • 自定义 “添加附件 ”按钮。

      带有自定义的“不发送”按钮的对话框,请求用户向邮件添加附件。

    提示

    如果将任务窗格分配给“ 不发送 ”按钮,关闭对话框也会打开指定的任务窗格。

  4. 向邮件添加附件。 如果实现了可选步骤来自定义“ 不发送 ”按钮,请使用任务窗格添加附件。

    任务窗格,其中包含用于添加附件的选项。

  5. 发送消息。 这次应该不会有警报。

尝试在运行时重写发送模式选项, (可选)

如果实现了可选步骤以在运行时替代发送模式选项,请执行下列操作来试用。

  1. 在项目的根目录中运行 npm start 。 如果本地 Web 服务器尚未运行) 并旁加载加载项,则会启动本地 Web 服务器 (。

    注意

    如果加载项未自动旁加载,请按照 旁加载 Outlook 外接程序 中的说明进行测试,在 Outlook 中手动旁加载加载项。

  2. 在 Outlook on Windows 中,创建新邮件并设置主题。 在正文中,添加一些文本。 例如,“下面是建议的徽标的图片。

  3. 在功能区中,选择“ Contoso 外接程序>显示任务窗格”。

  4. 在任务窗格中,选择 “添加内联图像”。 图像将添加到邮件正文。

  5. 发送消息。 此时会显示一个对话框,建议将图像的副本附加到邮件。

  6. 选择“ 仍然发送” 以按原样发送邮件,或在发送邮件前选择“ 附加 副本”以包含副本。

    “智能警报”对话框,在运行时提供“仍然发送”选项。

重要

如果实现替代功能的智能警报加载项由于错误而无法完成事件处理,或者在事件发生时不可用,它将使用清单中指定的发送模式选项。

另请参阅