Power Automate の「Create HTML Table」でURL列をそのまま出すと、長すぎてメールの見た目が崩れがちです。ところが <a> タグで「ラベル付きリンク」にしようとしても、タグが文字として表示されてしまうことがあります。この記事では、原因(なぜ起きるか)と、フローを大きく変えずにクリックできるリンクへ戻す手順を、式と実例つきで解説します。
起きている問題(症状)
Power Automate のフローで「Create HTML Table(HTML テーブルの作成)」を使い、メール本文に表を埋め込むケースは非常に多いです。特に、SharePoint リスト、Excel、Dataverse、Forms などから取得したデータを一覧で送る用途では定番です。
ただし、表の列に URL が入ると次のような困りごとが起きます。
- URL が長く、セルが横に伸びてレイアウトが崩れる
- メール本文の可読性が落ち、必要な情報(タイトルやステータス)が目に入らない
- スマホのメールアプリでスクロールが大変になり、読まれなくなる
そこで「URL をそのまま表示せず、ラベル表示にしてクリックできるリンクにしたい」と考え、値として次のように渡したくなります。
<a href="https://example.com/very/long/url">Click for Google</a>
しかし実際は、Create HTML Table で生成した表の中で <a> がリンクとして機能せず、次のように“文字列”として表示されてしまうことがあります。
| やりたいこと | 実際に起きること |
|---|---|
| URL をラベル付きリンクにする(クリックで遷移) | <a href="...">...</a> がそのまま表示される/タグが無視される |
| 長い URL を隠して見た目を整える | 長い URL 文字列が露出し、表が崩れる |
結論:原因は Create HTML Table の「自動エスケープ」
この現象の原因はシンプルで、Create HTML Table が“値の中に含まれる HTML を、そのまま HTML として解釈させないように自動でエスケープして出力する”ためです。
たとえば、値の中に < や >、引用符(")が含まれると、HTML として解釈されると危険なケースがあります。そこで Create HTML Table は、次のように文字をエンティティへ変換(エスケープ)し、文字扱いにします。
| 元の文字 | エスケープ後 | 意味 |
|---|---|---|
< | < | タグ開始と誤認されないようにする |
> | > | タグ終了と誤認されないようにする |
" | " | 属性値の引用符を無害化する |
その結果、たとえ入力値が <a href="...">... であっても、Create HTML Table の出力は次のようになります。
| 入力として渡した値 | Create HTML Table の出力(表内) |
|---|---|
<a href="https://example.com">Click</a> | <a href="https://example.com">Click</a> |
これは「タグが壊れている」のではなく、意図的に“タグとして解釈されないように変換されている”というのがポイントです。
解決策:Create HTML Table の後で “デコード(エスケープを戻す)”
対処法は、Create HTML Table の出力をそのままメール本文に入れるのではなく、一度エスケープを戻してから(デコードしてから)本文に使うことです。
流れとしては次の通りです。
| ステップ | やること | 目的 |
|---|---|---|
| 1 | リンク列の値を <a href="...">ラベル</a> で用意する | URL を短いラベルに置換するため |
| 2 | Create HTML Table で表を作る | 一覧表示の HTML を自動生成するため |
| 3 | Compose(作成)でエスケープを戻す | < 等を < に戻してリンクを有効化するため |
| 4 | Compose の出力をメール本文に入れる | 実際にクリックできる表として送るため |
具体手順:フローでの実装例(最短)
リンク用の値を作る(URL をラベルにする)
前提として、Create HTML Table に渡す配列(行データ)に、リンク用の列があるはずです。そこでリンク列には URL ではなく、アンカータグ文字列を入れます。
たとえば、リンク先が URL 列(Url)、表示ラベルが Label 列(Label)として存在するなら、Select アクションなどで次のような値を作れます。
concat('<a href="', item()?['Url'], '">', item()?['Label'], '</a>')
「URL だけあってラベルがない」場合は、固定文言でも問題ありません。
concat('<a href="', item()?['Url'], '">Click for Google</a>')
ラベルを固定にすると、表がすっきりして “読む側の迷い” が減ります(どこを見れば良いかが明確になるためです)。
Create HTML Table を実行する
次に、Create HTML Table(HTML テーブルの作成)で表を作成します。Columns は「自動」でも「カスタム」でも構いませんが、カスタムにすると列名を読みやすくでき、メールの業務用途ではおすすめです。
ここで重要なのは、Create HTML Table の時点では <a> がリンクにならなくて正常、という点です。後段で戻すからです。
Compose(作成)でエスケープを戻す
Create HTML Table の直後に Compose(作成)を追加し、次の式で < などを戻します。これは「Create HTML Table が安全のためにエスケープしたものを、メール本文で解釈できるように戻す」処理です。
replace(
replace(
replace(body('Create_HTML_table'),'<','<'),
'"','"'),
'>','>')
ポイントは次の通りです。
body('Create_HTML_table')の部分は、実際のアクション名(内部名)に合わせてください- 戻しているのは主に
<,",>の3種類(よく出るもの)です - リンクが効かない原因の大半はこの3つで解消します
メール本文は Compose の出力を使う
最後に、Send an email(Outlook の “メールの送信” 系)アクションの本文に、Create HTML Table ではなく Compose の出力を入れます。
ここも地味に重要で、メール送信アクション側が HTML として送信する設定になっていないと、せっかく戻した <a> が反映されません。Outlook の「Send an email (V2)」であれば HTML を前提としていることが多いですが、アクションによっては “Is HTML” の項目があるので、HTML が有効になっていることを確認してください。
動作確認:本当にリンクになったかをチェックする方法
実運用に入れる前に、次の観点で確認すると事故が減ります。
| 確認ポイント | 見る場所 | OK の状態 |
|---|---|---|
| Create HTML Table の出力 | 実行履歴(Run history) | <a ... > のようにエスケープされている |
| Compose の出力 | 実行履歴(Run history) | <a href="..."> が “実際のタグ” に戻っている |
| 受信したメール | Outlook / モバイル | ラベル文字がクリックでき、URL が表示されない(または最小限) |
Compose の出力でタグが戻っているのにメールでリンクにならない場合は、メール送信側が HTML として扱っていないケースが多いです。本文に入れるのが Create HTML Table の出力になっていないか、送信アクションが「通知」系(プレーンテキスト前提)になっていないかを見直してください。
実務で効く改善:リンク列の見た目をさらに整える
ラベルは「何が開くか」が分かる文言にする
“Click” だけでも短くなりますが、業務メールだと「何のリンクか」が分からないと不安が出ます。おすすめは、次のような命名ルールです。
- 申請・チケットなら:「申請を開く」 / 「チケット詳細」
- SharePoint アイテムなら:「一覧で確認」 / 「アイテムを開く」
- 外部サイトなら:「公式ページ」 / 「参照リンク」
ラベルは短く、意味が具体的であるほどクリック率が上がり、問い合わせが減ります。
URL から簡易ラベルを自動生成する(URLしかない場合)
「ラベル列が存在せず URL しかない」場合でも、最低限 “どのドメインか” が分かるだけで安心感が上がります。たとえば、URL からホスト名だけを取り出し、ラベルに混ぜる方法です。
URL から https:// や http:// を除いて / で分割し、先頭要素を取るとドメイン相当を作れます。
first(
split(
replace(replace(item()?['Url'],'https://',''),'http://',''),
'/'
)
)
これを使って、ラベル付きリンクを次のように組み立てるイメージです。
concat(
'<a href="', item()?['Url'], '">',
'Open: ',
first(split(replace(replace(item()?['Url'],'https://',''),'http://',''),'/')),
'</a>'
)
「Open: example.com」のように見えるだけでも、受信者は安心してクリックしやすくなります。
安全性の注意点(重要):何でもデコードしない
ここで紹介した方法は “HTML を有効化する方向” の処理です。つまり、データに意図しない HTML が混ざっていた場合、その HTML まで効いてしまう可能性があります。
実運用で安全に使うための指針をまとめます。
| 状況 | おすすめ | 理由 |
|---|---|---|
| URL・ラベルが自分のフロー内で生成される(固定文言・信頼できるデータ) | 今回のデコード方式でOK | 入力が管理下にあり、混入リスクが低い |
| 外部入力(フォーム自由記述、メール本文、外部システム)をそのまま表に出す | 全面デコードは避ける | 意図しないタグが混ざり得る(見た目改ざん・フィッシング誘導など) |
| どうしても外部入力を混ぜる必要がある | リンク列だけを自前で生成し、他列はそのまま(または明示的にサニタイズ) | リスクを“局所化”できる |
特に注意したいのは「不特定の入力を丸ごとデコードして HTML として解釈させる」パターンです。メールクライアントは多くの危険なタグを無効化しますが、それでも見た目の改ざんや誤誘導など、業務上の事故につながる余地は残ります。
安全性を上げたい場合:リンク関連だけ最小限デコードする
「表の中のリンクだけ有効になればよい」「他の列はエスケープされたままの方が安心」という場合は、デコード範囲を絞る考え方が有効です。
たとえば、Create HTML Table が出すリンクの典型パターンは次のようになります。
<a href="https://example.com">Label</a>
これをリンクとして成立する最小限に戻すなら、次のように “アンカー部分の並び” を狙って置換します。
replace(
replace(
replace(
body('Create_HTML_table'),
'<a href="', '<a href="'
),
'">', '">'
),
'</a>', '</a>'
)
この方法だと、< を全面的に < に戻さないため、他列に含まれる < 相当が不用意にタグ化されるリスクを抑えられます。フロー内でリンク列だけを確実に生成している場合に、より安心して使えるパターンです。
よくあるつまずきと対処(チェックリスト)
| 症状 | 原因候補 | 対処 |
|---|---|---|
| Compose で戻しているのにリンクにならない | メール送信が HTML 扱いではない | 送信アクションの “Is HTML” を確認、本文に Compose 出力を入れる |
| 一部の受信者だけリンクにならない | 受信側クライアント差(外部メール・セキュリティ設定) | Outlook / Web / モバイルで検証し、ラベル文言を明確にする |
| リンクはできたが URL に & が混ざって見える | URL クエリのエンコードが表示上残る | 見た目はラベルで隠す(URLを本文に出さない)、必要なら生成元URLを見直す |
| 表が読みづらい(罫線・余白が微妙) | Create HTML Table の標準出力が質素 | 必要なら後段で <table> に style を付与する(メールは inline style 推奨) |
まとめ:Create HTML Table の仕様を理解すれば最短で直せる
Power Automate の Create HTML Table は、値に含まれる HTML をそのまま解釈させないために自動でエスケープします。だからこそ、<a> を渡してもリンクにならず “文字列” として表示されます。
解決するには、Create HTML Table の直後に Compose を挟み、< / > / " を戻してからメール本文に使うのが最短です。さらに安全性を意識するなら、リンク部分だけ最小限デコードする方法も検討できます。
URL が長くてメールが読まれない問題は、見た目の問題に見えて、実は業務効率や確認漏れに直結します。ラベル付きリンクで “読む側の負担” を減らし、フロー通知を「読まれるメール」に整えていきましょう。

コメント