
1
00:00:00,000 –> 00:00:02,560
Your Power Automate emails aren’t clever automations.
2
00:00:02,560 –> 00:00:04,440
They’re an HR breach waiting to happen.
3
00:00:04,440 –> 00:00:06,280
You glue the flow to a service account,
4
00:00:06,280 –> 00:00:09,120
cross your fingers through MFA prompts and call it done.
5
00:00:09,120 –> 00:00:10,560
That’s amateur hour.
6
00:00:10,560 –> 00:00:11,460
Here’s the fix.
7
00:00:11,460 –> 00:00:13,720
Microsoft Graph with an app registration,
8
00:00:13,720 –> 00:00:15,640
locked by application access policies,
9
00:00:15,640 –> 00:00:18,720
so the app can only send from the mailboxes you approve.
10
00:00:18,720 –> 00:00:20,280
I’ll give you the exact power shell,
11
00:00:20,280 –> 00:00:23,080
the graph endpoints and a custom connector schema.
12
00:00:23,080 –> 00:00:25,800
HR notifications, offers, policy updates,
13
00:00:25,800 –> 00:00:27,800
terminations will deliver reliably
14
00:00:27,800 –> 00:00:30,440
under conditional access MFA and tenant restrictions.
15
00:00:30,440 –> 00:00:33,120
There’s one misstep that silently exposes every mailbox,
16
00:00:33,120 –> 00:00:34,200
we’ll close it.
17
00:00:34,200 –> 00:00:37,960
Foundation, why service accounts, sabotage email flows.
18
00:00:37,960 –> 00:00:39,520
Let’s start with the myth.
19
00:00:39,520 –> 00:00:41,160
A service account is simple.
20
00:00:41,160 –> 00:00:44,000
The truth, delegated auth tied to a human style identity
21
00:00:44,000 –> 00:00:45,120
is fragile by design.
22
00:00:45,120 –> 00:00:48,360
Conditional access changes, MFA challenges
23
00:00:48,360 –> 00:00:50,960
and password expiry aren’t edge cases, they’re routine.
24
00:00:50,960 –> 00:00:53,960
Your flow can’t approve a push notification at 2.14 a.m.
25
00:00:53,960 –> 00:00:56,240
So it chokes, ritris and occasionally sprays duplicates
26
00:00:56,240 –> 00:00:57,880
like a malfunctioning label maker.
27
00:00:57,880 –> 00:01:00,960
You wanted reliability, you built roulette.
28
00:01:00,960 –> 00:01:03,360
Now the over-privileged problem, to make it work,
29
00:01:03,360 –> 00:01:06,360
someone grants the service account sent as on a mailbox.
30
00:01:06,360 –> 00:01:08,360
Then another exception, then temporary access
31
00:01:08,360 –> 00:01:11,160
to a shared mailbox that mysteriously never gets removed.
32
00:01:11,160 –> 00:01:12,880
That creep turns a single-purpose sender
33
00:01:12,880 –> 00:01:15,160
into a tenant-wide impersonation machine.
34
00:01:15,160 –> 00:01:19,480
HR messages must be pristine, who sent what, when and as whom.
35
00:01:19,480 –> 00:01:22,120
With shared passwords and mailbox rights attribution blurs,
36
00:01:22,120 –> 00:01:24,000
was it the flow, the admin, the intern
37
00:01:24,000 –> 00:01:27,240
with the cashed outlook profile, your audit trail is vibes.
38
00:01:27,240 –> 00:01:29,120
Audit blindness is more than annoying.
39
00:01:29,120 –> 00:01:30,480
It’s non-compliant.
40
00:01:30,480 –> 00:01:32,920
When an offer letter goes out at 2.14 a.m.,
41
00:01:32,920 –> 00:01:35,080
you need a clean line to the non-human identity
42
00:01:35,080 –> 00:01:37,760
that issued the call plus the policy that allowed it.
43
00:01:37,760 –> 00:01:39,800
Delegated tokens issued to a user account
44
00:01:39,800 –> 00:01:41,240
don’t give you that clarity.
45
00:01:41,240 –> 00:01:43,840
And when tenant restrictions evolve, as they do,
46
00:01:43,840 –> 00:01:46,840
delegated flows inherit breakage silently.
47
00:01:46,840 –> 00:01:48,360
You discover the blast crater later
48
00:01:48,360 –> 00:01:50,920
when managers ask why nobody received policy updates
49
00:01:50,920 –> 00:01:52,960
on time, reliability takes a beating too.
50
00:01:52,960 –> 00:01:54,760
Delegated tokens are short-lived and coupled
51
00:01:54,760 –> 00:01:56,040
to interactive behavior.
52
00:01:56,040 –> 00:01:58,160
Flows wake up, find the token expired,
53
00:01:58,160 –> 00:02:00,600
and either fail hard or bounce between retreats
54
00:02:00,600 –> 00:02:02,320
until they duplicate sends.
55
00:02:02,320 –> 00:02:03,640
The help desk gets a ticket.
56
00:02:03,640 –> 00:02:04,720
Governance gets blamed.
57
00:02:04,720 –> 00:02:07,000
Everyone matters about power-automate being flaky
58
00:02:07,000 –> 00:02:08,560
when the problem is your auth model.
59
00:02:08,560 –> 00:02:09,640
And let’s talk compliance.
60
00:02:09,640 –> 00:02:11,440
Email isn’t a casual transport layer.
61
00:02:11,440 –> 00:02:13,640
It’s regulated infrastructure.
62
00:02:13,640 –> 00:02:16,120
HR notices, policy acknowledgments,
63
00:02:16,120 –> 00:02:17,800
and termination communications often
64
00:02:17,800 –> 00:02:20,440
sit inside legal and audit requirements.
65
00:02:20,440 –> 00:02:22,320
Just make it send is not a strategy.
66
00:02:22,320 –> 00:02:23,800
It’s negligence with HTML.
67
00:02:23,800 –> 00:02:26,760
Now you might be thinking, but our conditional access
68
00:02:26,760 –> 00:02:28,560
exempts the service account.
69
00:02:28,560 –> 00:02:30,360
Congratulations, you’ve bypassed the controls
70
00:02:30,360 –> 00:02:31,680
that protect your tenant.
71
00:02:31,680 –> 00:02:33,880
You reduced friction by removing the seat belt,
72
00:02:33,880 –> 00:02:35,760
also, exemptions drift.
73
00:02:35,760 –> 00:02:38,800
A well-meaning change to a CA policy breaks your exception
74
00:02:38,800 –> 00:02:39,920
or worse broadens it.
75
00:02:39,920 –> 00:02:42,360
You don’t discover it until the flow phase plans
76
00:02:42,360 –> 00:02:44,680
or start sending from the wrong identity
77
00:02:44,680 –> 00:02:46,840
because someone fixed it at the mailbox level.
78
00:02:46,840 –> 00:02:48,840
Everything changes when you stop pretending a robot
79
00:02:48,840 –> 00:02:49,840
is a person.
80
00:02:49,840 –> 00:02:51,920
Applications need non-human identities
81
00:02:51,920 –> 00:02:54,920
with machine-grade auth, certificates, or client secrets
82
00:02:54,920 –> 00:02:57,160
and permissions that are precise, inspectable,
83
00:02:57,160 –> 00:03:00,000
and revocable without touching user mailboxes.
84
00:03:00,000 –> 00:03:01,280
Enter app registrations.
85
00:03:01,280 –> 00:03:03,560
You grant mail send at the application scope,
86
00:03:03,560 –> 00:03:05,160
no delegated nonsense, and then you
87
00:03:05,160 –> 00:03:07,560
fence that power with application access policies.
88
00:03:07,560 –> 00:03:10,360
So the app can send as only the mailboxes you explicitly
89
00:03:10,360 –> 00:03:12,120
allow, not helpfully all.
90
00:03:12,120 –> 00:03:13,600
Precisely the ones you choose.
91
00:03:13,600 –> 00:03:16,360
This is where attribution and audit finally makes sense.
92
00:03:16,360 –> 00:03:18,320
Graph sign-in logs tie calls to the app.
93
00:03:18,320 –> 00:03:20,680
Exchange and purview trails show the mailbox,
94
00:03:20,680 –> 00:03:22,320
the operation, the time.
95
00:03:22,320 –> 00:03:25,480
You can export diagnostics to log analytics or your CM,
96
00:03:25,480 –> 00:03:28,040
correlate by client request ID and request ID,
97
00:03:28,040 –> 00:03:30,400
and answer the one question audits always ask.
98
00:03:30,400 –> 00:03:33,280
Who did what using which identity under which policy?
99
00:03:33,280 –> 00:03:34,560
And reliability?
100
00:03:34,560 –> 00:03:36,480
Tokens are obtained via client credentials.
101
00:03:36,480 –> 00:03:39,200
No MFA prompts, no browser popups, no passwords,
102
00:03:39,200 –> 00:03:41,200
expiring at midnight on quarter end.
103
00:03:41,200 –> 00:03:44,320
Access tokens live for about an hour, which is predictable.
104
00:03:44,320 –> 00:03:47,840
Your flow requests a new one, sends the mail, captures headers, moves on.
105
00:03:47,840 –> 00:03:49,240
No drama, no duplicates storm.
106
00:03:49,240 –> 00:03:50,520
So here’s the foundation.
107
00:03:50,520 –> 00:03:52,360
Service accounts sabotage your flows
108
00:03:52,360 –> 00:03:54,280
because they conflate human authentication
109
00:03:54,280 –> 00:03:57,560
with machine tasks, invite over privilege, erase attribution,
110
00:03:57,560 –> 00:04:00,440
and collapse the second conditional access evolves.
111
00:04:00,440 –> 00:04:02,120
You don’t fix that with another exception.
112
00:04:02,120 –> 00:04:04,200
You fix it by giving the machine its own identity
113
00:04:04,200 –> 00:04:06,000
and a fence it can’t climb.
114
00:04:06,000 –> 00:04:09,320
Architecture, app registration, plus graph is the professional standard.
115
00:04:09,320 –> 00:04:10,520
Enter app registration.
116
00:04:10,520 –> 00:04:12,640
Not a person in a trench coat pretending to be a robot,
117
00:04:12,640 –> 00:04:14,320
but an actual non-human identity
118
00:04:14,320 –> 00:04:16,360
with its own credentials and permissions.
119
00:04:16,360 –> 00:04:19,200
It authenticates with client credentials, certificate, or secret,
120
00:04:19,200 –> 00:04:21,640
so there’s no MFA bingo, no password roulette.
121
00:04:21,640 –> 00:04:24,760
It’s predictable and predictability is the oxygen of automation.
122
00:04:24,760 –> 00:04:26,200
You start with least privilege.
123
00:04:26,200 –> 00:04:29,680
And yes, average user that phrase has meaning, grant the app the mail.
124
00:04:29,680 –> 00:04:33,040
Send application permission, application not delegated.
125
00:04:33,040 –> 00:04:35,000
Delegated means act as a user.
126
00:04:35,000 –> 00:04:38,560
Application means act as itself, which is exactly what your flow is itself.
127
00:04:38,560 –> 00:04:40,680
Nothing more, nothing less.
128
00:04:40,680 –> 00:04:44,280
Now mail, send at application scope is powerful, too powerful
129
00:04:44,280 –> 00:04:45,440
if you leave it hanging open.
130
00:04:45,440 –> 00:04:46,120
The truth?
131
00:04:46,120 –> 00:04:49,160
Without a fence, the app can technically send as an email box.
132
00:04:49,160 –> 00:04:51,440
That’s not a feature, that’s an attack surface.
133
00:04:51,440 –> 00:04:55,160
So we add the fence, application access policies in exchange online.
134
00:04:55,160 –> 00:04:58,280
These policies tell exchange even though the app holds mail.
135
00:04:58,280 –> 00:05:00,760
Send it can only act for these mailboxes.
136
00:05:00,760 –> 00:05:03,960
Think digital keycard program to open only the HR mailboxes,
137
00:05:03,960 –> 00:05:06,360
not the CEOs, not the cafeteria newsletter.
138
00:05:06,360 –> 00:05:07,480
Precision.
139
00:05:07,480 –> 00:05:08,720
The pattern is simple.
140
00:05:08,720 –> 00:05:12,240
Create a mail-enabled security group, call it HR transactional senders
141
00:05:12,240 –> 00:05:13,320
if you must be literal.
142
00:05:13,320 –> 00:05:16,880
Add only the mailboxes that represent your HR communications.
143
00:05:16,880 –> 00:05:20,600
Offers a policy at termination set.
144
00:05:20,600 –> 00:05:22,480
Then bind your app registration to that group
145
00:05:22,480 –> 00:05:24,280
using an application access policy.
146
00:05:24,280 –> 00:05:25,880
Exchange becomes the bouncer.
147
00:05:25,880 –> 00:05:27,280
The app shows its ID.
148
00:05:27,280 –> 00:05:28,720
Exchange checks the list.
149
00:05:28,720 –> 00:05:31,840
If the mailbox isn’t in the group 403, door stays closed.
150
00:05:31,840 –> 00:05:33,520
No drama, just enforcement.
151
00:05:33,520 –> 00:05:36,200
Token acquisition uses the client credentials flow.
152
00:05:36,200 –> 00:05:38,160
The access token lives for roughly an hour,
153
00:05:38,160 –> 00:05:41,520
long enough to do useful work, short enough to limit blast radius.
154
00:05:41,520 –> 00:05:44,400
Your flow requests a token, calls graph and moves on.
155
00:05:44,400 –> 00:05:47,800
No pop-ups, no approved sign-in on someone’s phone at midnight.
156
00:05:47,800 –> 00:05:50,160
Because repeat after me, it’s not a person.
157
00:05:50,160 –> 00:05:51,840
Auditability gets an upgrade.
158
00:05:51,840 –> 00:05:55,320
With graph, the sign-in logs tie activity to the app’s service principle.
159
00:05:55,320 –> 00:05:58,440
Exchange audit shows senders with the target mailbox.
160
00:05:58,440 –> 00:06:00,760
Per view holds the compliance breadcrumbs.
161
00:06:00,760 –> 00:06:03,560
You include a client request ID header on every call.
162
00:06:03,560 –> 00:06:05,240
Graph returns a request ID in date.
163
00:06:05,240 –> 00:06:07,680
Those three values are your tracing trinity.
164
00:06:07,680 –> 00:06:09,560
When someone asks who sent that offer,
165
00:06:09,560 –> 00:06:12,720
you answer with a GUID and a timestamp instead of a shrug.
166
00:06:12,720 –> 00:06:14,600
Compare that to your current mess.
167
00:06:14,600 –> 00:06:17,680
Ambiguous shared accounts, fuzzy send-days permissions,
168
00:06:17,680 –> 00:06:21,200
and email headers that read like a crime novel written by committee.
169
00:06:21,200 –> 00:06:23,200
With app registration plus policy scoping,
170
00:06:23,200 –> 00:06:24,920
attribution is machine clean.
171
00:06:24,920 –> 00:06:27,600
You can export enter sign-ins, directory audit,
172
00:06:27,600 –> 00:06:31,040
and exchange logs to log analytics or your seam set alerts for anomalies
173
00:06:31,040 –> 00:06:33,040
and actually see patterns instead of guessing them.
174
00:06:33,040 –> 00:06:35,240
And yes, conditional access, here’s the important bit.
175
00:06:35,240 –> 00:06:38,040
Client credentials flows aren’t subject to user MFA.
176
00:06:38,040 –> 00:06:39,760
That’s not a loophole, it’s the design.
177
00:06:39,760 –> 00:06:42,320
You enforce safety at the permission layer and the policy fence,
178
00:06:42,320 –> 00:06:43,840
not with interactive challenges.
179
00:06:43,840 –> 00:06:45,840
Tenant restrictions, they still matter, for example,
180
00:06:45,840 –> 00:06:48,440
blocking legacy auth or constraining app types.
181
00:06:48,440 –> 00:06:50,800
But your app’s path is explicit and documentable.
182
00:06:50,800 –> 00:06:53,480
You don’t need a special carve-out for a fake user account.
183
00:06:53,480 –> 00:06:56,160
You need the right app permissions and the exchange access policy.
184
00:06:56,160 –> 00:06:59,640
That’s governance, not vibes, reliability steps forward, too.
185
00:06:59,640 –> 00:07:03,240
Because the app identity doesn’t expire its password like a board human.
186
00:07:03,240 –> 00:07:06,720
You’re not scheduling a quarterly who broke the flow of investigation.
187
00:07:06,720 –> 00:07:08,800
Certificates can be rotated on schedule.
188
00:07:08,800 –> 00:07:11,840
Secrets can be stored in a vault and rolled with change control.
189
00:07:11,840 –> 00:07:14,240
The flow keeps running because the contract is clear.
190
00:07:14,240 –> 00:07:17,120
App proves itself, exchange enforces scope,
191
00:07:17,120 –> 00:07:20,880
graph delivers the payload, HR use case mapping becomes straightforward.
192
00:07:20,880 –> 00:07:22,560
The security group is your ring fence.
193
00:07:22,560 –> 00:07:24,880
Need to add a new sender for onboarding season.
194
00:07:24,880 –> 00:07:26,440
Add the mailbox to the group.
195
00:07:26,440 –> 00:07:28,040
Need to revoke after a campaign.
196
00:07:28,040 –> 00:07:31,160
Remove it, no reprimissioning the app, no editing ten flows.
197
00:07:31,160 –> 00:07:33,040
The boundary lives where it belongs.
198
00:07:33,040 –> 00:07:36,240
In exchanges policy, visible, auditable and testable,
199
00:07:36,240 –> 00:07:39,360
essentially this architecture separates concerns cleanly.
200
00:07:39,360 –> 00:07:41,240
Identity, app registration,
201
00:07:41,240 –> 00:07:44,360
capability, mail, send at application scope,
202
00:07:44,360 –> 00:07:46,440
guard rail, application access policy,
203
00:07:46,440 –> 00:07:49,000
restricting target mailboxes, transport,
204
00:07:49,000 –> 00:07:51,120
Microsoft graph, telemetry,
205
00:07:51,120 –> 00:07:54,520
entra, exchange, purview, all stitched with request IDs.
206
00:07:54,520 –> 00:07:57,280
It’s boring in the best way like a well run airport.
207
00:07:57,280 –> 00:08:00,440
Plains land, planes take off, nobody argues with the runway lights.
208
00:08:00,440 –> 00:08:01,800
This is the professional standard,
209
00:08:01,800 –> 00:08:03,760
not because it’s trendy, but because it’s resilient,
210
00:08:03,760 –> 00:08:05,320
inspecable and reversible.
211
00:08:05,320 –> 00:08:07,280
You can prove who can send, who did send,
212
00:08:07,280 –> 00:08:10,560
and who can’t with a configuration diff instead of folklore.
213
00:08:10,560 –> 00:08:12,320
If you insist on service accounts,
214
00:08:12,320 –> 00:08:13,800
you’re announcing to your future self
215
00:08:13,800 –> 00:08:15,840
that you prefer outages with side effects.
216
00:08:15,840 –> 00:08:18,720
Use an app, fence it, log it, then sleep.
217
00:08:18,720 –> 00:08:20,920
Implementation part one, lock down sending
218
00:08:20,920 –> 00:08:22,840
with application access policies.
219
00:08:22,840 –> 00:08:24,240
Okay, so here’s the build.
220
00:08:24,240 –> 00:08:25,880
We’re giving the machine an identity
221
00:08:25,880 –> 00:08:29,240
and we’re fencing it so it can only send from HR approved mailboxes.
222
00:08:29,240 –> 00:08:31,080
Precision first, convenience later.
223
00:08:31,080 –> 00:08:33,640
Step one, create the app and grant the right permission.
224
00:08:33,640 –> 00:08:36,160
In Microsoft, enter a register a new application,
225
00:08:36,160 –> 00:08:40,000
call it HR transactional mail if names help you think straight.
226
00:08:40,000 –> 00:08:43,120
Capture the application client ID and directory tenant ID
227
00:08:43,120 –> 00:08:46,600
add a client credential ID Leon X 509 certificate,
228
00:08:46,600 –> 00:08:48,520
find a secret if you must,
229
00:08:48,520 –> 00:08:51,520
stored in a vault and rotated like a grownup.
230
00:08:51,520 –> 00:08:55,040
Under API permissions at Microsoft Graph application permissions mail,
231
00:08:55,040 –> 00:08:59,160
send then grant admin consent, not delegated application
232
00:08:59,160 –> 00:09:01,600
because the app is sending as itself under policy,
233
00:09:01,600 –> 00:09:03,040
not borrowing a human.
234
00:09:03,040 –> 00:09:05,120
Step two, create the ring fence.
235
00:09:05,120 –> 00:09:07,600
In exchange online, you need a mail enabled security group
236
00:09:07,600 –> 00:09:09,440
that represents allowed senders.
237
00:09:09,440 –> 00:09:12,680
Name it HR transactional senders add only the mailboxes
238
00:09:12,680 –> 00:09:15,320
you want the app to act for offers at Contoso,
239
00:09:15,320 –> 00:09:18,920
come policy at contoso.com terminations at contoso.com.
240
00:09:18,920 –> 00:09:21,360
Yes, just those, not everyone for convenience.
241
00:09:21,360 –> 00:09:23,280
That’s how incidents are manufactured.
242
00:09:23,280 –> 00:09:25,200
Step three, bind the app to the fence
243
00:09:25,200 –> 00:09:26,840
with an application access policy.
244
00:09:26,840 –> 00:09:29,840
This is the perimeter fire up exchange online power shell.
245
00:09:29,840 –> 00:09:32,280
You’ll need the apps service principle ID.
246
00:09:32,280 –> 00:09:36,720
That’s the enterprise application object in entra then new application
247
00:09:36,720 –> 00:09:40,240
access policy, app ID, policy scope group ID,
248
00:09:40,240 –> 00:09:43,680
HR transactional senders at contoso.com.
249
00:09:43,680 –> 00:09:47,680
Access write, restrict access, description, HR send scope.
250
00:09:47,680 –> 00:09:49,800
That single command is the difference between mail,
251
00:09:49,800 –> 00:09:51,760
send can impersonate the tenant and mail,
252
00:09:51,760 –> 00:09:53,920
send can only send us these mailboxes.
253
00:09:53,920 –> 00:09:55,400
Exchange is now the bouncer.
254
00:09:55,400 –> 00:09:57,680
The app shows its badge, exchange checks the list,
255
00:09:57,680 –> 00:10:00,960
you verify the policy with test application access policy.
256
00:10:00,960 –> 00:10:02,920
Example, test application access policy,
257
00:10:02,920 –> 00:10:04,960
app ID identity offers at contoso.
258
00:10:04,960 –> 00:10:07,840
Compton sort expect access check result granted.
259
00:10:07,840 –> 00:10:11,720
Then try a mailbox not in the group test application access policy,
260
00:10:11,720 –> 00:10:16,080
app ID identity CEO at contoso.com.expect access check result.
261
00:10:16,080 –> 00:10:18,120
Denied if you see granted where you shouldn’t,
262
00:10:18,120 –> 00:10:19,240
you did something wrong.
263
00:10:19,240 –> 00:10:21,000
Fix it before congratulating yourself.
264
00:10:21,000 –> 00:10:24,280
Now align with conditional access and MFA expectations.
265
00:10:24,280 –> 00:10:26,120
Client credentials aren’t interactive.
266
00:10:26,120 –> 00:10:30,160
CA policies targeting user sign-in controls and MFA prompts
267
00:10:30,160 –> 00:10:32,720
don’t apply to an app asserting its own identity.
268
00:10:32,720 –> 00:10:35,200
That’s not a gap, that’s the model, documented.
269
00:10:35,200 –> 00:10:36,920
Your tenant restrictions still matter.
270
00:10:36,920 –> 00:10:39,600
Block legacy protocols restrict app consent to admins,
271
00:10:39,600 –> 00:10:42,840
require certificates for confidential clients if you’re serious.
272
00:10:42,840 –> 00:10:46,040
The key is you’re not creating risky user exceptions.
273
00:10:46,040 –> 00:10:48,920
You’re using an app with least privilege and an exchange fence.
274
00:10:48,920 –> 00:10:51,560
Let’s talk PowerShell prerequisites so you don’t trip.
275
00:10:51,560 –> 00:10:53,800
Use the Exchange Online Management module.
276
00:10:53,800 –> 00:10:55,480
Connect Exchange Online with an account
277
00:10:55,480 –> 00:10:58,000
that can manage application access policies.
278
00:10:58,000 –> 00:11:00,080
Ensure the group is mail enabled and resolvable
279
00:11:00,080 –> 00:11:03,480
by primary SMTP address in policy scope group ID.
280
00:11:03,480 –> 00:11:06,680
And yes, the app it in the policy can be the application client ID.
281
00:11:06,680 –> 00:11:08,920
Exchange figures out the service principle.
282
00:11:08,920 –> 00:11:11,200
If you’ve duplicated objects across directories,
283
00:11:11,200 –> 00:11:11,880
that’s on you.
284
00:11:11,880 –> 00:11:13,120
Keep environments clean.
285
00:11:13,120 –> 00:11:14,600
Graph tracing is not optional.
286
00:11:14,600 –> 00:11:17,600
Every send request should include a client request ID header,
287
00:11:17,600 –> 00:11:18,960
a guide you generate.
288
00:11:18,960 –> 00:11:21,960
Graph will echo back request ID and date.
289
00:11:21,960 –> 00:11:23,880
In your flows capture both response headers
290
00:11:23,880 –> 00:11:25,600
and store them in your error log.
291
00:11:25,600 –> 00:11:28,400
Request ID, client request ID, date,
292
00:11:28,400 –> 00:11:30,760
sender, recipients outcome.
293
00:11:30,760 –> 00:11:33,200
When an HR manager says, did the offer go?
294
00:11:33,200 –> 00:11:33,720
You don’t guess.
295
00:11:33,720 –> 00:11:36,000
You search by GUID, reconcile with enter sign-ins
296
00:11:36,000 –> 00:11:38,160
and exchange audit and answer with receipts.
297
00:11:38,160 –> 00:11:40,480
Now test the perimeter with real calls.
298
00:11:40,480 –> 00:11:43,520
Acquire a token via client credentials for HTTPS
299
00:11:43,520 –> 00:11:46,720
thus slash graph, Microsoft.com default.
300
00:11:46,720 –> 00:11:50,520
Attempt, post, v1, users offers at contoso.com,
301
00:11:50,520 –> 00:11:52,200
send mail with a minimal payload.
302
00:11:52,200 –> 00:11:52,760
It should work.
303
00:11:52,760 –> 00:11:54,720
Attempt the same call with CEO at contoso.
304
00:11:54,720 –> 00:11:55,240
Come.
305
00:11:55,240 –> 00:11:57,360
You should get 403 with an error code
306
00:11:57,360 –> 00:12:00,800
like error access denied or authorization request denied.
307
00:12:00,800 –> 00:12:02,160
That’s the policy doing its job.
308
00:12:02,160 –> 00:12:04,080
If you see 401, your token is wrong.
309
00:12:04,080 –> 00:12:06,560
If you see 403 on an allowed mailbox,
310
00:12:06,560 –> 00:12:08,600
your policy scope or group membership is wrong
311
00:12:08,600 –> 00:12:10,320
or you forgot admin consent.
312
00:12:10,320 –> 00:12:11,200
This isn’t magic.
313
00:12:11,200 –> 00:12:12,080
It’s plumbing.
314
00:12:12,080 –> 00:12:13,560
Check each joint.
315
00:12:13,560 –> 00:12:15,600
Document tenant alignment decisions.
316
00:12:15,600 –> 00:12:19,040
Write down that CA/MFA don’t gate client credentials.
317
00:12:19,040 –> 00:12:20,680
That risk is mitigated by mail.
318
00:12:20,680 –> 00:12:22,320
Send at application scope,
319
00:12:22,320 –> 00:12:24,000
plus an application access policy,
320
00:12:24,000 –> 00:12:25,880
restricting target mailboxes.
321
00:12:25,880 –> 00:12:29,160
Note secret or certificate storage, key vault,
322
00:12:29,160 –> 00:12:32,000
rotation cadence, and who can modify the policy.
323
00:12:32,000 –> 00:12:34,160
If governance can’t read it, it didn’t happen.
324
00:12:34,160 –> 00:12:36,200
A quick micro story to keep you honest.
325
00:12:36,200 –> 00:12:39,720
Last week a team asked why their HR flow randomly failed.
326
00:12:39,720 –> 00:12:41,800
The service account password expired.
327
00:12:41,800 –> 00:12:42,960
When they rushed to fix it,
328
00:12:42,960 –> 00:12:46,560
someone gave it send A’s on a shared mailbox used for newsletters.
329
00:12:46,560 –> 00:12:49,320
Within hours automated HR mail and marketing mail blended,
330
00:12:49,320 –> 00:12:50,160
audit was a mess.
331
00:12:50,160 –> 00:12:52,080
We shifted them to an app added mail,
332
00:12:52,080 –> 00:12:54,720
send, created the HR transactional senders group,
333
00:12:54,720 –> 00:12:57,560
bound the policy and spoiler traceability returned.
334
00:12:57,560 –> 00:12:59,040
That’s the power of the fans.
335
00:12:59,040 –> 00:13:00,640
Finally regression proofing.
336
00:13:00,640 –> 00:13:02,400
After you create or change the policy,
337
00:13:02,400 –> 00:13:06,520
run test application access policy for each HR mailbox in scope
338
00:13:06,520 –> 00:13:07,840
and a few out of scope.
339
00:13:07,840 –> 00:13:09,520
Bake those tests into a runbook.
340
00:13:09,520 –> 00:13:11,160
On secret or certificate rotation day,
341
00:13:11,160 –> 00:13:13,480
validate token acquisition, then run policy tests,
342
00:13:13,480 –> 00:13:16,360
then send a deliberate test mail with a unique header.
343
00:13:16,360 –> 00:13:18,600
Xtrace intent, HR policy check.
344
00:13:18,600 –> 00:13:20,560
So you can find it in headers and logs.
345
00:13:20,560 –> 00:13:21,880
If you think this is overkill,
346
00:13:21,880 –> 00:13:24,160
you’ve never explained a breach to legal.
347
00:13:24,160 –> 00:13:27,520
Parameter set app identity in place, exchange and forcing scope.
348
00:13:27,520 –> 00:13:30,840
Next, we wire the actual send over graph, clean payloads,
349
00:13:30,840 –> 00:13:33,280
clean retries, no connectors yet.
350
00:13:33,280 –> 00:13:36,960
Implementation part two, graph email, send patterns and endpoints.
351
00:13:36,960 –> 00:13:38,800
Now we orchestrate the actual send.
352
00:13:38,800 –> 00:13:42,760
No connectors, no mystery, just HTTP against graph with headers you control.
353
00:13:42,760 –> 00:13:45,280
Core endpoint first, post-heart TPS such graph,
354
00:13:45,280 –> 00:13:49,800
Microsoft.com, where you want users or sender VPN, send mail.
355
00:13:49,800 –> 00:13:52,480
Replace sender VPN with the allowed mailbox,
356
00:13:52,480 –> 00:13:55,120
like offers@contoso.com/tun,
357
00:13:55,120 –> 00:13:56,840
this endpoint sends us that mailbox,
358
00:13:56,840 –> 00:13:59,480
which is exactly why the application access policy matters.
359
00:13:59,480 –> 00:14:03,680
Your body is a JSON envelope called message plus a save to send items flag.
360
00:14:03,680 –> 00:14:05,280
The minimal payload looks like this,
361
00:14:05,280 –> 00:14:07,400
conceptually not code, theater, message,
362
00:14:07,400 –> 00:14:11,880
subject message, body with content, type HTML or text and content message.
363
00:14:11,880 –> 00:14:14,920
To recipients as an array of objects with email address.
364
00:14:14,920 –> 00:14:18,160
Add CC recipients and BCC recipients arrays when needed.
365
00:14:18,160 –> 00:14:20,040
Save to send items, true for HR,
366
00:14:20,040 –> 00:14:21,720
so send items show the record.
367
00:14:21,720 –> 00:14:24,000
Faults only if you’ve planned an alternate archive.
368
00:14:24,000 –> 00:14:25,400
Attachments come in two flavors.
369
00:14:25,400 –> 00:14:28,720
For most HR scenarios offer letters, policy PDFs,
370
00:14:28,720 –> 00:14:31,680
use JSON attachments with content bytes as base64.
371
00:14:31,680 –> 00:14:35,560
Each item has name, content type and content bytes.
372
00:14:35,560 –> 00:14:38,200
Keep individual attachments sane, graph is happy,
373
00:14:38,200 –> 00:14:40,280
but your recipients gateways are not.
374
00:14:40,280 –> 00:14:42,760
If you need full MIME control, custom headers,
375
00:14:42,760 –> 00:14:45,160
S-MIME payloads, exact line endings,
376
00:14:45,160 –> 00:14:47,960
you pivot to send mail with a MIME message in base64,
377
00:14:47,960 –> 00:14:51,400
via the me sent mail equivalent for app as user scenarios,
378
00:14:51,400 –> 00:14:54,960
or you use users’ pop-osh ID messages with create plus send.
379
00:14:54,960 –> 00:14:58,520
For 99% of HR automation, the JSON model is simpler and safer.
380
00:14:58,520 –> 00:14:59,760
Headers matter.
381
00:14:59,760 –> 00:15:01,760
Always include client request ID as a guide,
382
00:15:01,760 –> 00:15:03,720
you generate per call and prefer.
383
00:15:03,720 –> 00:15:06,920
Outlook, time zone if you care about date normalization on drafts,
384
00:15:06,920 –> 00:15:08,920
though for send mail, it’s less relevant.
385
00:15:08,920 –> 00:15:11,480
Capture response headers request ID and date.
386
00:15:11,480 –> 00:15:14,120
These are your correlation anchors across graph,
387
00:15:14,120 –> 00:15:16,680
enter assignings and exchange audit.
388
00:15:16,680 –> 00:15:19,560
Now the unpleasant but necessary part, rate limiting.
389
00:15:19,560 –> 00:15:23,400
When graph returns 429, it’s not a suggestion, it’s a command.
390
00:15:23,400 –> 00:15:25,240
Respect, retry after in seconds.
391
00:15:25,240 –> 00:15:27,720
Implement exponential backoff that starts with retry after
392
00:15:27,720 –> 00:15:30,920
if present otherwise a sane default 24/8 seconds with jitter.
393
00:15:30,920 –> 00:15:34,200
Item potency is your shield against duplicate HR emails.
394
00:15:34,200 –> 00:15:38,040
Generate a stable item potency key per intended outbound message,
395
00:15:38,040 –> 00:15:40,840
compose it from the business object ID plus recipient
396
00:15:40,840 –> 00:15:43,320
and a timestamp bucket and store it.
397
00:15:43,320 –> 00:15:46,680
If a retry happens, check whether you’ve already recorded a successful send
398
00:15:46,680 –> 00:15:48,440
for that key before you fire again.
399
00:15:48,440 –> 00:15:51,480
You’re preventing the two offers, one candidate embarrassment.
400
00:15:51,480 –> 00:15:53,000
Error classes are predictable.
401
00:15:53,000 –> 00:15:55,720
401 means your token is missing or expired.
402
00:15:55,720 –> 00:15:59,320
Acquire a new access token using client credentials and replay once.
403
00:15:59,320 –> 00:16:01,000
403 is policy or permission.
404
00:16:01,000 –> 00:16:04,120
Decode the error.code in the JSON, authorization request,
405
00:16:04,120 –> 00:16:07,080
denied or error access denied usually means your mailbox
406
00:16:07,080 –> 00:16:09,400
isn’t in the application access policy group
407
00:16:09,400 –> 00:16:11,160
or admin consent didn’t happen.
408
00:16:11,160 –> 00:16:12,920
Do not retry a 403.
409
00:16:12,920 –> 00:16:16,040
Fix configuration 404 on the user path usually means
410
00:16:16,040 –> 00:16:18,040
you misspelled the sender UPN.
411
00:16:18,040 –> 00:16:19,800
5x is transit service wobble.
412
00:16:19,800 –> 00:16:22,760
Retry with back off over a new HTTP connection.
413
00:16:22,760 –> 00:16:27,240
Your flow should treat 429 and 5xx as recoverable within a small window.
414
00:16:27,240 –> 00:16:28,520
Everything else escalates.
415
00:16:28,520 –> 00:16:29,400
Security hygiene.
416
00:16:29,400 –> 00:16:31,400
Do not log bodies with PII.
417
00:16:31,400 –> 00:16:32,520
Yes, average user.
418
00:16:32,520 –> 00:16:34,280
This includes the entire offer letter.
419
00:16:34,280 –> 00:16:35,240
Log metadata.
420
00:16:35,240 –> 00:16:37,880
Client request ID, request ID, date, sender,
421
00:16:37,880 –> 00:16:41,000
recipient count, attachment count, outcome and any error.
422
00:16:41,000 –> 00:16:42,520
Code plus a redacted message.
423
00:16:42,520 –> 00:16:44,600
If you must keep a copy of the send content,
424
00:16:44,600 –> 00:16:48,120
rely on the mailboxes, send items or a governed archive.
425
00:16:48,120 –> 00:16:49,160
Not your flow logs.
426
00:16:49,160 –> 00:16:49,880
S-mime.
427
00:16:49,880 –> 00:16:52,680
If your HR notices require signing or encryption,
428
00:16:52,680 –> 00:16:53,880
you’re in MIME land.
429
00:16:53,880 –> 00:16:55,640
You’ll build the full MIME payload
430
00:16:55,640 –> 00:16:57,160
with the appropriate content type
431
00:16:57,160 –> 00:17:01,000
and transfer encoded as base 64 within the raw message.
432
00:17:01,000 –> 00:17:03,720
Application permissions can still send.
433
00:17:03,720 –> 00:17:07,080
The complexity lives in building the MIME correctly
434
00:17:07,080 –> 00:17:08,360
and managing certificates.
435
00:17:08,360 –> 00:17:10,200
For most internal policy updates,
436
00:17:10,200 –> 00:17:14,440
TLS@transportplusDKIM plus D-mark alignment is sufficient.
437
00:17:14,840 –> 00:17:17,800
Save S-mime for regulated cases where a signature is mandated.
438
00:17:17,800 –> 00:17:19,720
HR payload patterns should be templated,
439
00:17:19,720 –> 00:17:21,160
not hand-built per run.
440
00:17:21,160 –> 00:17:24,360
Store HTML templates with token placeholders, candidate name,
441
00:17:24,360 –> 00:17:26,600
start date, manager name, policy link.
442
00:17:26,600 –> 00:17:29,800
Replace at runtime, sanitize inputs and include a lightweight
443
00:17:29,800 –> 00:17:32,120
X-trace header via internet message headers
444
00:17:32,120 –> 00:17:33,480
for internal correlation.
445
00:17:33,480 –> 00:17:37,000
Like X-trace intent, HR offer, X-business id,
446
00:17:37,000 –> 00:17:38,200
12345.
447
00:17:38,200 –> 00:17:40,680
Keep custom headers minimal, some gateways
448
00:17:40,680 –> 00:17:41,880
waste strip or rewrite them.
449
00:17:41,880 –> 00:17:42,600
That’s fine.
450
00:17:42,600 –> 00:17:43,960
You log the IDs already.
451
00:17:43,960 –> 00:17:45,880
Identity deserves one more line.
452
00:17:45,880 –> 00:17:48,760
Use a stable deterministic key and record success
453
00:17:48,760 –> 00:17:51,480
before you acknowledge completion to upstream systems.
454
00:17:51,480 –> 00:17:55,080
If a retry loop kicks in, your first step is to query your log for that key.
455
00:17:55,080 –> 00:17:56,920
If found and success are bought sent.
456
00:17:56,920 –> 00:17:59,320
If found and failed with a final code, surface the error.
457
00:17:59,320 –> 00:18:00,680
If not found, proceed.
458
00:18:00,680 –> 00:18:03,080
Finally, build for burst without tripping limits,
459
00:18:03,080 –> 00:18:05,800
queue outbound messages and process in controlled concurrency
460
00:18:05,800 –> 00:18:08,360
2 to 4 parallel sensor mailbox is sensible.
461
00:18:08,360 –> 00:18:09,960
Respect retry after globally.
462
00:18:09,960 –> 00:18:12,120
When you get throttled, slow the entire worker,
463
00:18:12,120 –> 00:18:13,400
not just one thread.
464
00:18:13,400 –> 00:18:15,160
Your goal isn’t maximum throughput,
465
00:18:15,160 –> 00:18:17,720
it’s guaranteed delivery without collateral damage.
466
00:18:17,720 –> 00:18:21,160
We’ve now turned send an email into a disciplined API call,
467
00:18:21,160 –> 00:18:24,280
scoped identity, clean payloads, predictable retries,
468
00:18:24,280 –> 00:18:25,480
and zero drama.
469
00:18:25,480 –> 00:18:28,040
Next, we wrap it in a power automate custom connector
470
00:18:28,040 –> 00:18:29,880
so every flow gets the same guardrails
471
00:18:29,880 –> 00:18:31,400
without reinventing anything.
472
00:18:31,400 –> 00:18:33,000
The implementation part three,
473
00:18:33,000 –> 00:18:35,080
power automate custom connector schema.
474
00:18:35,080 –> 00:18:36,440
Now we make this repeatable.
475
00:18:36,440 –> 00:18:38,040
A custom connector turns,
476
00:18:38,040 –> 00:18:41,400
careful HTTP into a single, governed action.
477
00:18:41,400 –> 00:18:44,040
Your flows can reuse without copy-pacing headers
478
00:18:44,040 –> 00:18:46,440
and retry logic like a teenager’s homework.
479
00:18:46,440 –> 00:18:47,640
Start with basics.
480
00:18:47,640 –> 00:18:49,560
Base URL is RT-DPS-BARSH,
481
00:18:49,560 –> 00:18:53,400
graph-microsoft.com security is 002 with client credentials.
482
00:18:53,400 –> 00:18:55,400
No user delegation, no interactive login.
483
00:18:55,400 –> 00:18:57,480
Define the token URL as your tenants,
484
00:18:57,480 –> 00:18:59,320
Microsoft identity endpoint,
485
00:18:59,320 –> 00:19:01,400
and the scope as art default,
486
00:19:01,400 –> 00:19:03,240
which instructs graph to honor the app’s
487
00:19:03,240 –> 00:19:05,400
granted application permissions, including mail,
488
00:19:05,400 –> 00:19:08,280
send, store the client secret or certificate reference
489
00:19:08,280 –> 00:19:09,880
in a secure connection parameter,
490
00:19:09,880 –> 00:19:12,760
ideally tied to an Azure key vault-backed connection,
491
00:19:12,760 –> 00:19:14,920
so creators can’t exfiltrate credentials
492
00:19:14,920 –> 00:19:16,920
by helpfully previewing settings.
493
00:19:16,920 –> 00:19:21,400
Define one action, send mail, method, post, path, v1,
494
00:19:21,400 –> 00:19:23,080
user’s more sender, send mail,
495
00:19:23,080 –> 00:19:25,880
create a required path parameter called sender,
496
00:19:25,880 –> 00:19:27,560
validated as an email address.
497
00:19:27,560 –> 00:19:28,680
Yes, validated.
498
00:19:28,680 –> 00:19:31,400
If the sender isn’t in your application access policy group,
499
00:19:31,400 –> 00:19:34,440
the call will 403 and your error object will explain why.
500
00:19:34,440 –> 00:19:36,440
Don’t guess, let exchange be the bouncer.
501
00:19:36,440 –> 00:19:38,920
Request schema should mirror graphs JSON.
502
00:19:38,920 –> 00:19:41,480
At minimum, subject, string, body,
503
00:19:41,480 –> 00:19:43,560
object with content type and content,
504
00:19:43,560 –> 00:19:45,880
two recipients, array of email addresses
505
00:19:45,880 –> 00:19:49,560
with optional cc recipients and bcc recipients arrays.
506
00:19:49,560 –> 00:19:51,320
Add attachments as an array of objects
507
00:19:51,320 –> 00:19:54,440
with name, content type, and content bytes basics for.
508
00:19:54,440 –> 00:19:58,120
Include a Boolean save to send items defaulting to true for HR.
509
00:19:58,120 –> 00:20:00,120
Add optional internet message headers
510
00:20:00,120 –> 00:20:02,120
as an array for lightweight tracing.
511
00:20:02,120 –> 00:20:03,560
Name and value pairs,
512
00:20:03,560 –> 00:20:05,960
Xtrace intent, Xbusiness id.
513
00:20:05,960 –> 00:20:07,360
Keep it small, mail gateways
514
00:20:07,360 –> 00:20:09,680
have opinions, security headers and correlation
515
00:20:09,680 –> 00:20:12,160
belong in the connector, not scattered in flows.
516
00:20:12,160 –> 00:20:14,160
Define a static header parameter,
517
00:20:14,160 –> 00:20:17,600
client request id that generates a guide per call when omitted,
518
00:20:17,600 –> 00:20:20,080
but allow override for advanced scenarios.
519
00:20:20,080 –> 00:20:21,840
Always return response headers,
520
00:20:21,840 –> 00:20:24,640
request id and date, expose them as outputs,
521
00:20:24,640 –> 00:20:26,560
so flows can lock them without spelunking
522
00:20:26,560 –> 00:20:28,480
into raw response metadata.
523
00:20:28,480 –> 00:20:31,280
Now error handling, standardize it.
524
00:20:31,280 –> 00:20:34,080
Define a normalized error object with fields.
525
00:20:34,080 –> 00:20:36,960
Status, int, code, string,
526
00:20:36,960 –> 00:20:41,440
message, string, request id, string, date, string,
527
00:20:41,440 –> 00:20:43,440
and retry after int.
528
00:20:43,440 –> 00:20:46,480
When graph returns 429, pass retry after and surface it
529
00:20:46,480 –> 00:20:48,320
for 5xx surface a retribal flag.
530
00:20:48,320 –> 00:20:51,600
For 401, return a clear acquire token failed code.
531
00:20:51,600 –> 00:20:55,600
For 403, policy denied with a message that explicitly says,
532
00:20:55,600 –> 00:20:58,480
sender not authorized by application access policy
533
00:20:58,480 –> 00:21:00,080
or permission missing.
534
00:21:00,080 –> 00:21:02,320
Save the detective work for actual mysteries.
535
00:21:02,320 –> 00:21:04,160
Connector policy’s matter.
536
00:21:04,160 –> 00:21:06,000
Throttling, implement exponential back off
537
00:21:06,000 –> 00:21:08,720
with jitter inside the connector for 429 and 5x
538
00:21:08,720 –> 00:21:10,800
up to a safe cap, say three attempts.
539
00:21:10,800 –> 00:21:12,720
Respect retry after first timeouts,
540
00:21:12,720 –> 00:21:16,480
set a sensible HTTP timeout, e.g., 60 seconds,
541
00:21:16,480 –> 00:21:18,640
and allow the flow to configure a higher ceiling
542
00:21:18,640 –> 00:21:20,000
for large attachments.
543
00:21:20,000 –> 00:21:22,160
Concurrency, if your platform supports it,
544
00:21:22,160 –> 00:21:23,760
limit parallel calls per connection
545
00:21:23,760 –> 00:21:25,680
to avoid tripping tenant throttles.
546
00:21:25,680 –> 00:21:28,640
You’re designing for steady throughput, not chaos.
547
00:21:28,640 –> 00:21:30,240
Outputs should be boring and useful.
548
00:21:30,240 –> 00:21:33,040
Return status request id, date, client request id,
549
00:21:33,040 –> 00:21:34,320
and a summary object.
550
00:21:34,320 –> 00:21:36,560
Recipients count, attachments count,
551
00:21:36,560 –> 00:21:37,760
save to send items.
552
00:21:37,760 –> 00:21:39,360
If you want to be generous, echo,
553
00:21:39,360 –> 00:21:41,040
the sender and the first to recipient
554
00:21:41,040 –> 00:21:42,800
for quick eyeballing in run history
555
00:21:42,800 –> 00:21:44,640
do not echo the entire body content.
556
00:21:44,640 –> 00:21:46,480
Your building traceability not a leak.
557
00:21:46,480 –> 00:21:47,600
In Power Automate flows,
558
00:21:47,600 –> 00:21:49,760
wrap the action in a scope named try.
559
00:21:49,760 –> 00:21:51,040
Follow with a scope named catch,
560
00:21:51,040 –> 00:21:52,560
configure to run on failure,
561
00:21:52,560 –> 00:21:53,920
and try call send mail.
562
00:21:53,920 –> 00:21:57,680
In catch, use results try to extract the connector’s error object
563
00:21:57,680 –> 00:21:59,120
and log to a govern store,
564
00:21:59,120 –> 00:22:00,480
dataverse or SharePoint,
565
00:22:00,480 –> 00:22:01,760
capturing client request,
566
00:22:01,760 –> 00:22:05,440
each request id, date, sender, recipients, status, code,
567
00:22:05,440 –> 00:22:06,240
and message.
568
00:22:06,240 –> 00:22:06,960
Then branch.
569
00:22:06,960 –> 00:22:08,640
If code is policy denied,
570
00:22:08,640 –> 00:22:11,440
alert the admin owning application access policies.
571
00:22:11,440 –> 00:22:13,120
If code is acquired token failed,
572
00:22:13,120 –> 00:22:14,720
trigger a credential runbook.
573
00:22:14,720 –> 00:22:16,320
If retry after exists,
574
00:22:16,320 –> 00:22:18,560
recue or delay intelligently.
575
00:22:18,560 –> 00:22:20,480
Add a small guardrail before sending,
576
00:22:20,480 –> 00:22:22,720
validate sender against a maintained list mirrored
577
00:22:22,720 –> 00:22:24,640
from the HR transactional sender’s group.
578
00:22:24,640 –> 00:22:26,560
It’s a fast fail that saves a round trip
579
00:22:26,560 –> 00:22:28,160
and keeps noise out of your logs.
580
00:22:28,160 –> 00:22:30,240
And yes, use the safe navigation operator,
581
00:22:30,240 –> 00:22:33,120
the question mark in expressions when accessing optional outputs
582
00:22:33,120 –> 00:22:35,280
so a missing header never crashes your flow.
583
00:22:35,280 –> 00:22:38,160
What you get is a single action that encodes the rules.
584
00:22:38,160 –> 00:22:41,200
App-out, scope sender, durable retries,
585
00:22:41,200 –> 00:22:43,920
clean errors, and first class traceability.
586
00:22:43,920 –> 00:22:44,880
Congratulations.
587
00:22:44,880 –> 00:22:46,640
You’ve replaced folklore with an interface.
588
00:22:46,640 –> 00:22:49,920
Audit, monitoring, and incident prevention.
589
00:22:49,920 –> 00:22:51,120
You’ve secured delivery.
590
00:22:51,120 –> 00:22:51,840
Now prove it.
591
00:22:51,840 –> 00:22:54,720
Security that can’t be measured is superstition in a hoodie.
592
00:22:54,720 –> 00:22:56,800
Start with audit sources that actually matter.
593
00:22:56,800 –> 00:22:59,040
Enter sign-ins for the app’s service principle,
594
00:22:59,040 –> 00:23:01,360
tell you when tokens were minted and from where.
595
00:23:01,360 –> 00:23:03,680
Directory audit logs record permission changes,
596
00:23:03,680 –> 00:23:06,080
who granted mail, send, who consented,
597
00:23:06,080 –> 00:23:07,920
who touched the enterprise application.
598
00:23:07,920 –> 00:23:10,800
Exchange audit logs tell you the mailbox operations.
599
00:23:10,800 –> 00:23:13,760
Send A’s, send on behalf, mailbox access.
600
00:23:13,760 –> 00:23:15,360
Per view holds the compliance trail.
601
00:23:15,360 –> 00:23:16,960
Route all three into log analytics
602
00:23:16,960 –> 00:23:18,800
or your CMV or diagnostic settings
603
00:23:18,800 –> 00:23:21,920
so you don’t play download CSV forensics after an incident,
604
00:23:21,920 –> 00:23:23,840
centralized or enjoy chaos.
605
00:23:23,840 –> 00:23:24,880
Your choice.
606
00:23:24,880 –> 00:23:26,560
Tire together with correlation.
607
00:23:26,560 –> 00:23:29,600
Remember the tracing trinity client request ID you generate
608
00:23:29,600 –> 00:23:31,360
plus request ID and date from graph.
609
00:23:31,360 –> 00:23:33,440
Those IDs show up across systems.
610
00:23:33,440 –> 00:23:34,720
When an HR leader asks,
611
00:23:34,720 –> 00:23:38,240
did policy updates go to 8,000 employees at 9 a.m.?
612
00:23:38,240 –> 00:23:40,080
You pivot to your structured log store,
613
00:23:40,080 –> 00:23:43,200
a dataverse table or a SharePoint list if you’re frugal.
614
00:23:43,200 –> 00:23:45,280
And query by client request ID.
615
00:23:45,280 –> 00:23:47,120
The entry links to enter sign-ins
616
00:23:47,120 –> 00:23:48,880
points to exchange audit for the mailbox
617
00:23:48,880 –> 00:23:51,360
and carries the graph request ID for cross checking.
618
00:23:51,360 –> 00:23:52,080
Mystery solved.
619
00:23:52,080 –> 00:23:53,440
No sayons required.
620
00:23:53,440 –> 00:23:55,600
Diagnostic settings aren’t a suggestion.
621
00:23:55,600 –> 00:23:57,680
Turn them on for Microsoft Graph Sign-ins
622
00:23:57,680 –> 00:24:00,640
and directory audits via intras diagnostic export.
623
00:24:00,640 –> 00:24:02,720
Exchange admin and mailbox audit logs.
624
00:24:02,720 –> 00:24:06,160
Per view audit events if your compliance team expects attestations.
625
00:24:06,160 –> 00:24:08,160
Send them to log analytics with a retention
626
00:24:08,160 –> 00:24:10,000
that matches your regulatory window.
627
00:24:10,000 –> 00:24:12,560
Yes, 90 days is not enough if you answer to audits
628
00:24:12,560 –> 00:24:13,680
with multi-year look back.
629
00:24:13,680 –> 00:24:15,360
Storage is cheaper than litigation.
630
00:24:15,360 –> 00:24:17,280
Your operational logs need structure.
631
00:24:17,280 –> 00:24:19,600
In your flow sketch block, write a single record
632
00:24:19,600 –> 00:24:22,480
with fields that future you will actually use.
633
00:24:22,480 –> 00:24:25,440
Client request ID, request ID, date, sender,
634
00:24:25,440 –> 00:24:28,320
recipient’s count, attachments count, status error code,
635
00:24:28,320 –> 00:24:31,200
redacted message, retry after seconds.
636
00:24:31,200 –> 00:24:34,400
Add intent tags, offer, policy update, termination,
637
00:24:34,400 –> 00:24:36,480
so you can pivot during incidents.
638
00:24:36,480 –> 00:24:38,720
Put a partition key on the business object ID
639
00:24:38,720 –> 00:24:40,960
if you ever want to answer, show me everything tied
640
00:24:40,960 –> 00:24:44,560
to candidate 1, 2, 3, 4, 5 without scanning the galaxy.
641
00:24:44,560 –> 00:24:47,200
Alerting is not email the admin when anything fails.
642
00:24:47,200 –> 00:24:49,680
That’s how inboxes die, build focused signals.
643
00:24:50,800 –> 00:24:53,040
Failure rate threshold, alert when more than
644
00:24:53,040 –> 00:24:55,280
x% of sense fail in 10 minutes.
645
00:24:55,280 –> 00:24:58,080
Threatlings bike, alert on clusters of photo 29
646
00:24:58,080 –> 00:25:00,000
with retry after above a threshold.
647
00:25:00,000 –> 00:25:02,080
Your flow is outrunning your tenant’s patience.
648
00:25:02,080 –> 00:25:04,160
Policy denied detection, alert immediately.
649
00:25:04,160 –> 00:25:06,000
Someone tried to send from a mailbox outside
650
00:25:06,000 –> 00:25:08,160
the application access policy scope.
651
00:25:08,160 –> 00:25:11,200
That’s either misconfiguration or an attempted escalation.
652
00:25:11,200 –> 00:25:13,520
A normalist volume.
653
00:25:13,520 –> 00:25:15,840
Detect HR blast patterns at odd hours
654
00:25:15,840 –> 00:25:17,680
or unusual recipient domains,
655
00:25:17,680 –> 00:25:19,840
correlate with tarryl and outbound spam policies
656
00:25:19,840 –> 00:25:21,760
so you don’t trip compliance landmines.
657
00:25:21,760 –> 00:25:24,800
Yes, tenant restrictions and outbound policies still apply.
658
00:25:24,800 –> 00:25:26,400
The external recipient rate limits
659
00:25:26,400 –> 00:25:28,320
and bulk sender authentication requirements
660
00:25:28,320 –> 00:25:30,160
exist to protect you and everyone else.
661
00:25:30,160 –> 00:25:33,120
Respect them, set dashboards for daily external recipient counts
662
00:25:33,120 –> 00:25:35,360
and SPF or DKM demarc alignment
663
00:25:35,360 –> 00:25:38,160
or enjoy bizarre deliverability issues you’ll blame on graph.
664
00:25:38,160 –> 00:25:40,800
Now the runbook, the thing you wish you had
665
00:25:40,800 –> 00:25:42,720
during the incident you deny will happen.
666
00:25:42,720 –> 00:25:44,800
Include, revoke and rotate,
667
00:25:44,800 –> 00:25:48,560
immediate steps to disable the app’s client secret or certificate
668
00:25:48,560 –> 00:25:51,920
with key vault integration and who’s authorised to do it.
669
00:25:51,920 –> 00:25:56,160
Policy lockdown, how to disable the application access policy temporarily
670
00:25:56,160 –> 00:25:59,200
or better, how to tighten the scope by removing mailboxes
671
00:25:59,200 –> 00:26:01,200
from the HR transactional sender’s group.
672
00:26:01,200 –> 00:26:04,880
Validation tests, exact test application access policy commands
673
00:26:04,880 –> 00:26:07,120
to confirm state before and after changes.
674
00:26:07,120 –> 00:26:09,440
Regression suite, token acquisition test,
675
00:26:09,440 –> 00:26:11,360
a controlled send to a test mailbox
676
00:26:11,360 –> 00:26:13,840
with xtrace intent, HR policy check
677
00:26:13,840 –> 00:26:17,280
and verification steps in exchange audit and log analytics.
678
00:26:17,280 –> 00:26:20,480
Rollback, how to restore prior config from documented diffs
679
00:26:20,480 –> 00:26:21,840
not memory.
680
00:26:21,840 –> 00:26:24,400
Close the loop we planted earlier, the one misstep
681
00:26:24,400 –> 00:26:27,200
that silently exposes every mailbox is skipping
682
00:26:27,200 –> 00:26:29,600
the application access policy because mail
683
00:26:29,600 –> 00:26:31,440
send is already least privileged.
684
00:26:31,440 –> 00:26:34,160
It isn’t, without the policy your app can impersonate
685
00:26:34,160 –> 00:26:35,840
the tenant’s entire directory.
686
00:26:35,840 –> 00:26:38,080
The fence is what prevents lateral blast radius.
687
00:26:38,080 –> 00:26:40,960
It also gives you a crisp error, 403 policy denied
688
00:26:40,960 –> 00:26:43,040
when someone wonders outside the lane.
689
00:26:43,040 –> 00:26:45,040
Incidents become containable by design.
690
00:26:45,040 –> 00:26:47,760
Last piece, ownership, assign a human owner for the app,
691
00:26:47,760 –> 00:26:50,560
the policy and the connector, document contact methods
692
00:26:50,560 –> 00:26:52,960
in the enterprise application’s directory metadata.
693
00:26:52,960 –> 00:26:56,080
When the alert files are 214 AM, the on-call engineer
694
00:26:56,080 –> 00:26:58,640
shouldn’t be spelunking SharePoint to find a name.
695
00:26:58,640 –> 00:27:00,240
Efficiency is not an accident,
696
00:27:00,240 –> 00:27:02,800
it’s documentation plus accountability.
697
00:27:02,800 –> 00:27:05,440
You’ve now moved from, I hope it works too,
698
00:27:05,440 –> 00:27:08,480
I can prove it, detect drift and recover fast.
699
00:27:08,480 –> 00:27:11,040
That’s incident prevention, not incident theater.
700
00:27:11,040 –> 00:27:13,280
Here’s the point, stop impersonating people
701
00:27:13,280 –> 00:27:14,560
with brittle service accounts.
702
00:27:14,560 –> 00:27:16,080
Use an app registration with mail,
703
00:27:16,080 –> 00:27:18,400
send, fence it with an application access policy,
704
00:27:18,400 –> 00:27:20,960
send through graph and log like an adult.
705
00:27:20,960 –> 00:27:24,320
If this saved you from another midnight outage, subscribe.
706
00:27:24,320 –> 00:27:26,160
Next, grab the exact power shell,
707
00:27:26,160 –> 00:27:28,800
graph payload schemers and the custom connector definition.
708
00:27:28,800 –> 00:27:31,600
I’m walking through each command and endpoint in the follow-up.
709
00:27:31,600 –> 00:27:33,600
Implemented before your next HR cycle,
710
00:27:33,600 –> 00:27:35,360
so your offer send means delivered,
711
00:27:35,360 –> 00:27:36,960
auditable and scoped.
712
00:27:36,960 –> 00:27:39,040
Entropy wins by default, choose structure.