Add a Real “Email User” Button for a SharePoint List using Power Automate
Add a Real “Email User” Button for a SharePoint List using Power Automate —
Overview
This guide shows how to send server-side emails from a SharePoint list item using Power Automate. It includes two options:
-
Option 2A — “For a selected item” flow: runs from the list’s Automate menu.
-
Option 2B — Real in-row button: a column-format button that opens the flow’s run panel (uses
executeFlow).
Everything here is generic—replace the placeholders with your own values (no tenant domains or personal addresses exposed).
Prerequisites
-
A SharePoint list (call it anything, e.g., Email Requests).
-
A Person column (single or multi). In steps below, use its internal name: <PersonColumnInternalName>.
-
(Optional) Column Title for the email subject.
-
Power Automate access and an Outlook mailbox (personal or a shared mailbox).
Placeholders you’ll see
-
<SiteUrl> — your SharePoint site URL (e.g., https://<yourtenant>.sharepoint.com/sites/<yourSite>).
-
<ListName> — your list name (e.g., Email Requests).
-
<PersonColumnInternalName> — internal name of the Person column (e.g., Recipient).
-
<SharedMailboxAddress> — shared mailbox address if you send from a shared mailbox.
A SharePoint list (call it anything, e.g., Email Requests).
A Person column (single or multi). In steps below, use its internal name: <PersonColumnInternalName>.
(Optional) Column Title for the email subject.
Power Automate access and an Outlook mailbox (personal or a shared mailbox).
Placeholders you’ll see
-
<SiteUrl>— your SharePoint site URL (e.g.,https://<yourtenant>.sharepoint.com/sites/<yourSite>). -
<ListName>— your list name (e.g.,Email Requests). -
<PersonColumnInternalName>— internal name of the Person column (e.g.,Recipient). -
<SharedMailboxAddress>— shared mailbox address if you send from a shared mailbox.
Option 2A — “For a selected item” flow (menu-triggered)
Step 1 — Create the flow
-
In your list: Automate ▸ Power Automate ▸ Create a flow.
-
Choose For a selected item (list-scoped manual trigger).
-
Add Get item (SharePoint):
-
Site Address: <SiteUrl>
-
List Name: <ListName>
-
Id: ID (dynamic from the trigger)
In your list: Automate ▸ Power Automate ▸ Create a flow.
Choose For a selected item (list-scoped manual trigger).
Add Get item (SharePoint):
-
Site Address:
<SiteUrl> -
List Name:
<ListName> -
Id: ID (dynamic from the trigger)
Step 2 — Build the recipients
Single-person column? You can map To directly from Get item ▸ <PersonColumnInternalName> Email.
Multi-person column? Create a semicolon string:
-
Add Compose (name:
Compose_Recipients)
join(
select(
outputs('Get_item')?['body/<PersonColumnInternalName>'],
item()?['Email']
),
';'
)
If your environment returns a simple array of strings, use:
join(outputs('Get_item')?['body/<PersonColumnInternalName>'],';')
Step 3 — Send the email
Add Send an email (V2):
-
To (single):
@{outputs('Get_item')?['body/<PersonColumnInternalName>']?['Email']} -
To (multi):
@{outputs('Compose_Recipients')} -
Subject:
Regarding: @{coalesce(outputs('Get_item')?['body/Title'],'List item')} -
Body (plain text example):
Hi @{coalesce(outputs('Get_item')?['body/<PersonColumnInternalName>']?['DisplayName'], 'there')}, This is a quick note regarding "@{outputs('Get_item')?['body/Title']}".
Turn on Is HTML if you paste an HTML body (see variants below).
Click Save and test it by selecting a row → Automate ▸ your flow.
Useful Variants (All Generic)
A) Send from a Shared Mailbox
Replace the action with Send an email from a shared mailbox (V2):
-
From (Shared Mailbox Address):
<SharedMailboxAddress> -
To / Subject / Body: same as above
-
Ensure the connection owner has Send As or Send on behalf rights.
B) Add CC/BCC
-
CC: team@yourdomain.com; approver@yourdomain.com
-
BCC: audit@yourdomain.com
CC: team@yourdomain.com; approver@yourdomain.com
BCC: audit@yourdomain.com
C) HTML template + item link
-
Add Initialize variable:
-
Name: SiteUrl
-
Type: String
-
Value: <SiteUrl>
-
Add Compose (Compose_Html):
<p>Hi @{coalesce(outputs('Get_item')?['body/<PersonColumnInternalName>']?['DisplayName'], 'team')},</p>
<p>Here are the details for <b>@{outputs('Get_item')?['body/Title']}</b>.</p>
<p><a href="@{concat(variables('SiteUrl'), '/Lists/', encodeUriComponent('<ListName>'), '/DispForm.aspx?ID=', outputs('Get_item')?['body/ID'])}">Open item</a></p>
<hr>
<p>Sent automatically by Power Automate.</p>
-
In Send an email, set Is HTML = Yes and use @outputs('Compose_Html') as Body.
If your trigger exposes Link to item, you can use that instead of building the URL.
Add Initialize variable:
-
Name:
SiteUrl -
Type: String
-
Value:
<SiteUrl>
Add Compose (Compose_Html):
<p>Hi @{coalesce(outputs('Get_item')?['body/<PersonColumnInternalName>']?['DisplayName'], 'team')},</p>
<p>Here are the details for <b>@{outputs('Get_item')?['body/Title']}</b>.</p>
<p><a href="@{concat(variables('SiteUrl'), '/Lists/', encodeUriComponent('<ListName>'), '/DispForm.aspx?ID=', outputs('Get_item')?['body/ID'])}">Open item</a></p>
<hr>
<p>Sent automatically by Power Automate.</p>
In Send an email, set Is HTML = Yes and use @outputs('Compose_Html') as Body.
If your trigger exposes Link to item, you can use that instead of building the URL.
D) Include attachments stored on the list item
-
Get attachments (SharePoint) after Get item.
-
Apply to each (value from Get attachments):
-
Get attachment content.
-
Append into two arrays you initialize beforehand: AttachNames, AttachContents.
-
In Send an email (V2):
-
Attachments Name: @{variables('AttachNames')}
-
Attachments Content: @{variables('AttachContents')}
Get attachments (SharePoint) after Get item.
Apply to each (value from Get attachments):
-
Get attachment content.
-
Append into two arrays you initialize beforehand:
AttachNames,AttachContents.
In Send an email (V2):
-
Attachments Name:
@{variables('AttachNames')} -
Attachments Content:
@{variables('AttachContents')}
E) Only notify when a condition is met
Add a Condition before the email:
-
Left:
outputs('Get_item')?['body/Status'] -
Equals:
Ready to Notify
Put the Send email action in the Yes branch.
F) Log emails to a separate list (audit)
Create list EmailLog with: ItemId (Number), To (Text), Subject (Text), SentOn (DateTime), RunBy (Person).
After sending, Create item:
-
ItemId:
@{outputs('Get_item')?['body/ID']} -
To: (single) as above, or (multi)
@{outputs('Compose_Recipients')} -
Subject: same as the email subject
-
SentOn:
@{utcNow()} -
RunBy: User email from the trigger
G) Fallback recipient if Person is empty
@if(
empty(outputs('Get_item')?['body/<PersonColumnInternalName>']),
'fallback@yourdomain.com',
outputs('Get_item')?['body/<PersonColumnInternalName>']?['Email']
)
@if(
empty(outputs('Get_item')?['body/<PersonColumnInternalName>']),
'fallback@yourdomain.com',
outputs('Get_item')?['body/<PersonColumnInternalName>']?['Email']
)
(For multi-person, wrap outputs('Compose_Recipients') in the same if.)
Option 2B — Real in-row button (executeFlow)
Step 1 — Reuse your working 2A flow
It must be a For a selected item flow.
Step 2 — Get the flow GUID
Open the flow in the maker portal and copy the GUID from its URL.
Step 3 — Allow Run-only users
In the flow details → Run-only users → add your site (or the specific list).
Step 4 — Add a button column with JSON
-
Add a Single line of text column, e.g., SendMail.
-
Column header → Format this column ▸ Advanced mode → paste:
{
"$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json",
"elmType": "button",
"txtContent": "Send email",
"iconName": "Send",
"attributes": { "class": "ms-fontColor-white ms-bgColor-themePrimary" },
"customRowAction": {
"action": "executeFlow",
"actionParams": "{\"id\": \"PUT-FLOW-GUID-HERE\", \"headerText\": \"Send email to user\", \"runFlowButtonText\": \"Send\", \"includeFormValues\": true}"
}
}
-
Replace PUT-FLOW-GUID-HERE with your flow ID → Save and test.
Add a Single line of text column, e.g., SendMail.
Column header → Format this column ▸ Advanced mode → paste:
{
"$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json",
"elmType": "button",
"txtContent": "Send email",
"iconName": "Send",
"attributes": { "class": "ms-fontColor-white ms-bgColor-themePrimary" },
"customRowAction": {
"action": "executeFlow",
"actionParams": "{\"id\": \"PUT-FLOW-GUID-HERE\", \"headerText\": \"Send email to user\", \"runFlowButtonText\": \"Send\", \"includeFormValues\": true}"
}
}
Replace PUT-FLOW-GUID-HERE with your flow ID → Save and test.
Governance & Tips
-
Sender identity: By default, email sends under the connection owner. Use a shared mailbox for a neutral “From”.
-
Array shapes vary: If join() fails on the Person field, map with select(array, item()?['Email']) then join.
-
HTML bodies: Don’t forget Is HTML = Yes.
-
Attachment limits: Respect your Exchange attachment size limits (often ~25 MB unless customized).
-
Keep secrets out of flows: No tenant domains or personal addresses should be hard-coded. Use environment variables or config lists for addresses.
Sender identity: By default, email sends under the connection owner. Use a shared mailbox for a neutral “From”.
Array shapes vary: If join() fails on the Person field, map with select(array, item()?['Email']) then join.
HTML bodies: Don’t forget Is HTML = Yes.
Attachment limits: Respect your Exchange attachment size limits (often ~25 MB unless customized).
Keep secrets out of flows: No tenant domains or personal addresses should be hard-coded. Use environment variables or config lists for addresses.
Copy-Paste Recipes (Generic)
Subject with ID + Title
Regarding: @{outputs('Get_item')?['body/ID']}: @{coalesce(outputs('Get_item')?['body/Title'],'List item')}
Robust multi-recipient
@{join(select(outputs('Get_item')?['body/<PersonColumnInternalName>'], item()?['Email']), ';')}
HTML line break: <br/>

Comments
Post a Comment