最近、Power Apps(Microsoftのローコード開発プラットフォーム)がますます注目を集めていると感じています。僕はSharePointリストとPower Appsを連携し、ForAll関数を使ってデータをPatch(更新)しようと試行錯誤していました。ところが、いつのまにか想定外のメールが大量に送信されてしまう事態が発生し、慌てて対策を考えることに。さらに、SharePointのユーザー列を使って「登録者」へ自動メールを送りたいのに、思った以上に設定がややこしい部分もありました。そこで今回の記事では、同じような状況に悩む人のために、ForAll+Patchでよく起こりがちなメール多重送信の失敗事例と、スマートに改善するための実践的な方法を紹介します。この記事を読めば、Power Appsでのメール送信ロジックを上手に組み立て、誤送や重複送信のリスクを抑えながら業務効率を高める方法が見えてくるはずです。ぜひ最後まで読んでみてください。
メール多重送信が起きたときの混乱

メールが大量発射されてしまう恐怖
僕が初めてこの状況に遭遇したときは、SharePointリストのデータを「ForAll関数」でループ処理しながらPatchを実行し、ついでに1レコードずつメールも送信するようにコードを書いていました。すると、処理対象の行数分のメールが飛んでしまい、受信側には「何この大量メール…?」という混乱を招くことに。僕自身も「あれ? おかしいな、想定外すぎる…」と焦ってしまいました。
よくある失敗例
- ForAllの中で
Office365Outlook.SendEmail
を直書きする - 全行にメール送信が必要かどうかを十分に検討しない
- SharePointリストのユーザー列の内部名に気づかず、宛先指定がうまくいかない
特に上記のような書き方をしてしまうと、気づかないうちに想定外のメール爆撃が起こります。
なぜForAllでのメール送信が問題になるのか
ForAllの特徴
Power AppsのForAll(テーブル, 処理)
という関数は、一括処理を並列または逐次に行う機能を持っています。各行に対して定義した処理を実行するため、書き方によっては1行ごとに同じ操作が連続で行われることが多いです。
連続で実行される例
ForAll(
MyGallery.AllItems,
Office365Outlook.SendEmail(
ThisRecord.登録者.Email,
"確認依頼",
"テスト送信"
)
);
このコードを実行すれば、ギャラリー内のアイテムの数だけ同じメールが送られてしまいます。
Patchとの組み合わせで混乱が増幅
加えて、Patch関数をForAllで回す場合には「データを複数行に対して更新する」という要件を満たしやすいというメリットがあります。ところが同時に、同じ構文内でメール送信を記述すると、その更新された行の数だけメール送信が行われることになります。
- 良かれと思ってForAllでPatch + メール送信
→ 実は複数の更新が終わるたびに同じメールが飛んでいた…
「最終的には一通だけメールを送りたいのに」と思っていても、コードの組み方次第では大量送信になるパターンに陥りやすいのです。
SharePointリストの「ユーザー列」を狙ったメールを送るには
ユーザー列の内部名を把握しよう
SharePointリストのユーザー列(People or Group列)は、たとえば表示名が「登録者」だとしても、内部名が「Author」や「CreatedBy」というケースが少なくありません。通常、SharePoint標準の「作成者」列は内部名がAuthor
となっています。
- 表示名:登録者(画面に見える名前)
- 内部名:Author(実際にコードで呼び出すプロパティ名)
これを知らないと、
ThisRecord.登録者.Email
みたいな書き方ではエラーになったり、値が取得できなかったりします。
どうやって調べる?
- SharePointリストの「リスト設定」→「列」を開いて内部名を確認する
- あるいはPower Appsの「View」を見て、
ThisItem.Author
やThisItem.作成者
などの表記を探る
実は「Author.Email」でOKだった
コード例として、こんな風に書くとユーザー列(作成者列)のEmailプロパティを取得できます。
ForAll(
MyGallery.AllItems As oneItem,
Patch(
ListSample,
LookUp(ListSample, ID = oneItem.ID),
{
Comment: oneItem.txtComment.Text
}
);
Office365Outlook.SendEmail(
oneItem.Author.Email,
"確認依頼",
"テスト送信"
)
);
上のようにForAllの中で記述すれば、全レコードに対してメール送信が走ります。ただ、この記述だと行数分のメールが配信されてしまうわけです。
1通だけ送りたい場合の実装
ForAllの外でメール送信する
複数レコードの更新後に「1回だけメールを送る」方針であれば、メール送信部分はForAllの外に書くようにするのが基本です。たとえば、ギャラリー内のアイテムの中で「代表となる1行分の登録者情報」を拾って送る方法を紹介します。
代表1行分から取得して送信
// すべてのPatch処理
ForAll(
gal対象アイテム.AllItems As itemRow,
Patch(
ListSample,
LookUp(ListSample, ID = itemRow.ID),
{
Status: itemRow.ddlStatus.Selected.Value
}
)
);
// 1行目の登録者情報だけを使い、メール送信
If(
!IsEmpty(gal対象アイテム.AllItems),
Office365Outlook.SendEmail(
First(gal対象アイテム.AllItems).Author.Email,
"まとめのご案内",
"すべての更新が終わりました。ご確認ください。"
)
);
Notify("更新とメール送信が完了しました!", NotificationType.Success);
上記のように、ForAllの外でOffice365Outlook.SendEmail()
を呼べば、一度だけメールが送られます。ここでは代表としてギャラリー内の一番上のアイテム(First)を参照するイメージです。
もし「特定の人に必ず送る」なら、リストからでなくても固定のメールアドレスを記述できます。いずれにせよ「更新のループ処理の中にメール送信を入れない」という点が重要です。
まとめて更新するならPatch(…)やUpdateIf(…)も検討
- まとめてPatchする:各アイテムをテーブルにまとめてから一発更新
- UpdateIf:特定条件に一致する全行を一度に更新
こうした方法だと「そもそもForAll自体が不要」というシナリオも生まれます。構成次第で大きく処理が簡略化できる場合があるので、ぜひ検討してみましょう。
失敗事例:ForAllとNotifyの配置ミス
Notifyの表示タイミング
僕が陥ったことがあるのは、ForAllの中にNotify
を配置してしまい、行ごとに通知がポップアップで表示されるというお騒がせ仕様にしてしまったケースです。これもメール送信の多重送信と同じ落とし穴で、ループ内に書いてはいけない処理を入れてしまうことが原因でした。
ForAll(
gal対象アイテム.AllItems,
Patch(
ListSample,
LookUp(ListSample, ID = ThisRecord.ID),
{
Title: "更新済"
}
);
Notify("更新完了", NotificationType.Information)
);
これを実行すると、更新する行数分「更新完了」が連呼されます。僕の場合はテストデータが多かったので、画面が一気にNotifyだらけになってしまいました。メール処理に限らず、ユーザーに向けた通知もForAll外で1回だけ書くようにするのがおすすめです。
SharePointユーザー列を独自に作った場合の注意点
新規ユーザー列の内部名
標準の「作成者」とは別に、カスタムでユーザー列を追加して「担当者」「チェック担当」「登録者」といった列名を付けるケースもあるはずです。その場合は、SharePointのリスト設定で列の内部名を確認してください。意外と自動的に付けられた内部名は「担当者_x0020_abc」など複雑な文字列になっている場合も。そこを知らずに、
ThisItem.担当者.Email
と書いてもうまく取得できず、実際は
ThisItem.担当者_x0020_abc.Email
と呼び出す必要があった、なんてことが起こります。
よくある質問と対策
Q1. 「すべてのレコードにメールを送りたい」んだけどダメなの?
A1. 必要なら構いません。ただし、送信先が同じ人なのに何通も届くと迷惑なので工夫が必要です。場合によっては同じ宛先には1回だけ、異なる宛先にのみ複数回送るなど、ロジックを分岐させるとよいでしょう。
Q2. 「Author」がエラーになってしまう…
A2. リストによっては「CreatedBy」「作成者」「登録者」など別の内部名を使っている可能性があります。Power Appsのデータフィールドを確認し、正しいフィールド名を使ってください。
Q3. 「メール送信が使えない」と表示される…
A3. Office365Outlookコネクタの権限が有効になっているか確認してみてください。Power Appsでデータソースを追加するところから「Office 365 Outlook」を選んで接続しましょう。
Q4. ForAllを使うと遅い気がする…
A4. 更新件数が多いと、どうしても1レコードずつに対してPatchが実行されるため処理時間が長く感じられます。パフォーマンス向上を目指すなら、可能な限りまとめてPatchする、または他のアプローチを検討してください。
コード例:多数の行をPatchして、一度だけ通知&メール
ここで典型的なサンプルとして、チェックリストを大量に更新した後に、一度だけ代表ユーザーにメールを送る流れを紹介します。ギャラリー(galCheckList
)にデータが入り、SharePointリスト名がListCheckData
だとします。ユーザー列の内部名はChecker
と仮定します。これを少し別の名前に設定しているケースもあるかと思いますので、皆さんのリスト環境に合わせて読み替えてください。
// 1. ギャラリー内のアイテムをForAllでPatch
ForAll(
galCheckList.AllItems As rowData,
Patch(
ListCheckData,
LookUp(ListCheckData, ID = rowData.ID),
{
Status: rowData.ddlStatus.Selected.Value,
Comments: rowData.txtComment.Text
}
)
);
// 2. ギャラリーの1行目からChecker.Emailを取得してメール送信
If(
!IsEmpty(galCheckList.AllItems),
Office365Outlook.SendEmail(
First(galCheckList.AllItems).Checker.Email,
"チェックご協力のお願い",
"一覧の更新が完了しました。ご確認をお願いします。"
)
);
// 3. 通知を1回だけ行う
Notify("更新処理が完了しました", NotificationType.Success);
上記のようにForAllの外へメール送信とNotifyをまとめるだけで「必要以上のスパムメール」や「通知の連打」を防げます。
うまく動かない時のデバッグポイント
- ギャラリーでちゃんとIDが取れているか
LookUp(ListCheckData, ID = rowData.ID)
の結果をギャラリーのアイテムIDと突き合わせてみる
- 内部名が違う可能性
Checker
が正しい内部名か再チェック
- 送信の権限周り
- Office 365 のライセンスが有効か、Power AppsでOutlookコネクタを追加済みか確認
- テスト時に送信先を自分のアドレスにする
- 確実に受信できるアドレスを登録し、メールが届くかどうかをテストする
僕のちょっとした工夫:送信後に一気に画面をリセット
大量更新後には、不要な項目をリセットして次回に備えたい場面もあります。たとえば:
ResetForm(EditForm1);
Set(varすべて完了, true);
Navigate(SCREEN, ScreenTransition.None);
こんな感じでボタン押下後にフォームを初期化し、別の画面へ戻すといった工夫を加えると、ユーザー体験的に「作業が完了した感」を出しやすいです。実際のプロジェクトで使うときは、用途やシナリオに合わせてUIを考えてみてください。
まとめ
- ForAllはレコードごとに処理を繰り返すため、メール送信を入れると大量送信のリスクが高い
- ユーザー列の内部名に注意し、
Author.Email
やThisItem.作成者列.Email
など正しいプロパティを使う - 1通だけメールを送る場合はForAll処理の外でSendEmailを実行する
- Notifyも同様にForAllの外でまとめて行う
- SharePoint側に複数のユーザー列がある場合、その内部名はリスト設定で必ずチェック
こうしたポイントを守るだけで、無駄な混乱やトラブルをかなり減らせると思います。僕は最初のころに大量メールの悲劇をやらかしましたが、いまは意図した分だけメールを送れるように落ち着いています。もし同じような悩みがあったら、ぜひ参考にしてみてください。
コメント