2017 年 8 月

第 32 卷,第 8 期

本文章是由機器翻譯。

Microsoft Office - Outlook 可採取動作的郵件

Woon Kiat Kiat|2017 年 8 月

我喜歡電子郵件。工作、 已放入頂端發生什麼事,以及哪些我在哪裡尋求必須進行。它會接收 noti-fications 新等我的小組,對我推文,新的註解為我的提取要求的新回覆所提交的經費支出報表。但是,電子郵件可能是比較好。為什麼需要按一下電子郵件中的連結,然後等待財務系統網站,我可以核准經費支出報表之前,在瀏覽器中載入? 為什麼必須心理變更我的內容? 我可以核准直接在我的電子郵件用戶端的內容中的經費支出報表。

聽起來很熟悉嗎? Outlook 會讓您的生活更好,節省您的時間,並讓您更有效率。

介紹可採取動作的訊息

可採取動作的訊息,讓使用者在完成電子郵件本身內的工作。它提供原生的體驗,在 Outlook 桌面用戶端和 Outlook Web Access (OWA)。在本文中,我將使用 word Outlook 表示 Outlook 桌面用戶端或 OWA。

在範例中使用,虛構公司 Contoso 有內部的經費支出核准系統。每次員工提交經費支出報表時,電子郵件訊息傳送給管理員核准。我如何使用 Outlook,可讓核准內電子郵件訊息 it-自助要求的管理員可採取動作的訊息會逐步執行的步驟。

我的第一個可採取動作訊息

圖 1,您會看到可採取動作的訊息的 HTML。它可能會看起來很複雜,但我認為,則不是。我將說明下列各節中詳細的標記。第一個步驟是傳送電子郵件以從標記圖 1 Office 365 電子郵件帳戶。

圖 1 HTML 的 Outlook 可採取動作訊息

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf8">
    <script type="application/ld+json">{
      "@context": "http://schema.org/extensions",
      "@type": "MessageCard",
      "hideOriginalBody": "true",
      "title": "Expense report is pending your approval",
      "sections": [{
        "text": "Please review the expense report below.",
        "facts": [{
          "name": "ID",
          "value": "98432019"
        }, {
          "name": "Amount",
          "value": "83.27 USD"
        }, {
          "name": "Submitter",
          "value": "Kathrine Joseph"
        }, {
          "name": "Description",
          "value": "Dinner with client"
        }]
      }],
      "potentialAction": [{
        "@type": "HttpPost",
        "name": "Approve",
        "target": ""
      }, {
        "@type": "OpenUri",
        "name": "View Expense",
        "targets": [ { "os": "default", 
        "uri": "https://expense.contoso.com/view?id=98432019"} ]
      }]
    }
    </script>
  </head>
  <body>
    <p>Please <a href="https://expense.contoso.com/view?id=98432019">approve</a> 
      expense report #98432019 for $83.27.</p>
  </body>
</html>

中所示圖 2,在訊息本身中沒有訊息卡片具有兩個按鈕,您可以與之互動。如果您按一下 [核准] 按鈕時,它會導致錯誤現在因為還沒指定動作的 URL。您稍後會加入 URL。如果您按一下 [檢視費用報表] 按鈕,瀏覽器會開啟,並瀏覽至經費支出核准網站。

在 Outlook Web Access 可採取動作的訊息
圖 2 中 Outlook Web Access 可採取動作的訊息

MessageCard 標記

電子郵件訊息本身是典型的 HTML 標記。若要在 Outlook 中,讓它可採取動作的訊息,您可以插入訊息卡標記 < 指令碼 > 元素中。這種方法的主要優點之一是訊息將會繼續如往常般呈現不認得 MessageCard 標記的用戶端上該電子郵件。此標記的格式稱為 JSON LD,這是標準格式,若要建立透過網際網路的電腦可讀取的資料。現在,我們再逐行詳細資料中的標記。這些兩行程式碼會強制在每個標記中:

"@context": "http://schema.org/extensions",
"@type": "MessageCard",

您將內容設定為 http://schema.org/extensions 並輸入要 「 MessageCard。 」 MessageCard 類型表示此電子郵件是可採取動作的訊息。

接下來是將屬性"hideOriginalBody。 」 隱藏的值設為 true 時,電子郵件內文,並且只卡會顯示,如中所示圖 2。卡本身包含的使用者會需要的所有資訊時,這非常有用,或智慧卡的內容是多餘的電子郵件本文的內容。如果不了解訊息卡片的電子郵件用戶端中檢視訊息,然後將顯示原始的主體和訊息卡不是,將"hideOriginalBody。 」 的值為何 屬性"title"的值是 MessageCard 標題:

"hideOriginalBody": "true",
"title": "Expense report is pending your approval",

接下來是 「 區段 」。 您可以將一個區段,以表示 「 活動 」。 如果您的卡片具有多個活動,您應該明確地使用多個區段,其中每個活動。圖 3 顯示一個區段的標記。您可以使用事實的區段的屬性,也就是名稱 / 值組的陣列,以顯示 [費用報表的詳細資料。

圖 3 卡具有一個區段

"sections": [{
  "text": "Please review the expense report below.",
  "facts": [{
    "name": "ID",
    "value": "98432019"
  }, {
    "name": "Amount",
    "value": "83.27 USD"
  }, {
    "name": "Submitter",
    "value": "Jonathan Kiev"
  }, {
    "name": "Description",
    "value": "Dinner with client"
  }]
}],

接下來是"potentialAction。 」 這是可以在這張介面卡叫用的動作陣列。目前支援的動作而 OpenUri HttpPOST:

"potentialAction": [{
  "@type": "HttpPost",
  "name": "Approve",
  "target": ""
}, {
  "@type": "OpenUri",
  "name": "View Expense",
  "targets": [ { "os": "default",
  "uri": "https://expense.contoso.com/view?id=98432019"} ]
}]

OpenUri 動作會開啟瀏覽器並瀏覽至目標屬性中指定的 URL。目標屬性是陣列,可讓您指定的平台特定的 Url。比方說,您可能希望使用者在 iOS 和 Android navi-門至不同的 Url。在此範例中,您可以設定作業系統預設值,這表示 URL 也適用於所有平台。

HttpPOST 動作會對外部 Web 服務的目標屬性中指定的 HTTP POST 要求。目前訊息的值是空的。這就是為什麼當您按一下 [核准] 按鈕時,您會看到錯誤。

MessageCard 遊樂場應用程式

如果您無法將視覺化卡片的您所撰寫的標記外觀,它可能會很棒。Microsoft 有 Web 應用程式,可讓您執行上述工作。它稱為 MessageCard 遊樂場應用程式 (bit.ly/2s274S9)。

您應該要設計您的應用程式中的卡第一次。一旦您滿意卡片配置,您可以使用標記以電子郵件訊息。

呼叫具有 HttpPOST 動作的外部 Web 服務

現在,您會有訊息卡與兩個動作。OpenUri 會開啟瀏覽器並瀏覽至動作中指定的 URL。HttpPOST 動作,您想要呼叫您的 REST API 將核准的經費支出報表。您以下列內容取代 HttpPOST 動作:

{
  "@type": "HttpPost",
  "name": "Approve",
  "target": "https://api.contoso.com/expense/approve",
  "body": "{ \"id\": \"98432019\" }"
}

當使用者按一下 [核准] 按鈕時,Microsoft server 提出 HTTP POST 要求,類似於資料夾 lowing:

POST api.contoso.com/expense/approve
Content-Type: application/json

{ "id": "98432019" }

目標是 Microsoft server 即將進行的 POST 要求的 URL,且主體為要求的內容。本文內容一律假設為 JSON。

現在,您要將您自己的新標記的電子郵件。當您按一下 [核准] 按鈕時,此動作為成功地完成 ed。

ActionCard 動作

現在讓我們加入拒絕按鈕,讓使用者可以拒絕經費支出報表。拒絕,您必須另外輸入的使用者說明為何會拒絕的經費支出報表。

ActionCard 動作被針對這種情況。它包含一或多個輸入和相關聯的動作,可以是 OpenUri 或 HttpPost。中所示,插入 ActionCard 動作 HttpPOST 和 OpenUri,之間圖 4

圖 4 ActionCard 動作

"potentialAction": [{
  "@type": "HttpPost",
  ...
}, {
  "@type": "ActionCard",
  "name": "Reject",
  "inputs": [{
    "@type": "TextInput",
    "id": "comment",
    "isMultiline": true,
    "title": "Explain why the expense report is rejected"
  }],
  "actions": [{
    "@type": "HttpPOST",
    "name": "Reject",
    "target": "https://api.contoso.com/expense/reject",
    "body": "{ \"id\": \"98432019\", \"comment\": \"{{rejectComment.value}}\" }"
  }]
},{
  "@type": "OpenUri",
  ...
}]

如果您傳送自行更新的標記,有幾個核准、 拒絕及檢視費用報表的按鈕。如果您按一下 Re ject 按鈕時,您現在可以在拒絕的經費支出報表之前輸入註解。

讓我們看看 ActionCard 動作標記。以外的類型和名稱屬性,其具有輸入和動作的陣列。在此範例中,您會有多行的輸入,讓使用者輸入的文字。其他支援的輸入是 DateInput 和 MultichoiceInput。如需詳細資訊,請參閱bit.ly/2t3bLJN

您有 HttpPOST 動作,可讓外部 Web 服務呼叫,以拒絕的經費支出報表。這是 simi-lar HttpPOST 動作核准動作。一項主要差異是您想要傳遞至 Web 服務呼叫的使用者輸入的註解。您可以參考的文字輸入使用 {{rejectComment.value}} rejectComment 所在的文字輸入的識別碼值。

Web 服務,可採取動作的訊息

到目前為止所見標記中 Outlook 和它的運作方式可採取動作的訊息。在文件的其餘部分,我將會取消說明 Web 服務應該如何處理來自可採取動作的訊息,在 Outlook 中的要求。

可採取動作的訊息將會使用任何 Web 服務可以處理 HTTP POST 要求。在此範例中,您的 Web 服務是此 API 控制器會在 ASP.NET MVC 中。圖 5顯示您的 API 控制器。

圖 5 費用 API 控制器

[RoutePrefix("expense")]
public class ExpenseController : ApiController
{
  [HttpPost]
  [Route("approve")]
  public HttpResponseMessage Approve([FromBody]JObject jBody)
  {
    string expenseId = jBody["id"].ToString();

    // Process and approve the expense report.
    HttpResponseMessage response = this.Request.CreateResponse(HttpStatusCode.OK);
    response.Headers.Add("CARD-ACTION-STATUS", "The expense was approved.");

      return response;    
  }

  [HttpPost]
  [Route("reject")]
  public HttpResponseMessage Reject([FromBody]JObject jBody)
  {
    string expenseId = jBody["id"].ToString();
    string comment = jBody["comment"].ToString();

    // Process and reject the expense report.
    HttpResponseMessage response = this.Request.CreateResponse(HttpStatusCode.OK);
    response.Headers.Add("CARD-ACTION-STATUS", "The expense was rejected.");

    return response;    
  }
}

共有兩種方法,此 API 控制器中的,一個用於核准和拒絕的另一個。Web 服務必須傳回 HTTP 狀態碼的 2xx 動作才能算是成功。Web 服務也可以在回應中包含的卡片動作狀態標頭。此標頭的值將顯示給使用者的智慧卡的保留區。如果您部署至 Web 服務https://api.contoso.com並且您按一下 [核准] 5d; 按鈕,就會收到的操作已順利完成,如中所示 noti fication圖 6

成功的核准,通知的經費支出報表
圖 6 經費支出報表具有核准成功通知

您現在已可採取動作的訊息使用端對端。您可以傳送出可採取動作的訊息和 HTTP POST 要求當使用者按一下 [核准] 按鈕時,對您的 Web 服務。您的 Web 服務會處理要求,並傳回 200 確定。Outlook 會接著在標記動作完成。接下來,我會探討您如何保護您的 Web 服務。

有限用途語彙基元

因為費用識別碼通常是跟特定格式,會有攻擊者可以藉由公佈的許多不同的費用 Id 與要求執行攻擊的風險。如果攻擊成功猜測費用編號,攻擊者可能能夠核准或拒絕該經費支出報表。Microsoft 建議開發人員使用 「 有限用途語彙基元 」 一部分的動作目標 URL,或在要求主體中。有限用途語彙基元應該是硬式攻擊者更難以猜測。例如,使用 GUID 做為有限用途權杖的 128 位元數字。這個語彙基元可以用來與服務 Url 使用者與特定要求相互關聯。它也可以用來防止重新執行攻擊 (bit.ly/2sBQmdn) 的 Web 服務。您更新主體中包含 GUID 的標記:

{
  "@type": "HttpPost",
  "name": "Approve",
  "target": "https://api.contoso.com/expense/approve",
  "body": "{ \"id\": \"98432019\", \"token\": \
  "d8a0bf4f-ae70-4df6-b129-5999b41f4b7f\" }"
}

承載權杖

雖然有限用途語彙基元,讓攻擊者偽造要求,它們仍不完整。在理想情況下,Web 伺服器,應該能夠告訴 HTTP POST 要求是否來自 Microsoft 的伺服器,而不是某些未經授權的潛在惡意伺服器。

Microsoft 會解決此問題,它會傳送至 Web 服務的每個 HTTP POST 要求中包含的承載權杖。承載權杖是 JSON Web Token (JWT),並且包含要求的授權標頭中。當使用者按一下 [核准] 按鈕時,Web 服務會收到要求看起來像這樣:

POST https://api.contoso.com/expenses/approve

Content-Type: application/json
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJ­SUzI1NiIsIng1dCI6I­jhx­Z3A4­VER­CbDJINkp5­RkU0WjM0­ZDJoYS1rR­SIsImtpZCI6I­jhxZ3A4V­ERCbDJINkp5RkU0WjM0ZD­JoYS1rRSJ9.eyJpYXQiOjE0ODQwODkyNzksInZlciI6IlNUSS5FeHRlcm­5hbEFjY2Vzc1Rva2­VuLlYxIiwiYXBw aWQiOiI0OGFmMD­hkYy1mN­mQyLTQzNWYtYjJhNy0wN­jlhYmQ5OWMwODYiLCJzd­WIiOiJk­YXZpZEBj­ b250b3NvLmN­vbSIsImFwcGlk­YWNyIjoiMiIsIm­FjciI6IjAi­LCJzZW5kZ­XIiOiJleHB­lbnNlYXBw... (truncated for brevity)

{
  "id": "98432019",
  "token": "d8a0bf4f-ae70-4df6-b129-5999b41f4b7f"
}

以下的授權標頭中"變更 Bearer"是長時間的 base 64 編碼的字串是 JSON Web Token (JWT)。您可以解碼在 jwt.calebb.net JWT。圖 7它解碼之後,會顯示範例權杖。

圖 7 A 範例承載 JSON Web 權杖

{
  typ: "JWT",
  alg: "RS256",
  x5t: "8qgp8TDBl2H6JyFE4Z34d2ha-kE",
  kid: "8qgp8TDBl2H6JyFE4Z34d2ha-kE"
}.
{
  iat: 1484089279,
  ver: "STI.ExternalAccessToken.V1",
  appid: "48af08dc-f6d2-435f-b2a7-069abd99c086",
  sub: "david@contoso.com",
  appidacr: "2",
  acr: "0",
  sender: "expenseapproval@contoso.com",
  iss: "https://substrate.office.com/sts/",
  aud: "https://api.contoso.com",
  exp: 1484090179,
  nbf: 1484089279
}.
[signature]

每個 JWT 具有三個區段,以點 (.) 分隔。第一個區段是描述套用至 JWT 的 crypto 圖形作業的標頭。在此情況下,用來簽署權杖的演算法 (alg) 是 RS256,這表示使用 sha-256 雜湊演算法的 RSA。X5t 值會指定用來簽署權杖的金鑰的憑證指紋。

第二個區段是本身的內容。它有一份語彙基元判斷提示的宣告。Web 服務應該使用這些宣告來驗證要求。中的資料表圖 8說明這些宣告。

宣告在承載中的圖 8 說明

宣告 描述
iss 權杖簽發者。值應該一律是 https://substrate.office.om/sts/。如果值不符合,Web 服務應該拒絕語彙基元和要求。
appid 發行權杖的應用程式識別碼。值應該一律是48af08dc-f6d2-435f-b2a7-069abd99c086。如果值不符合,Web 服務應該拒絕語彙基元和要求。
語彙基元的對象。其值必須符合 Web 服務 URL 的主機名稱。如果值不符合,Web 服務應該拒絕語彙基元和要求。
sub 主旨人員執行此動作。如果電子郵件地址或任何 proxy 電子郵件地址中,值會是執行動作之人員的電子郵件地址: 列。如果沒有任何電子郵件地址配對時,這會是主體的使用者主體名稱 (UPN) 的雜湊的值。它具有保證能夠針對相同的 UPN 相同的雜湊的值。
寄件者 原始訊息寄件者電子郵件地址。
tid 權杖簽發者的租用戶識別碼。

第三個區段是語彙基元的數位簽章。藉由驗證簽章,Web 服務可以確信權杖會傳送 microsoft 和信任權杖中的宣告。

驗證數位簽章是一個複雜的工作。幸運的是,沒有文件庫,以簡化驗證工作的 NuGet。媒體櫃將會位於bit.ly/2stq90c ,它 Microsoft 所設計。Microsoft 也會發行有關如何驗證權杖的其他語言的程式碼範例。在本文結尾可使用這些程式碼範例的連結。

您在 Web 服務專案中包含 NuGet 封裝之後,您可以使用 VerifyBearerToken 方法,如中所示圖 9,驗證要求的持有人權杖。

圖 9 VerifyBearerToken 方法

private async Task<HttpStatusCode> VerifyBearerToken(
  HttpRequestMessage request, string serviceBaseUrl, string expectedSender)
{
  if (request.Headers.Authorization == null ||
    !string.Equals(request.Headers.Authorization.Scheme, "bearer", 
      StringComparison.OrdinalIgnoreCase) ||
      string.IsNullOrEmpty(request.Headers.Authorization.Parameter))
  {
    return HttpStatusCode.Unauthorized ;
  }

  string bearerToken = request.Headers.Authorization.Parameter;
  ActionableMessageTokenValidator validator = 
    new ActionableMessageTokenValidator();
  ActionableMessageTokenValidationResult result = 
    await validator.ValidateTokenAsync(bearerToken, serviceBaseUrl);

  if (!result.ValidationSucceeded)
  {
    return HttpStatusCode.Unauthorized;
  }

  if (!string.Equals(result.Sender, expectedSender, 
    StringComparison.OrdinalIgnoreCase) ||
      !result.ActionPerformer.EndsWith("@contoso.com", 
        StringComparison.OrdinalIgnoreCase))
  {
    return HttpStatusCode.Forbidden;
  }

  return HttpStatusCode.OK;
}

[HttpPost]
[Route("approve")]
public async Task<HttpResponseMessage> Approve([FromBody]JObject jBody)
{
  HttpRequestMessage request = this.ActionContext.Request;
  HttpStatusCode result = await VerifyBearerToken(
    request, "https://api.contoso.com", 
    "expenseapproval@contoso.com");

  switch (result)
  {
    case HttpStatusCode.Unauthorized:
      return request.CreateErrorResponse(
        HttpStatusCode.Unauthorized, new HttpError());

    case HttpStatusCode.Forbidden:
      HttpResponseMessage errorResponse = 
        this.Request.CreateErrorResponse(HttpStatusCode.Forbidden, new HttpError());
      errorResponse.Headers.Add("CARD-ACTION-STATUS", 
        "Invalid sender or the action performer is not allowed.");
      return errorResponse;

    default:
      break;
  }

  string expenseId = jBody["id"].ToString();

  // Process and approve the expense report.

  HttpResponseMessage response = this.Request.CreateResponse(HttpStatusCode.OK);
  response.Headers.Add("CARD-ACTION-STATUS", "The expense was approved.");

  return response;
}

首先,方法會驗證授權標頭中沒有的承載權杖。然後,它會初始化動作 ableMessageTokenValidator 的新執行個體,並呼叫 ValidateTokenAsync 方法。此方法會採用兩個參數。第一個是本身的持有人權杖。第二個是 Web 服務的基底 URL。如果您查看已解碼的 JWT 時,這是則 (對象) 宣告的值。基本上會在核發權杖的適用對象,也就是您的 Web 服務,但不是含任何其他 Web 服務。在此情況下,API 呼叫是http://api.contoso.com/expense/approve。宣告中的值會是基底 URL,即https://api.contoso.com。

方法會傳回 ActionableMessageTokenValidationResult 的執行個體。首先,您會檢查 ValidationSucceeded 的屬性。如果驗證成功,值會是 true。否則,會為 false。

結果也會包含兩個其他屬性,將會用於第三方。第一個是寄件者。這是寄件者宣告權杖中的值。這是可採取動作的訊息傳送之帳戶的電子郵件地址。第二個是 ActionPerformer sub 宣告的值。這是執行此動作之人員的電子郵件地址。在此範例中,只限於<@contoso.com>電子郵件地址可以核准或拒絕經費支出報表。您可以將程式碼取代您自己的更複雜的驗證。

重新整理卡

到目前為止,要提供意見反應給使用者的唯一方式是透過卡動作狀態標頭。標頭的值將顯示給使用者的智慧卡的保留區。另一個選項是重新整理卡傳回給使用者。這個概念是將目前的動作卡取代使用不同的卡片。有幾個原因,您想要這麼做的原因。比方說,核准經費支出報表後,您不想使用者可以核准或拒絕的經費支出報表一次。相反地,您想要告訴使用者已核准的經費支出報表。 圖 10顯示標記,您將會傳回。

圖 10 標記回到經費支出報表重新整理卡

{
  "@context": "http://schema.org/extensions",
  "@type": "MessageCard",
  "hideOriginalBody": "true",
  "title": "Expense report #98432019 was approved",
  "sections": [{
    "facts": [{
      "name": "ID",
      "value": "98432019"
    }, {
      "name": "Amount",
      "value": "83.27 USD"
    }, {
      "name": "Submitter",
      "value": "Kathrine Joseph"
    }, {
      "name": "Description",
      "value": "Dinner with client"
    }]
  }]
}

您必須設定為 true,因此 Microsoft 伺服器會知道回應具有重新整理卡卡更新-在主體標頭的值。 圖 11顯示核准方法會傳回重新整理卡。

圖 11 核准方法會傳回重新整理卡

private HttpResponseMessage CreateRefreshCard(
  HttpRequestMessage request, string actionStatus, 
  string expenseID, string amount, string submitter, string description)
{
  string refreshCardFormatString = "{\"@context\": \"http://schema.org/extensions\",\"@type\": \"MessageCard\",\"hideOriginalBody\": \"true\",\"title\": \"Expense report #{0} was approved\",\"sections\": [{\"facts\": [{\"name\": \"ID\",\"value\": \"{0}\"},{\"name\": \"Amount\",\"value\": \"{1}\"},{\"name\": \"Submitter\",\"value\": \"{2}\"},{\"name\": \"Description\",\"value\": \"{3}\"}]}]}";
  string refreshCardMarkup = string.Format(
    refreshCardFormatString,
    expenseID,
    amount,
    submitter,
    description);

HttpResponseMessage response = request.CreateResponse(HttpStatusCode.OK);
Response.Headers.Add("CARD-ACTION-STATUS", actionStatus);
  response.Headers.Add("CARD-UPDATE-IN-BODY", "true");
  response.Content = new StringContent(refreshCardMarkup);

  return response;
}

[HttpPost]
[Route("approve")]
public async Task<HttpResponseMessage> Approve([FromBody]JObject jBody)
{
  HttpRequestMessage request = this.ActionContext.Request;
  HttpStatusCode result = await VerifyBearerToken(
    request, "https://api.contoso.com", 
    "expenseapproval@contoso.com");

  switch (result)
  {
    case HttpStatusCode.Unauthorized:
      return request.CreateErrorResponse(
        HttpStatusCode.Unauthorized, new HttpError());

    case HttpStatusCode.Forbidden:
      HttpResponseMessage errorResponse = 
        this.Request.CreateErrorResponse(
          HttpStatusCode.Forbidden, new HttpError());
      errorResponse.Headers.Add("CARD-ACTION-STATUS", 
        "Invalid sender or the action performer is not allowed.");
      return errorResponse;

    default:
      break;
  }

  string expenseId = jBody["id"].ToString();

  // Process and approve the expense report.

  return CreateRefreshCard(
    request,
    "The expense was approved.",
    "98432019",
    "83.27 USD",
    "Jonathan Kiev",
    "Dinner with client");
}

總結

可採取動作的訊息,讓使用者安全的方式完成在 Outlook 中的工作。它使用中桌面的 Outlook 和 Outlook Web Access 今天,此功能即將推出將適用於 Mac 的 Outlook 和 Outlook Mobile。它會直接實作可採取動作的訊息。首先,您必須將必要的標記加入至您要傳送出的電子郵件。其次,您必須確認您的 Web 服務以傳送 microsoft 的持有人權杖。可採取動作的訊息會讓您的使用者,幸福且更具生產力。沒有這麼多超過有關可採取動作的訊息本文可以列舉。請瀏覽bit.ly/2rAD6AZ完整的參考和程式碼範例的連結。

我想要了解 Sohail Zafar,Edaena Salinas Jasso,Vasant Kumar Tiwari、 標記 Encarnacion 和 Miaosen Wang 協助人員會檢閱本文的文法、 拼字和流程。


Woon Kiat 黃是軟體工程師,從在 Microsoft Research 知識技術群組。他密切與 Outlook 小組可採取動作的訊息傳遞。請連絡他在wowong@microsoft.com

非常感謝下列 Microsoft 技術專家檢閱這篇文章:Pretish 林肯、 David Claux、 標記 Encarnacion 和 Patrick Pantel


MSDN Magazine 論壇中的這篇文章的討論