Stop Sabotaging Your Power Automate Email Flows

Mirko PetersPodcasts11 minutes ago2 Views


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.





Source link

0 Votes: 0 Upvotes, 0 Downvotes (0 Points)

Leave a reply

Follow
Search
Loading

Signing-in 3 seconds...

Signing-up 3 seconds...