Building a “Comments Created Today” Digest for SharePoint Online with Power Automate (REST) — Including Clickable Item Links
This article documents a mature, production-ready pattern to collect SharePoint item comments created today, format them into a clean HTML email, and ensure the item links are truly clickable—even when you start from Create HTML table.
Privacy note (for public blogs): Replace any real tenant/site/list names with neutral placeholders, e.g.
https://contoso.sharepoint.com/sites/ExampleSiteandExample List.
Why this pattern is needed
SharePoint exposes comments through REST under a specific list item:
.../items(<ID>)/comments
In practice, you iterate items, fetch comments per item, then filter comments by date. You can use normal OData $filter for list items (e.g., to reduce the number of items you scan), but comments themselves aren’t typically queried as a global list-like entity in a single OData query. For list item REST patterns and OData query operations, see Microsoft Learn. (Microsoft Learn)
Target outcome
Send an email containing a table with:
- Comment Created Date
- Comment Text
- Author
- Item Title / ID
- Clickable “Open item” link
Architecture overview
Flow outline
- Get candidate items from your list (optionally pre-filtered).
- Apply to each item
- Call REST:
.../items(ID)/comments - Parse JSON
- Append comment objects to an array
- Call REST:
- Filter array to “created today”
- Create HTML table
- Compose to “unescape” anchors so the link becomes clickable
- Send email (V2) with HTML enabled
Step 1 — Get candidate items (reduce scanning)
If you already have your list of candidate items, skip this. Otherwise, use SharePoint REST list item querying with $select/$filter to reduce the number of items you loop through. Microsoft Learn covers list item REST operations and OData query capabilities. (Microsoft Learn)
Example REST (illustrative):
GET _api/web/lists/getbytitle('Example List')/items?$select=Id,Title,Modified&$filter=Modified ge datetime'2026-02-11T00:00:00Z'
Note: Whether “adding a comment” updates
Modifiedcan vary by scenario; if it doesn’t help, filter candidates using your own business rules (Status, last X days, etc.).
Step 2 — Get comments for each item (REST)
Inside your Apply to each (item) loop, call:
GET _api/web/lists/getbytitle('Example List')/items(@{items('Apply_to_each')?['ID']})/commentsAccept: application/json;odata=verbose
You already have this working—great.
Step 3 — Parse JSON and build a “rich” array (comment + item metadata)
Create an Array variable:
commentsToEmail(Array)
Then, inside the Apply to each (comment results), append objects (not just dates). Example:
Recommended object shape
createdDatetextauthorNameauthorEmailitemIditemTitleitemLinkHtml(this will be your<a>tag)
Item link (DispForm pattern)
concat( 'https://contoso.sharepoint.com/sites/ExampleSite/Lists/ExampleList/DispForm.aspx?ID=', string(items('Apply_to_each')?['ID']))
Clickable anchor stored as a string
concat( '<a href="', <the link above>, '">Open item</a>')
If your comment JSON fields differ (some tenants return
text, some use another property), use the run-history sample to map fields correctly.
Step 4 — Filter comments created “today”
Use a Filter array on commentsToEmail.
If you treat “today” as UTC (simple + stable)
@greaterOrEquals(item()?['createdDate'], startOfDay(utcNow()))
For guidance on using expressions in conditions (Power Automate), see Microsoft Learn. (Microsoft Learn)
If you need “today” in a local timezone, you can apply timezone conversion logic. Be careful:
startOfDay(utcNow())is UTC day boundary (common gotcha). (This is a known behavior frequently discussed in the Power Platform community.) (Microsoft Power Platform Community)
Step 5 — Create HTML table (keep your current approach)
Now run Create HTML table using the filtered array.
At this stage, formatting is good—but the link often isn’t clickable because Create HTML table HTML-encodes content inside cells.
You asked specifically to reuse the HTML table you already built. Good—keep it.
Step 6 — Make links clickable (without rebuilding the table)
This is the key “maturity step” you reached:
- Store the link as an
<a href="...">Open item</a>string in your array object (itemLinkHtml) - After Create HTML table, use Compose to “unescape” only the anchor tags.
Compose expression (anchor-only unescape)
replace( replace( replace( body('Create_HTML_table'), '<a href="', '<a href="' ), '">', '">' ), '</a>', '</a>')
This converts escaped anchor markup back into real HTML anchors while leaving the rest of the table intact.
Step 7 — Send the email as HTML
Use Office 365 Outlook → Send an email (V2):
- Body: the output of the Compose step (unescaped anchors)
- Is HTML: Yes
Microsoft’s connector documentation includes notes about how Outlook/connector actions treat HTML. (Microsoft Learn)
Tip: Avoid “Send email with options” for this scenario unless you understand its HTML limitations (action cards can behave differently). (Microsoft Learn)
Formatting tips (without breaking Outlook)
Email clients—especially Outlook desktop—can be strict. If you want nicer formatting:
Wrap the table in a styled container
concat( '<div style="font-family:Segoe UI, Arial; font-size:13px; color:#222;">', '<h3 style="margin:0 0 10px 0;">Comments created today</h3>', '<div style="border:1px solid #e1e1e1; border-radius:8px; overflow:hidden;">', outputs('Compose_UnescapeAnchors'), '</div>', '<p style="margin-top:10px;color:#666;">Generated: ', formatDateTime(utcNow(),'yyyy-MM-dd HH:mm'), ' UTC</p>', '</div>')
Operational hardening (recommended next steps)
1) De-duplicate notifications
If the flow runs multiple times a day, store a “last processed comment timestamp/id” in a separate list (a “state list”). Then only email new comments since the last run.
2) Scope candidate items
To reduce calls, filter items first using business logic (Status, active projects, last N days, etc.). Microsoft Learn shows how to use $select/$filter efficiently on list items. (Microsoft Learn)
3) Error handling
Wrap REST + Parse JSON in a scope with failure handling so one problematic item doesn’t break the entire digest.
Final summary tables
Steps summary
| Step | Action | Output |
|---|---|---|
| 1 | Get candidate items (optional $filter) | Smaller item set to scan |
| 2 | REST: items(ID)/comments | Comments per item |
| 3 | Parse JSON | results array |
| 4 | Append object to array | Comment + item + link HTML |
| 5 | Filter array (today) | Only today’s comments |
| 6 | Create HTML table | Email-ready table |
| 7 | Compose replace() | Clickable <a> restored |
| 8 | Send email (HTML) | Final digest delivered |
Technical reference
| Need | Expression / Reference |
|---|---|
| SharePoint list REST basics | Microsoft Learn: working with lists/items (Microsoft Learn) |
OData $select/$filter patterns | Microsoft Learn: OData query operations (Microsoft Learn) |
| Compare dates in conditions | Microsoft Learn: expressions in conditions (Microsoft Learn) |
| HTML handling considerations | Microsoft connector notes (Outlook) (Microsoft Learn) |
| UTC day boundary gotcha | Community explanation (timezone behavior) (Microsoft Power Platform Community) |
