【Power Apps】Outlookのメールを一度に25件以上取得する方法

Power AppsでOutlookのメールを一度にたくさん取得し、まとめて何らかの処理を行う方法を紹介します。
またユーザー定義型を利用することで扱いづらいHTTP要求の戻り値を処理しやすくする方法も紹介します。

## Outlookの標準メール取得アクションでは一度にメールを25件までしか取得できない

Power Apps / Power AutomateでOutlookメールを取得する方法として、Outlookコネクタの「メールを取得する (V3)」アクションがあります。
ただしこのアクションでは一度にメールを最大25件までしか取得できないという制限があり、大量のメールに対して処理を行う場合は繰り返し処理する必要があり不便です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618051/5a70172d-10ad-8c44-6343-2398ca2120f2.png)

この制限を回避する方法としてMicrosoft Graph APIを利用する方法があり、以下の記事でその方法が紹介されています。

https://idea.tostring.jp/?p=7614

本記事ではこちらのPower Automateで制限回避する方法を参考に、Power Appsで同様の処理を実装する方法を紹介します。

この記事は [Microsoft Power Apps Advent Calendar 2024](https://qiita.com/advent-calendar/2024/powerapps) シリーズ1 12月18日 担当分の記事です。

## 実装方法

### Power AppsからOutlook REST APIを使用する

OutlookのREST APIをOutlookコネクタのHttpRequestアクションから利用します。

[Outlook メール REST API を使用する - Microsoft Graph v1.0 | Microsoft Learn](https://learn.microsoft.com/ja-jp/graph/api/resources/mail-api-overview?view=graph-rest-1.0)

InboxやフォルダID指定でメールを取得する数式は以下です。

```
//Inboxのメール取得
Office365Outlook.HttpRequest("https://graph.microsoft.com/v1.0/me/mailFolders/Inbox/messages", "GET", "", {ContentType:"application/json"})

//フォルダIDでのメール取得
Office365Outlook.HttpRequest("https://graph.microsoft.com/v1.0/me/mailFolders/{フォルダID}", "GET", "", {ContentType:"application/json"})
```

#### フォルダID取得方法

フォルダーIDはPower Automateで取得するのが簡単です。
取得対象のフォルダーを選択して、Code viewを確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618051/9a624179-36ec-12e6-8770-747a10d385d4.png)

"folderPath"のId::以降の部分がフォルダーIDです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618051/7a708661-18ee-269b-13ed-c731dfcdbc21.png)

#### クエリ パラメーター設定方法

以下を参考にクエリ パラメーターを設定することで、取得する件数を絞ったりフィルターをかけたりソートしたりできます。

[クエリ パラメーターを使用して応答をカスタマイズする - Microsoft Graph | Microsoft Learn](https://learn.microsoft.com/ja-jp/graph/query-parameters?tabs=http)

```
//例：Inbox内のメールを上から1件だけ取得する
Office365Outlook.HttpRequest("https://graph.microsoft.com/v1.0/me/mailFolders/Inbox/messages?$top=1", "GET", "", {ContentType:"application/json"})
```

とはいえPower Appsでも同じことができるので、パフォーマンスなどに懸念がない限りはクエリではなくPower Appsの関数で処理した方がいいと思います。

### ユーザー定義型機能を用いた型定義

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618051/86ffb632-5274-5f71-584d-21cbb6dfcb37.png)

HttpRequestの出力値はUntypedObject型のためそのままではデータを取り出すことは出来ず、JSON関数とParseJSON関数で型定義する必要があります。

これらの関数を用いた変換を簡単にするユーザー定義型という機能が試験段階で公開されたのでこちらを活用します。
詳細や注意点などはヨウセイさんの記事をご一読ください。

https://youseibubu.com/apps/user-defined-type1/

#### App.Formulasで型定義

このユーザー定義型機能を利用するには、App.Formulasプロパティで特定の書式で型定義する必要があります。

結論としては以下の文字列をApp.Formulasに記載すればOKです。(※Outlook REST APIのme/mailFolders/Inbox/messagesに限る)
ただこの書式は現状1から書くのはかなり面倒なので、簡単に生成する方法を別記事で紹介します。

```
MailDef := Type({
    '@odata.context': Text,
    '@odata.nextLink': Text,
    value: [{
        '@odata.etag': Text,
        bccRecipients: [{emailAddress: {address: Text, name: Text}}],
        body: {
            content: Text,
            contentType: Text
        },
        bodyPreview: Text,
        categories: [Text],
        ccRecipients: [{emailAddress: {address: Text, name: Text}}],
        changeKey: Text,
        conversationId: Text,
        conversationIndex: Text,
        createdDateTime: Text,
        flag: {
            flagStatus: Text
        },
        from: {
            emailAddress: {
                address: Text,
                name: Text
            }
        },
        hasAttachments: Boolean,
        id: Text,
        importance: Text,
        inferenceClassification: Text,
        internetMessageId: Text,
        isDeliveryReceiptRequested: Text,
        isDraft: Boolean,
        isRead: Boolean,
        isReadReceiptRequested: Boolean,
        lastModifiedDateTime: Text,
        parentFolderId: Text,
        receivedDateTime: Text,
        replyTo: [{emailAddress: {address: Text, name: Text}}],
        sender: {
            emailAddress: {
                address: Text,
                name: Text
            }
        },
        sentDateTime: Text,
        subject: Text,
        toRecipients: [{
            emailAddress: {
                address: Text,
                name: Text
            }
        }],
        webLink: Text
    }]
});
```

このMailDefを定義することで、ParseJSON関数で従来よりも簡単に型定義を行うことができます。

#### ユーザー定義型の利用方法

例としてHttpRequestの出力値を以下の数式で変数に格納することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618051/c650eed2-1d13-2dc3-da69-e2e1216a990a.png)

```
Set(_Mail, ParseJSON(JSON(Office365Outlook.HttpRequest("https://graph.microsoft.com/v1.0/me/mailFolders/Inbox/messages?$top=100", "GET", "", {ContentType:"application/json"})), MailDef))
```

このようにメールを一覧表示することができました。25件を超えるメールも一度に取得することができています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618051/56db90af-b2ef-0bdf-0eb6-9c82970c186d.png)

そして本文を取得する場合は以下の数式です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618051/e504e3e4-16bd-3202-d99d-2a33c2cb920d.png)

```
PlainText(First(_Mail.value).body.content)
```

本文のテキストは構造化されているため、First関数や.列名などを用いて値を指定する必要があります。
また本文にはHTMLタグが含まれているためPlainText関数で変換をかけています。

## おわりに

フロー作ると管理コストが増えるので、Power AppsでできることはPower Appsで実装したい派です。
とはいえPower Automateと比較するとPower Appsの実装は全くローコードではないので、保守運用をする人のスキルなども鑑みながらよりよい実装方法を選択していきましょう。

### 元記事

https://powerplatformnikki.com/getoutlookmailsover25/