Phase 2, optional. Builds a single BCC'd draft (or, if DLP blocks that, sends individually) to whichever Thursday batch you specify, without you having to rebuild the recipient list by hand every week. v2.0: the Thursday send is split into two independent batches (server-load reasons — see the app's own Send Email screen), so this flow now takes a Batch input and you run it twice, once per batch, reviewing/sending each draft separately.
You want to review subject/body/attachments before anything goes out, and you may want to run it on a day other than Thursday occasionally. A manually-triggered flow (run from Power Automate's mobile app, the web portal, or a button added to the canvas app later) gives you that control. Nothing here auto-sends on a timer.
Manually trigger a flow (Power Automate → Instant cloud flow). Inputs:
| Input | Type | Notes |
|---|---|---|
| Batch | Choice (Batch 1 / Batch 2) | Which Thursday batch to build this run. Run the flow twice, once per batch — the two batches are always disjoint groups, so this never double-emails anyone. |
| Subject | Text | Default value you set once, editable each run. |
| Body | Text (multi-line) | Plain text or simple HTML — used as-is in the draft body. |
| ConfirmSend | Yes/No | Default No. Safety gate — the flow stops early unless this is explicitly set to Yes on the run. |
BM Groups, Filter Query: ThursdayBatch eq '@{triggerBody()['Batch']}' (test this exact syntax against your tenant's Choice-column OData behaviour first — some environments want ThursdayBatch/Value eq '...' instead; if the filter comes back empty, that's the first thing to try)join(select(body('Get_items')?['value'], concat('GroupName eq ''', item()?['Title'], '''')), ' or ')
BM Memberships, Filter Query: @{outputs('Build_OData_filter')}body('Get_items_2')?['value'], Map = item()?['Email']union(body('Emails_only'), body('Emails_only')) — this is the standard Power Automate trick for deduplicating an array of primitives (union of a list with itself keeps only unique values).outputs('Dedupe_emails'), Map = {"emailAddress": {"address": item()}}ConfirmSend is equal to Yes
BM Outbox{
"@odata.type": "#microsoft.graph.fileAttachment",
"name": items('Apply_to_each')?['{FilenameWithExtension}'],
"contentBytes": base64(body('Get_file_content'))
}
(Collect these into an array — either let Apply to each's Compose output accumulate automatically, or use a separate "Select" afterward over the file list mapping to the same shape.)
POSThttps://graph.microsoft.com/v1.0/me/messages{
"subject": "@{triggerBody()['Subject']}",
"body": {
"contentType": "HTML",
"content": "@{triggerBody()['Body']}"
},
"bccRecipients": @{outputs('BCC_recipient_objects')},
"attachments": @{body('Select_attachment_objects')}
}
Nothing here needs to mention which batch it is — the recipient list itself is already scoped to the chosen batch from step 1. If you want the batch visible at a glance in your Drafts folder, add it to the Subject input yourself each run (e.g. "Weekly Update — Batch 1").
/me/messages with no /send call afterwards). Nothing is sent — you open Outlook, review it, hit Send yourself. There is no native "create draft" action in the standard Office 365 Outlook connector, which is why this goes via Send an HTTP request against Graph directly.Some tenants' Data Loss Prevention policies classify Send an HTTP request as a "premium"/blocked action even though it's part of a standard connector, or block outbound HTTP actions generally. If step 10 above fails with a DLP policy violation error, replace steps 9–10 with:
outputs('Dedupe_emails') (the flat email array from step 5, not the BCC-shaped one)@{item()}@{triggerBody()['Subject']}@{triggerBody()['Body']}This sends one individual email per recipient (mail-merge style) rather than one BCC'd draft — no BCC needed since each message has exactly one real recipient. Keep the same ConfirmSend gate in front of this loop. For ~130 recipients per group, this is well within Exchange Online's per-flow-run sending limits, but consider adding a short Delay (1–2 seconds) inside the loop if you see throttling errors on a live run.
BM Memberships temporarily, or a one-off manual test group) before running either version against a full batch. Also confirm the ThursdayBatch filter query in step 1 actually returns the right groups for each batch before your first real run — a wrong filter here silently sends to the wrong (or zero) people rather than erroring.