<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>MSB365</title>
	<atom:link href="https://www.msb365.blog/?feed=rss2" rel="self" type="application/rss+xml" />
	<link>https://www.msb365.blog</link>
	<description>The Microsoft Blog</description>
	<lastBuildDate>Mon, 27 Apr 2026 14:36:48 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://msb365.abstergo.ch/wp-content/uploads/2025/11/cropped-Logo_MSB-32x32.png</url>
	<title>MSB365</title>
	<link>https://www.msb365.blog</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>How to lock down Exchange Online so EOP refuses direct external mail</title>
		<link>https://www.msb365.blog/?p=6164</link>
					<comments>https://www.msb365.blog/?p=6164#respond</comments>
		
		<dc:creator><![CDATA[drago]]></dc:creator>
		<pubDate>Mon, 27 Apr 2026 14:36:48 +0000</pubDate>
				<category><![CDATA[Microsoft 365]]></category>
		<category><![CDATA[MS Exchange]]></category>
		<guid isPermaLink="false">https://www.msb365.blog/?p=6164</guid>

					<description><![CDATA[Microsoft 365 · Email Security A practical, step-by-step guide for tenants running a centralized mail flow with a third-party Secure Email Gateway (SEG) — and discovering that mail and spoofing attempts still slip in directly through Exchange Online Protection. Security-relevant Exchange Online EOP / Defender Production-ready The problem in a nutshell In a centralized mail [&#8230;]]]></description>
										<content:encoded><![CDATA[<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Fraunces:opsz,wght@9..144,400;9..144,600;9..144,800&family=Inter+Tight:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
.eop-lockdown-post{
  --bg:#fbfaf7;
  --bg-soft:#f3f1ec;
  --bg-elev:#ffffff;
  --line:#d8d4c8;
  --line-soft:#e7e3d8;
  --text:#1a1d23;
  --text-soft:#52596a;
  --text-dim:#8a8f9c;
  --accent:#c2410c;
  --accent-deep:#9a3412;
  --ok:#15803d;
  --warn:#a16207;
  --danger:#b91c1c;
  --info:#1d4ed8;
  --code-bg:#f6f3ec;</p>
<p>  background:var(--bg);
  color:var(--text);
  font-family:'Inter Tight', system-ui, -apple-system, sans-serif;
  line-height:1.65;
  font-size:16px;
  -webkit-font-smoothing:antialiased;
  padding:48px 40px;
  border-radius:12px;
  border:1px solid var(--line-soft);
  max-width:920px;
  margin:0 auto;
  counter-reset:sec;
}</p>
<p>/* Reset only inside the post wrapper */
.eop-lockdown-post *{box-sizing:border-box}
.eop-lockdown-post p,
.eop-lockdown-post h1,
.eop-lockdown-post h2,
.eop-lockdown-post h3,
.eop-lockdown-post h4,
.eop-lockdown-post ul,
.eop-lockdown-post ol{margin:0;padding:0}</p>
<p>/* ─── Hero / Intro ────────────────── */
.eop-lockdown-post .hero{
  margin-bottom:48px;padding-bottom:32px;
  border-bottom:1px solid var(--line);
}
.eop-lockdown-post .eyebrow{
  font-family:'JetBrains Mono', monospace;
  font-size:12px;color:var(--accent);
  letter-spacing:2px;text-transform:uppercase;
  margin-bottom:18px;
  display:inline-flex;align-items:center;gap:10px;
}
.eop-lockdown-post .eyebrow::before{
  content:"";width:24px;height:1px;background:var(--accent);
  display:inline-block;
}
.eop-lockdown-post h1.title{
  font-family:'Fraunces', Georgia, serif;
  font-size:clamp(32px, 4.6vw, 48px);
  line-height:1.08;
  font-weight:600;
  letter-spacing:-0.02em;
  margin-bottom:20px;
  color:var(--text);
}
.eop-lockdown-post h1.title em{
  font-style:italic;color:var(--accent);font-weight:400;
}
.eop-lockdown-post .lead{
  font-size:18px;color:var(--text-soft);
  max-width:680px;line-height:1.6;
  margin-bottom:24px;
}
.eop-lockdown-post .stamps{
  display:flex;gap:10px;flex-wrap:wrap;
  font-family:'JetBrains Mono', monospace;font-size:11px;
}
.eop-lockdown-post .stamp{
  padding:5px 11px;border:1px solid var(--line);
  border-radius:4px;color:var(--text-soft);
  text-transform:uppercase;letter-spacing:1px;
  background:var(--bg-elev);
}
.eop-lockdown-post .stamp.crit{border-color:var(--danger);color:var(--danger)}
.eop-lockdown-post .stamp.ok{border-color:var(--ok);color:var(--ok)}</p>
<p>/* ─── Sections ────────────────────── */
.eop-lockdown-post section{
  margin-bottom:64px;scroll-margin-top:80px;
}
.eop-lockdown-post section h2{
  font-family:'Fraunces', Georgia, serif;
  font-size:30px;font-weight:600;
  letter-spacing:-0.01em;
  margin-bottom:22px;
  display:flex;align-items:baseline;gap:14px;
  color:var(--text);
}
.eop-lockdown-post section h2::before{
  content:counter(sec, decimal-leading-zero);
  counter-increment:sec;
  font-family:'JetBrains Mono', monospace;
  font-size:14px;color:var(--accent);font-weight:400;
}
.eop-lockdown-post section h3{
  font-size:20px;font-weight:600;
  margin:32px 0 12px;
  color:var(--text);
}
.eop-lockdown-post section h4{
  font-size:14px;font-weight:600;
  margin:22px 0 10px;color:var(--text);
  text-transform:uppercase;letter-spacing:0.5px;
  font-family:'JetBrains Mono', monospace;
}
.eop-lockdown-post section p{
  margin-bottom:14px;color:var(--text-soft);
}
.eop-lockdown-post section p strong{color:var(--text);font-weight:600}
.eop-lockdown-post section ul,
.eop-lockdown-post section ol{
  margin:10px 0 18px 22px;color:var(--text-soft);
}
.eop-lockdown-post section li{margin-bottom:7px}
.eop-lockdown-post section li strong{color:var(--text)}
.eop-lockdown-post section a{
  color:var(--info);text-decoration:underline;
  text-decoration-thickness:1px;
  text-underline-offset:2px;
}
.eop-lockdown-post section a:hover{color:var(--accent-deep)}</p>
<p>/* ─── Code blocks ─────────────────── */
.eop-lockdown-post pre{
  background:var(--code-bg);
  border:1px solid var(--line);
  border-radius:8px;
  padding:18px 22px;
  overflow-x:auto;
  margin:14px 0 22px;
  font-family:'JetBrains Mono', monospace;
  font-size:13px;line-height:1.65;
  position:relative;
}
.eop-lockdown-post pre[data-label]::before{
  content:attr(data-label);
  position:absolute;top:-1px;right:-1px;
  background:var(--bg-elev);
  color:var(--text-dim);
  padding:4px 12px;
  font-size:10px;
  text-transform:uppercase;
  letter-spacing:1.5px;
  border-radius:0 8px 0 8px;
  border-left:1px solid var(--line);
  border-bottom:1px solid var(--line);
}
.eop-lockdown-post code{
  font-family:'JetBrains Mono', monospace;
  background:var(--bg-soft);
  padding:2px 6px;
  border-radius:3px;
  font-size:0.88em;
  color:var(--accent);
  border:1px solid var(--line-soft);
}
.eop-lockdown-post pre code{
  background:none;padding:0;border:none;color:var(--text);
}
.eop-lockdown-post .ps-cmd{color:#0550ae}
.eop-lockdown-post .ps-param{color:#953800}
.eop-lockdown-post .ps-string{color:#0a3069}
.eop-lockdown-post .ps-comment{color:#6e7781;font-style:italic}
.eop-lockdown-post .ps-var{color:#6f42c1}</p>
<p>/* ─── Callouts ────────────────────── */
.eop-lockdown-post .callout{
  border:1px solid var(--line);
  border-left:3px solid var(--info);
  background:linear-gradient(to right, rgba(29,78,216,0.05), transparent 40%);
  padding:16px 20px;border-radius:6px;
  margin:22px 0;
}
.eop-lockdown-post .callout.warn{
  border-left-color:var(--warn);
  background:linear-gradient(to right, rgba(161,98,7,0.06), transparent 40%);
}
.eop-lockdown-post .callout.crit{
  border-left-color:var(--danger);
  background:linear-gradient(to right, rgba(185,28,28,0.06), transparent 40%);
}
.eop-lockdown-post .callout.ok{
  border-left-color:var(--ok);
  background:linear-gradient(to right, rgba(21,128,61,0.05), transparent 40%);
}
.eop-lockdown-post .callout .lbl{
  font-family:'JetBrains Mono', monospace;
  font-size:11px;text-transform:uppercase;
  letter-spacing:1.5px;font-weight:700;
  margin-bottom:7px;display:block;
  color:var(--info);
}
.eop-lockdown-post .callout.warn .lbl{color:var(--warn)}
.eop-lockdown-post .callout.crit .lbl{color:var(--danger)}
.eop-lockdown-post .callout.ok .lbl{color:var(--ok)}
.eop-lockdown-post .callout p{margin:0;color:var(--text)}
.eop-lockdown-post .callout p + p{margin-top:8px}</p>
<p>/* ─── Flow diagram ────────────────── */
.eop-lockdown-post .flow-diagram{
  background:var(--bg-soft);
  border:1px solid var(--line);
  border-radius:10px;
  padding:28px;
  margin:22px 0;
}
.eop-lockdown-post .flow-diagram h4{
  margin-top:0;margin-bottom:18px;color:var(--text-soft);
}
.eop-lockdown-post .flow-row{
  display:flex;align-items:center;gap:12px;flex-wrap:wrap;
  font-family:'JetBrains Mono', monospace;font-size:12px;
  margin-bottom:12px;
}
.eop-lockdown-post .flow-row:last-child{margin-bottom:0}
.eop-lockdown-post .flow-node{
  padding:10px 16px;border:1px solid var(--line);
  border-radius:6px;background:var(--bg-elev);
  min-width:120px;text-align:center;
  color:var(--text);
}
.eop-lockdown-post .flow-node.bad{
  border-color:var(--danger);color:var(--danger);
  background:rgba(185,28,28,0.06);
}
.eop-lockdown-post .flow-node.good{
  border-color:var(--ok);color:var(--ok);
  background:rgba(21,128,61,0.06);
}
.eop-lockdown-post .flow-node.gateway{
  border-color:var(--info);color:var(--info);
  background:rgba(29,78,216,0.06);
}
.eop-lockdown-post .flow-arrow{color:var(--text-dim);font-size:18px}
.eop-lockdown-post .flow-arrow.bad{color:var(--danger)}
.eop-lockdown-post .flow-arrow.good{color:var(--ok)}
.eop-lockdown-post .flow-label{
  font-size:10px;color:var(--text-dim);
  text-transform:uppercase;letter-spacing:1px;
  margin-top:-6px;margin-bottom:14px;padding-left:8px;
}</p>
<p>/* ─── Tables ──────────────────────── */
.eop-lockdown-post table{
  width:100%;border-collapse:collapse;
  margin:22px 0;font-size:14px;
  border:1px solid var(--line);border-radius:8px;
  overflow:hidden;
}
.eop-lockdown-post th{
  background:var(--bg-soft);
  text-align:left;padding:11px 16px;
  font-family:'JetBrains Mono', monospace;
  font-size:11px;text-transform:uppercase;
  letter-spacing:1px;color:var(--text-soft);
  font-weight:600;
  border-bottom:1px solid var(--line);
}
.eop-lockdown-post td{
  padding:13px 16px;
  border-bottom:1px solid var(--line-soft);
  color:var(--text-soft);vertical-align:top;
}
.eop-lockdown-post tr:last-child td{border-bottom:none}
.eop-lockdown-post td code{font-size:12px}</p>
<p>/* ─── Step list ───────────────────── */
.eop-lockdown-post .steps{
  counter-reset:step;list-style:none;margin-left:0;
}
.eop-lockdown-post .steps > li{
  counter-increment:step;
  padding-left:54px;position:relative;
  margin-bottom:24px;padding-bottom:6px;
  min-height:40px;
}
.eop-lockdown-post .steps > li::before{
  content:counter(step, decimal-leading-zero);
  position:absolute;left:0;top:-2px;
  font-family:'JetBrains Mono', monospace;
  font-size:14px;font-weight:700;
  color:var(--accent);
  width:40px;height:40px;
  display:flex;align-items:center;justify-content:center;
  border:1.5px solid var(--accent);border-radius:50%;
  background:rgba(194,65,12,0.05);
}</p>
<p>/* ─── Checklist ───────────────────── */
.eop-lockdown-post .checklist{
  list-style:none;margin-left:0;padding-left:0;
}
.eop-lockdown-post .checklist li{
  padding:13px 16px;border:1px solid var(--line-soft);
  border-radius:6px;margin-bottom:8px;
  display:flex;align-items:flex-start;gap:14px;
  background:var(--bg-elev);
}
.eop-lockdown-post .checklist li::before{
  content:"☐";font-family:'JetBrains Mono', monospace;
  font-size:18px;color:var(--accent);
  line-height:1.2;flex-shrink:0;
}
.eop-lockdown-post .checklist li strong{
  display:block;margin-bottom:3px;color:var(--text);
}
.eop-lockdown-post .checklist li span{
  color:var(--text-soft);font-size:14px;line-height:1.5;
}</p>
<p>/* ─── Footer ──────────────────────── */
.eop-lockdown-post .post-footer{
  margin-top:64px;padding-top:28px;
  border-top:1px solid var(--line);
  font-family:'JetBrains Mono', monospace;
  font-size:12px;color:var(--text-dim);
  display:flex;justify-content:space-between;
  flex-wrap:wrap;gap:14px;
}</p>
<p>/* ─── Responsive ──────────────────── */
@media (max-width:700px){
  .eop-lockdown-post{padding:32px 22px}
  .eop-lockdown-post h1.title{font-size:30px}
  .eop-lockdown-post section h2{font-size:24px}
  .eop-lockdown-post pre{font-size:11px;padding:14px 16px}
  .eop-lockdown-post .flow-row{font-size:11px}
}
</style>
<article class="eop-lockdown-post">
<div class="hero">
    <span class="eyebrow">Microsoft 365 · Email Security</span></p>
<p class="lead">
      A practical, step-by-step guide for tenants running a centralized mail flow with a third-party<br />
      Secure Email Gateway (SEG) — and discovering that mail and spoofing attempts still slip in<br />
      directly through Exchange Online Protection.
    </p>
<div class="stamps">
      <span class="stamp crit">Security-relevant</span><br />
      <span class="stamp">Exchange Online</span><br />
      <span class="stamp">EOP / Defender</span><br />
      <span class="stamp ok">Production-ready</span>
    </div>
</p></div>
<p>  <!-- ─── Section 1 ─────────────────────────── --></p>
<section>
<h2>The problem in a nutshell</h2>
<p>
      In a centralized mail flow setup, every inbound message is supposed to travel a single,<br />
      well-defined path: the public MX record points at a third-party Secure Email Gateway<br />
      (Mimecast, Proofpoint, Cisco IronPort, Barracuda, an on-premises Exchange edge — pick your<br />
      flavor), the gateway scans and filters the message, and only then is it handed off to<br />
      Exchange Online Protection through an authenticated connector.
    </p>
<p>
      In the real world, things are messier. Many organizations notice — sometimes only after<br />
      a successful phishing attempt — that mail is reaching mailboxes <strong>directly through<br />
      EOP</strong>, completely bypassing the gateway that was supposed to be the first line of<br />
      defense. Often these messages are spoofed, claiming to come from internal addresses such<br />
      as <code>ceo@yourcompany.com</code>.
    </p>
<h3>The desired state</h3>
<div class="flow-diagram">
<h4>Allowed mail flow</h4>
<div class="flow-row">
<div class="flow-node">Internet</div>
<p>        <span class="flow-arrow good">→</span></p>
<div class="flow-node gateway">SEG / Gateway</div>
<p>        <span class="flow-arrow good">→</span></p>
<div class="flow-node">EOP (via connector)</div>
<p>        <span class="flow-arrow good">→</span></p>
<div class="flow-node good">Mailbox ✓</div>
</p></div>
<h4 style="margin-top:24px">Mail flow to be blocked</h4>
<div class="flow-row">
<div class="flow-node">Attacker</div>
<p>        <span class="flow-arrow bad">⨯</span></p>
<div class="flow-node bad">tenant.mail.protection.outlook.com</div>
<p>        <span class="flow-arrow bad">⨯</span></p>
<div class="flow-node bad">EOP direct</div>
</p></div>
<p class="flow-label">Gateway bypass via direct SMTP connect to the EOP MX endpoint</p>
</p></div>
<p>What we want to achieve:</p>
<ul>
<li><strong>Block Direct Send</strong> — anonymous mail using your own domains, sent straight to EOP, must be rejected.</li>
<li><strong>Restrict the inbound connector</strong> — only the SEG’s IPs or TLS certificate may deliver mail.</li>
<li><strong>Stop spoofing</strong> — strict SPF, DKIM and DMARC, plus EOP anti-spoofing in enforcement mode.</li>
<li><strong>Stay auditable</strong> — message trace and Defender reports must show every bypass attempt.</li>
</ul>
</section>
<p>  <!-- ─── Section 2 ─────────────────────────── --></p>
<section>
<h2>Why does EOP accept mail directly in the first place?</h2>
<p>
      Every Microsoft 365 tenant has a publicly resolvable MX endpoint of the form<br />
      <code><tenant>.mail.protection.outlook.com</code>. Regardless of where your MX record<br />
      actually points, that endpoint is reachable from the internet and — by default —<br />
      <strong>accepts anonymous SMTP connections</strong> for any of your accepted domains.<br />
      Microsoft calls this mechanism <em>Direct Send</em>.
    </p>
<p>
      Direct Send is officially intended for printers, scanners, and legacy line-of-business<br />
      apps that need to drop mail into internal mailboxes without authenticating. Convenient —<br />
      but it’s also exactly the mechanism attackers exploit to bypass your gateway and impersonate<br />
      internal senders.
    </p>
<div class="callout warn">
      <span class="lbl">Important to understand</span></p>
<p>
        A centralized mail flow or an MX record pointing somewhere else does <strong>not</strong><br />
        protect you against Direct Send. The MX record is just a DNS hint. Attackers can connect<br />
        to the EOP endpoint directly at any time — unless you’ve explicitly hardened the tenant.
      </p>
</p></div>
<p>
      The fix is multi-layered: the tenant-wide <code>RejectDirectSend</code> flag, a tightly<br />
      restricted inbound connector, a transport rule as a safety net, and proper anti-spoofing<br />
      configuration. We’ll walk through each of them.
    </p>
</section>
<p>  <!-- ─── Section 3 ─────────────────────────── --></p>
<section>
<h2>Prerequisites</h2>
<h4>Permissions</h4>
<ul>
<li><strong>Organization Configuration</strong> (for <code>Set-OrganizationConfig</code>)</li>
<li><strong>Exchange Administrator</strong> or <strong>Global Administrator</strong> (connectors and rules)</li>
<li><strong>Security Administrator</strong> (Defender policies and anti-phishing)</li>
</ul>
<h4>Tooling</h4>
<pre data-label="PowerShell"><code><span class="ps-comment"># Install the Exchange Online module if you haven't already</span>
<span class="ps-cmd">Install-Module</span> <span class="ps-param">-Name</span> ExchangeOnlineManagement <span class="ps-param">-Scope</span> CurrentUser

<span class="ps-comment"># Connect</span>
<span class="ps-cmd">Connect-ExchangeOnline</span> <span class="ps-param">-UserPrincipalName</span> <span class="ps-string">admin@yourcompany.com</span></code></pre>
<h4>Information to gather upfront</h4>
<ul>
<li>The full list of <strong>public IP addresses or ranges</strong> used by your SEG, including DR/secondary regions.</li>
<li>Optionally, the <strong>TLS certificate subject / SAN</strong> the SEG presents when delivering to EOP — preferred over IP binding.</li>
<li>All accepted domains of the tenant: <code>Get-AcceptedDomain</code>.</li>
<li>Document existing inbound connectors: <code>Get-InboundConnector | Format-List</code>.</li>
<li>Current SPF, DKIM, and DMARC records for each sending domain.</li>
</ul>
<div class="callout">
      <span class="lbl">Recommendation</span></p>
<p>
        Before changing anything, take a JSON or XML snapshot of the current state via<br />
        <code>Get-OrganizationConfig</code>, <code>Get-InboundConnector</code>, and<br />
        <code>Get-TransportRule</code>. It makes rollback trivial if something breaks.
      </p>
</p></div>
</section>
<p>  <!-- ─── Section 4 ─────────────────────────── --></p>
<section>
<h2>Step 1 — Enable Reject Direct Send</h2>
<p>
      The simplest and most powerful single switch is the tenant-wide<br />
      <code>RejectDirectSend</code> flag. When it is enabled, EOP rejects <strong>any anonymous<br />
      message whose P1 Mail-From address matches one of your accepted domains</strong>, unless<br />
      it arrived authenticated through an inbound connector. The sender receives the NDR<br />
      <code>550 5.7.68 TenantInboundAttribution; Direct Send not allowed for this organization<br />
      from unauthorized sources</code>.
    </p>
<ol class="steps">
<li>
        <strong>Check the current state.</strong></p>
<pre data-label="PowerShell"><code><span class="ps-cmd">Get-OrganizationConfig</span> | <span class="ps-cmd">Select-Object</span> Identity, RejectDirectSend</code></pre>
<p>        On existing tenants the default is <code>False</code>. Microsoft has announced that new tenants will get <code>True</code> by default starting in 2026.
      </li>
<li>
        <strong>Enable Reject Direct Send.</strong></p>
<pre data-label="PowerShell"><code><span class="ps-cmd">Set-OrganizationConfig</span> <span class="ps-param">-RejectDirectSend</span> <span class="ps-var">$true</span></code></pre>
<p>        Propagation across all EOP servers takes up to 30 minutes.
      </li>
<li>
        <strong>Verify.</strong></p>
<pre data-label="PowerShell"><code><span class="ps-cmd">Get-OrganizationConfig</span> | <span class="ps-cmd">Format-List</span> RejectDirectSend
<span class="ps-comment"># Expected: True</span></code></pre>
</li>
</ol>
<div class="callout warn">
      <span class="lbl">Watch out — possible side effects</span></p>
<p>
        Before flipping the switch, identify any legitimate Direct Send sources in your environment:<br />
        multifunction printers, ERP systems, monitoring tools, marketing platforms — anything that<br />
        sends as one of your domains directly to EOP. Each of those needs a partner inbound connector<br />
        beforehand, otherwise their delivery breaks the moment the flag is enabled.
      </p>
<p>
        A useful starting point: review your domain’s SPF record. Every entry there is a candidate<br />
        for a dedicated connector.
      </p>
</p></div>
</section>
<p>  <!-- ─── Section 5 ─────────────────────────── --></p>
<section>
<h2>Step 2 — Restrict the inbound connector to SEG IPs or certificate</h2>
<p>
      <code>RejectDirectSend</code> only covers messages whose sender domain is one of your own<br />
      accepted domains. Spoofed mail from <strong>foreign</strong> domains delivered straight to<br />
      EOP would still be accepted. To close that gap, configure your <em>Partner</em> inbound<br />
      connector so that EOP only accepts inbound mail from the SEG’s IPs or matching TLS<br />
      certificate.
    </p>
<h3>Option A — Configuration in the Exchange Admin Center</h3>
<ol class="steps">
<li>
        Open EAC at <code>https://admin.exchange.microsoft.com</code> →<br />
        <em>Mail flow</em> → <em>Connectors</em> → <em>Add a connector</em>.
      </li>
<li>
        <strong>Define the connection:</strong></p>
<ul>
<li>Connection from: <em>Partner organization</em></li>
<li>Connection to: <em>Office 365</em></li>
</ul>
</li>
<li>
        <strong>Authenticate the partner:</strong> prefer<br />
        <em>“By verifying that the subject name on the certificate that the sending server uses to<br />
        authenticate with Office 365 matches this domain name”</em> and enter the certificate the<br />
        SEG actually presents. As a fallback — when no TLS certificate is available —<br />
        <em>“By verifying that the IP address of the sending server matches one of the following<br />
        IP addresses”</em> with <strong>all</strong> of the SEG’s outbound IPs.
      </li>
<li>
        <strong>Enforce delivery rules:</strong></p>
<ul>
<li><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <em>Reject email messages if they aren’t sent over TLS</em></li>
<li><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <em>Reject email messages if they aren’t sent from within this IP address range</em> (with the SEG IPs)</li>
</ul>
</li>
<li>Save and enable the connector.</li>
</ol>
<h3>Option B — PowerShell (idempotent and auditable)</h3>
<pre data-label="PowerShell"><code><span class="ps-comment"># Example: SEG identifies itself via certificate (recommended)</span>
<span class="ps-cmd">New-InboundConnector</span> <span class="ps-param">-Name</span> <span class="ps-string">"From Secure Email Gateway"</span> `
    <span class="ps-param">-ConnectorType</span> Partner `
    <span class="ps-param">-SenderDomains</span> <span class="ps-string">"*"</span> `
    <span class="ps-param">-RestrictDomainsToCertificate</span> <span class="ps-var">$true</span> `
    <span class="ps-param">-TlsSenderCertificateName</span> <span class="ps-string">"*.mail-gateway.example.com"</span> `
    <span class="ps-param">-RequireTls</span> <span class="ps-var">$true</span> `
    <span class="ps-param">-Enabled</span> <span class="ps-var">$true</span>

<span class="ps-comment"># Alternative: SEG identifies itself by IP range</span>
<span class="ps-cmd">New-InboundConnector</span> <span class="ps-param">-Name</span> <span class="ps-string">"From SEG (IP-bound)"</span> `
    <span class="ps-param">-ConnectorType</span> Partner `
    <span class="ps-param">-SenderDomains</span> <span class="ps-string">"*"</span> `
    <span class="ps-param">-RestrictDomainsToIPAddresses</span> <span class="ps-var">$true</span> `
    <span class="ps-param">-SenderIPAddresses</span> <span class="ps-string">"203.0.113.10","203.0.113.11","198.51.100.0/28"</span> `
    <span class="ps-param">-RequireTls</span> <span class="ps-var">$true</span> `
    <span class="ps-param">-Enabled</span> <span class="ps-var">$true</span></code></pre>
<div class="callout">
      <span class="lbl">What <code>RestrictDomainsTo*</code> actually does</span></p>
<p>
        With these flags set to <code>$true</code> EOP effectively tells the world:<br />
        <em>“Mail addressed to my domains is only accepted when it arrives via IP X or certificate Y.”</em><br />
        Any other source receives <code>550 5.7.51 TenantInboundAttribution; There is a partner<br />
        connector configured that matched the message’s recipient domain</code> and is rejected.
      </p>
</p></div>
<table>
<thead>
<tr>
<th>Method</th>
<th>Pros</th>
<th>Cons</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>TLS certificate</strong></td>
<td>Robust against IP changes, cryptographically verifiable</td>
<td>Requires a valid third-party certificate at the SEG</td>
</tr>
<tr>
<td><strong>IP range</strong></td>
<td>Simple to set up</td>
<td>Maintenance burden when IPs change, slightly weaker</td>
</tr>
</tbody>
</table>
</section>
<p>  <!-- ─── Section 6 ─────────────────────────── --></p>
<section>
<h2>Step 3 — Add a transport rule as a safety net</h2>
<p>
      Beyond the connector, it’s smart to add a transport rule as a second layer that rejects<br />
      <strong>any</strong> external mail not arriving from your allowed IP range. It protects you<br />
      against connector misconfiguration and produces a very clean audit trail in message trace.
    </p>
<h3>Configuration in the EAC</h3>
<ol class="steps">
<li>EAC → <em>Mail flow</em> → <em>Rules</em> → <em>Add a rule</em> → <em>Create a new rule</em>.</li>
<li><strong>Name:</strong> <code>BLOCK – Direct internet ingress without SEG</code></li>
<li>
        <strong>Apply this rule if…</strong></p>
<ul>
<li>The sender → is external/internal → <em>Outside the organization</em></li>
</ul>
</li>
<li>
        <strong>Do the following:</strong> <em>Block the message</em> →<br />
        <em>Reject the message and include an explanation</em> →<br />
        Reason: <em>“Mail to this organization must be delivered via the official Secure Email Gateway.<br />
        Direct delivery to EOP is not permitted.”</em>
      </li>
<li>
        <strong>Except if:</strong></p>
<ul>
<li>The sender → IP address is in any of these ranges → <strong>your SEG IPs</strong></li>
<li><em>or</em> The message headers → includes any of these words → header<br />
            <code>X-MS-Exchange-Organization-AuthAs</code> with value <code>Internal</code><br />
            (prevents breaking internal hybrid mail flow)</li>
</ul>
</li>
<li><strong>Rule mode:</strong> start in <em>Test with policy tips</em>, then switch to <em>Enforce</em> after validation.</li>
</ol>
<h3>PowerShell variant</h3>
<pre data-label="PowerShell"><code><span class="ps-cmd">New-TransportRule</span> <span class="ps-param">-Name</span> <span class="ps-string">"BLOCK - Direct EOP Ingress (Bypass SEG)"</span> `
    <span class="ps-param">-FromScope</span> NotInOrganization `
    <span class="ps-param">-ExceptIfSenderIPRanges</span> <span class="ps-string">"203.0.113.10","203.0.113.11","198.51.100.0/28"</span> `
    <span class="ps-param">-ExceptIfHeaderMatchesMessageHeader</span> <span class="ps-string">"X-MS-Exchange-Organization-AuthAs"</span> `
    <span class="ps-param">-ExceptIfHeaderMatchesPatterns</span> <span class="ps-string">"Internal"</span> `
    <span class="ps-param">-RejectMessageEnhancedStatusCode</span> <span class="ps-string">"5.7.1"</span> `
    <span class="ps-param">-RejectMessageReasonText</span> <span class="ps-string">"Mail not delivered via SEG."</span> `
    <span class="ps-param">-Mode</span> AuditAndNotify `
    <span class="ps-param">-Enabled</span> <span class="ps-var">$true</span></code></pre>
<div class="callout warn">
      <span class="lbl">Mind the rule order</span></p>
<p>
        Place this rule <strong>before</strong> any bypass or allow-list rules (lower priority value).<br />
        Otherwise an upstream rule may silently override your block. Starting in<br />
        <code>AuditAndNotify</code> mode gives you a safe pilot phase before flipping to<br />
        <code>Enforce</code>.
      </p>
</p></div>
</section>
<p>  <!-- ─── Section 7 ─────────────────────────── --></p>
<section>
<h2>Step 4 — Anti-spoofing and DMARC</h2>
<p>
      The previous steps lock down the transport path. Spoofing attempts that travel correctly<br />
      through the SEG (because an attacker hijacked some other domain or abused an open relay)<br />
      still need to be caught by authentication checks.
    </p>
<h3>4.1 SPF, DKIM and DMARC for your domains</h3>
<ul>
<li><strong>SPF:</strong> hard fail (<code>-all</code>), only your SEG egress IPs and legitimate cloud senders (e.g. <code>spf.protection.outlook.com</code>).</li>
<li><strong>DKIM:</strong> enable signing for every sending domain in the Defender portal under<br />
        <em>Email & collaboration</em> → <em>Policies</em> → <em>Email authentication settings</em> → <em>DKIM</em>.</li>
<li><strong>DMARC:</strong> at minimum <code>p=quarantine</code>, target <code>p=reject</code> with<br />
        <code>rua=mailto:dmarc-reports@yourcompany.com</code>. Use a DMARC reporting service<br />
        (dmarcian, Valimail, Postmark, etc.) to make the RUA/RUF data actionable.</li>
</ul>
<pre data-label="DNS (example)"><code><span class="ps-comment"># SPF record</span>
yourcompany.com.   IN TXT "v=spf1 ip4:203.0.113.10 ip4:203.0.113.11 include:spf.protection.outlook.com -all"

<span class="ps-comment"># DMARC record</span>
_dmarc.yourcompany.com.  IN TXT "v=DMARC1; p=reject; rua=mailto:dmarc@yourcompany.com; ruf=mailto:dmarc@yourcompany.com; fo=1; adkim=s; aspf=s"</code></pre>
<h3>4.2 Anti-phishing policy (Defender for Office 365)</h3>
<p>
      In the Defender portal under <em>Email & collaboration</em> → <em>Policies & rules</em><br />
      → <em>Threat policies</em> → <em>Anti-phishing</em>, harden the default policy or create a<br />
      dedicated one for high-value recipients:
    </p>
<ul>
<li><strong>Spoof intelligence:</strong> Enabled</li>
<li><strong>Honor DMARC policy:</strong> Enabled (so messages with <code>p=reject</code> are actually rejected)</li>
<li><strong>Action for unauthenticated senders:</strong> <em>Quarantine</em></li>
<li><strong>Impersonation protection:</strong> explicitly cover sensitive mailboxes (CEO, finance, HR)</li>
<li><strong>Mailbox intelligence:</strong> Enabled</li>
</ul>
<h3>4.3 Anti-spam policy</h3>
<ul>
<li><strong>Bulk Complaint Level (BCL) threshold:</strong> 6 or lower</li>
<li><strong>Spam action:</strong> <em>Quarantine</em></li>
<li><strong>High-confidence phish action:</strong> <em>Quarantine</em></li>
<li>Avoid allow lists — they’re a frequent root cause of spoofing slip-throughs.</li>
</ul>
</section>
<p>  <!-- ─── Section 8 ─────────────────────────── --></p>
<section>
<h2>Step 5 — Enhanced Filtering for Connectors</h2>
<p>
      Because the SEG overwrites the original sender IP, EOP would normally evaluate SPF against<br />
      the SEG’s IP rather than the actual sender — meaning every phishing attempt passes SPF<br />
      effortlessly. <strong>Enhanced Filtering for Connectors</strong> (also known as skip listing)<br />
      fixes this by telling EOP to look further back in the Received header chain to find the real<br />
      sender IP.
    </p>
<ol class="steps">
<li>Open the Defender portal at <code>https://security.microsoft.com/skiplisting</code><br />
        (or <em>Email & collaboration</em> → <em>Policies & rules</em> → <em>Enhanced filtering</em>).</li>
<li>Select the inbound connector you created in Step 2.</li>
<li>Choose <strong>Skip these IP addresses that are associated with the connector</strong><br />
        and add <strong>all</strong> public IPs of the SEG (including any intermediate hops).</li>
<li><strong>Apply to entire organization</strong> after a small pilot phase with a few mailboxes.</li>
</ol>
<div class="callout crit">
      <span class="lbl">Don’t do this</span></p>
<p>
        Do not add on-premises hybrid server IPs to the skip list when your MX points to EOP.<br />
        Microsoft does not support this in a centralized mail flow scenario; it can lead to<br />
        false positives in spam scoring.
      </p>
</p></div>
</section>
<p>  <!-- ─── Section 9 ─────────────────────────── --></p>
<section>
<h2>Verification & testing</h2>
<h3>Test 1 — Direct Send from an external host</h3>
<p>From an external system, attempt a direct SMTP delivery to the EOP endpoint:</p>
<pre data-label="PowerShell (external)"><code><span class="ps-cmd">Send-MailMessage</span> `
    <span class="ps-param">-From</span> <span class="ps-string">"ceo@yourcompany.com"</span> `
    <span class="ps-param">-To</span> <span class="ps-string">"recipient@yourcompany.com"</span> `
    <span class="ps-param">-Subject</span> <span class="ps-string">"Direct Send Test"</span> `
    <span class="ps-param">-Body</span> <span class="ps-string">"Testing the Reject Direct Send flag"</span> `
    <span class="ps-param">-SmtpServer</span> <span class="ps-string">"yourcompany-com.mail.protection.outlook.com"</span> `
    <span class="ps-param">-Port</span> 25</code></pre>
<p><strong>Expected result:</strong></p>
<pre data-label="SMTP response"><code>550 5.7.68 TenantInboundAttribution;
Direct Send not allowed for this organization from unauthorized sources</code></pre>
<h3>Test 2 — Spoof from a foreign domain bypassing the SEG</h3>
<p>External test using a foreign sender domain (e.g. <code>fake@gmail.com</code>) directly to the EOP endpoint:</p>
<p><strong>Expected result:</strong></p>
<pre data-label="SMTP response"><code>550 5.7.51 TenantInboundAttribution;
There is a partner connector configured that matched the message's recipient domain</code></pre>
<h3>Test 3 — Legitimate mail through the SEG</h3>
<p>
      Send an external test message from Gmail or Outlook.com to an internal recipient. In message<br />
      trace, verify that the mail arrived from the SEG IP, was accepted by the inbound connector,<br />
      and delivered correctly.
    </p>
<pre data-label="PowerShell"><code><span class="ps-cmd">Get-MessageTrace</span> <span class="ps-param">-RecipientAddress</span> <span class="ps-string">"recipient@yourcompany.com"</span> <span class="ps-param">-StartDate</span> (<span class="ps-cmd">Get-Date</span>).AddHours(-1) <span class="ps-param">-EndDate</span> (<span class="ps-cmd">Get-Date</span>) |
    <span class="ps-cmd">Select-Object</span> Received, SenderAddress, FromIP, Status, Subject</code></pre>
<h3>Test 4 — Header analysis</h3>
<p>
      Inspect a delivered message via <em>File → Properties</em> in Outlook or paste the headers<br />
      into the <a href="https://mha.azurewebsites.net" target="_blank" rel="noopener">Message Header Analyzer</a>.<br />
      The following headers confirm a healthy configuration:
    </p>
<ul>
<li><code>Authentication-Results-Original</code> shows SPF pass against the <strong>real</strong> sender IP — not the SEG IP.</li>
<li>The <code>Received</code> chain shows the SEG as the last hop before EOP.</li>
<li><code>X-MS-Exchange-SkipListedInternetSender</code> is set, indicating Enhanced Filtering is working.</li>
</ul>
</section>
<p>  <!-- ─── Section 10 ─────────────────────────── --></p>
<section>
<h2>Monitoring & reporting</h2>
<h3>Daily / weekly</h3>
<ul>
<li><strong>Message trace:</strong> filter on status <em>Failed</em> with reason <code>5.7.68</code> or <code>5.7.51</code> — every hit is a blocked bypass attempt.</li>
<li><strong>Defender → Reports → Mailflow:</strong> <em>Threat protection status</em> and <em>Spoof detections</em>.</li>
<li><strong>Transport rule reports:</strong> <em>Mail flow</em> → <em>Reports</em> → <em>Mail flow rule matches</em> — your safety-net rule from Step 3.</li>
<li><strong>DMARC aggregate reports:</strong> review RUA reports — every unknown source is a signal worth investigating.</li>
</ul>
<h3>Useful KQL queries (Defender for Office 365 hunting)</h3>
<pre data-label="KQL"><code><span class="ps-comment">// Direct Send attempts in the last 7 days</span>
EmailEvents
| where Timestamp > ago(7d)
| where DeliveryAction == "Blocked"
| where DeliveryLocation == "Failed"
| where AdditionalFields has "5.7.68"
| project Timestamp, SenderFromAddress, RecipientEmailAddress, SenderIPv4, Subject

<span class="ps-comment">// Mail that did NOT arrive from your SEG IPs</span>
EmailEvents
| where Timestamp > ago(1d)
| where SenderIPv4 !in ("203.0.113.10","203.0.113.11")
| where EmailDirection == "Inbound"
| summarize count() by SenderIPv4, SenderFromDomain</code></pre>
<h3>Alerting</h3>
<ul>
<li>Defender alert policy on <em>Mail flow rule match</em> for the safety-net rule.</li>
<li>SIEM forwarding (Sentinel, Splunk, etc.) of the EmailEvents table.</li>
<li>A weekly review report sent to the security team.</li>
</ul>
</section>
<p>  <!-- ─── Section 11 ─────────────────────────── --></p>
<section>
<h2>Rollback plan</h2>
<p>
      If business-critical mail flows break after activation, the commands below let you revert<br />
      quickly. The rollback order is the reverse of the activation order.
    </p>
<pre data-label="PowerShell — rollback"><code><span class="ps-comment"># 1. Disable the transport rule</span>
<span class="ps-cmd">Disable-TransportRule</span> <span class="ps-param">-Identity</span> <span class="ps-string">"BLOCK - Direct EOP Ingress (Bypass SEG)"</span>

<span class="ps-comment"># 2. Loosen the inbound connector (drop IP binding)</span>
<span class="ps-cmd">Set-InboundConnector</span> <span class="ps-param">-Identity</span> <span class="ps-string">"From Secure Email Gateway"</span> `
    <span class="ps-param">-RestrictDomainsToIPAddresses</span> <span class="ps-var">$false</span>

<span class="ps-comment"># 3. Disable Reject Direct Send</span>
<span class="ps-cmd">Set-OrganizationConfig</span> <span class="ps-param">-RejectDirectSend</span> <span class="ps-var">$false</span>

<span class="ps-comment"># Confirm</span>
<span class="ps-cmd">Get-OrganizationConfig</span> | <span class="ps-cmd">Format-List</span> RejectDirectSend</code></pre>
<div class="callout ok">
      <span class="lbl">Recommended rollout phases</span></p>
<p>
        1) Enable the transport rule in <em>audit mode</em> (one week of observation) →<br />
        2) Harden the inbound connector (one to two days of observation) →<br />
        3) Enable <code>RejectDirectSend</code> →<br />
        4) Switch the transport rule to <em>Enforce</em>. Each step is small and quickly reversible.
      </p>
</p></div>
</section>
<p>  <!-- ─── Section 12 ─────────────────────────── --></p>
<section>
<h2>Final checklist</h2>
<ul class="checklist">
<li>
<div><strong>Direct Send sources inventoried</strong><span>SPF analyzed, every printer / app / cloud service sending as your domain documented</span></div>
</li>
<li>
<div><strong>Configuration backup taken</strong><span>Get-OrganizationConfig, Get-InboundConnector, Get-TransportRule exported</span></div>
</li>
<li>
<div><strong>Inbound connector with IP/cert binding active</strong><span>RestrictDomainsToIPAddresses or RestrictDomainsToCertificate set to $true</span></div>
</li>
<li>
<div><strong>Reject Direct Send enabled</strong><span>Set-OrganizationConfig -RejectDirectSend $true applied and propagated</span></div>
</li>
<li>
<div><strong>Transport rule (safety net) active</strong><span>Reject rule for non-SEG IPs in enforce mode, correctly prioritized</span></div>
</li>
<li>
<div><strong>SPF / DKIM / DMARC enforced</strong><span>SPF -all, DKIM signing for all sending domains, DMARC at least p=quarantine</span></div>
</li>
<li>
<div><strong>Anti-phishing policy hardened</strong><span>Spoof intelligence + Honor DMARC + quarantine for unauthenticated senders</span></div>
</li>
<li>
<div><strong>Enhanced filtering configured</strong><span>Skip listing of SEG IPs at the inbound connector enabled</span></div>
</li>
<li>
<div><strong>Tests performed</strong><span>Direct Send blocked (550 5.7.68), legitimate mail via SEG delivered, headers correct</span></div>
</li>
<li>
<div><strong>Monitoring in place</strong><span>Message trace reviews, KQL hunting, DMARC reporting, alerting</span></div>
</li>
</ul>
</section>
<p>  <!-- ─── Section 13 ─────────────────────────── --></p>
<section>
<h2>References & further reading</h2>
<ul>
<li>Microsoft Learn — <a href="https://learn.microsoft.com/en-us/exchange/transport-routing" target="_blank" rel="noopener">Email routing in Exchange hybrid deployments</a></li>
<li>Microsoft Learn — <a href="https://learn.microsoft.com/en-us/exchange/mail-flow-best-practices/use-connectors-to-configure-mail-flow/enhanced-filtering-for-connectors" target="_blank" rel="noopener">Enhanced Filtering for Connectors</a></li>
<li>Microsoft Learn — <a href="https://learn.microsoft.com/en-us/defender-office-365/connection-filter-policies-configure" target="_blank" rel="noopener">Configure the default connection filter policy</a></li>
<li>Microsoft Tech Community — <a href="https://techcommunity.microsoft.com/blog/exchange/introducing-more-control-over-direct-send-in-exchange-online/4408790" target="_blank" rel="noopener">Introducing more control over Direct Send</a></li>
<li>Microsoft Learn — <a href="https://learn.microsoft.com/en-us/exchange/security-and-compliance/mail-flow-rules/mail-flow-rules" target="_blank" rel="noopener">Mail flow rules in Exchange Online</a></li>
<li>Defender portal — <code>https://security.microsoft.com/skiplisting</code></li>
<li>Exchange Admin Center — <code>https://admin.exchange.microsoft.com</code></li>
</ul>
</section>
<div class="post-footer">
<div>EOP Lockdown Guide · Centralized Mail Flow Hardening</div>
<div>Rev. 1.0 · 2026</div>
</p></div>
</article>
]]></content:encoded>
					
					<wfw:commentRss>https://www.msb365.blog/?feed=rss2&#038;p=6164</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Mass Email with Exchange Online: Pros, Cons, Limits &#038; Better Alternatives</title>
		<link>https://www.msb365.blog/?p=6153</link>
					<comments>https://www.msb365.blog/?p=6153#respond</comments>
		
		<dc:creator><![CDATA[drago]]></dc:creator>
		<pubDate>Tue, 17 Mar 2026 09:36:22 +0000</pubDate>
				<category><![CDATA[Microsoft 365]]></category>
		<category><![CDATA[MS Exchange]]></category>
		<guid isPermaLink="false">https://www.msb365.blog/?p=6153</guid>

					<description><![CDATA[Email Strategy Exchange Online excels at business email but was never built to be a bulk marketing engine. This article provides a complete technical overview of limits, risks, best‑practice architecture and alternatives for high‑volume or marketing email delivery. Per‑mailbox limit (24h) ~10,000 Send rate ~30/min Tenant external cap License‑based TERRL When Exchange Online can work [&#8230;]]]></description>
										<content:encoded><![CDATA[<style>
  :root{
    --bg:#ffffff;
    --card:#f7f7f7;
    --fg:#1f2937;
    --muted:#6b7280;
    --accent:#2563eb;
    --ok:#059669;
    --warn:#d97706;
    --bad:#dc2626;
  }
  html,body{margin:0;padding:0;background:var(--bg);color:var(--fg);font:16px/1.6 system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,'Helvetica Neue',Arial}
  .wrap{max-width:980px;margin:0 auto;padding:48px 20px}
  .card{background:#ffffff;border:1px solid #e5e7eb;box-shadow:0 4px 16px rgba(0,0,0,.06);border-radius:16px;padding:32px}
  h1{font-size:36px;line-height:1.2;margin:0 0 8px}
  h2{font-size:24px;margin:28px 0 8px}
  h3{font-size:19px;margin:22px 0 6px;color:var(--accent)}
  p{margin:10px 0}
  .lead{font-size:18px;color:var(--muted)}
  .pill{display:inline-block;padding:4px 10px;border-radius:999px;background:rgba(37,99,235,.12);color:var(--accent);font-weight:600;margin:4px 0}
  .grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:16px;margin:14px 0}
  .kpi{background:#f3f4f6;border:1px solid #e5e7eb;border-radius:12px;padding:16px}
  .kpi h4{margin:0 0 6px;font-size:16px;color:var(--muted)}
  .kpi .v{font-size:22px;font-weight:700}
  ul{margin:8px 0 8px 18px}
  li{margin:6px 0}
  .pro{color:var(--ok)}
  .con{color:var(--bad)}
  .note{border-left:3px solid var(--accent);padding:10px 14px;background:rgba(37,99,235,.08);border-radius:6px}
  table{width:100%;border-collapse:collapse;margin:12px 0}
  th,td{border:1px solid #e5e7eb;padding:10px 12px}
  th{background:#f9fafb;text-align:left}
  code{background:#f3f4f6;padding:2px 6px;border-radius:6px}
  .footer{color:var(--muted);font-size:14px;margin-top:24px}
</style>
<div class="wrap">
<div class="card">
    <span class="pill">Email Strategy</span></p>
<p class="lead">
      Exchange Online excels at business email but was never built to be a bulk marketing engine.<br />
      This article provides a complete technical overview of limits, risks, best‑practice architecture and alternatives for high‑volume or marketing email delivery.
    </p>
<div class="grid">
<div class="kpi">
<h4>Per‑mailbox limit (24h)</h4>
<div class="v">~10,000</div>
</div>
<div class="kpi">
<h4>Send rate</h4>
<div class="v">~30/min</div>
</div>
<div class="kpi">
<h4>Tenant external cap</h4>
<div class="v">License‑based TERRL</div>
</div></div>
<h2>When Exchange Online can work</h2>
<p>Exchange Online works fine when message volume stays low and recipients are primarily internal.</p>
<ul>
<li class="pro">Small internal communications.</li>
<li class="pro">Department updates, announcements, emergencies.</li>
<li class="pro">Internal distribution lists count as 1 recipient.</li>
<li class="pro">No additional systems or APIs required.</li>
</ul>
<h2>Technical and deliverability limitations</h2>
<p>Exchange Online includes strict policies to protect the service from abuse, spam and compromised accounts.</p>
<ul>
<li class="con">Not designed for marketing or bulk sending.</li>
<li class="con">High risk of throttling (per‑minute and per‑day limits).</li>
<li class="con">Risk of IP warm‑up issues and reputation drops.</li>
<li class="con">No proper bounce handling or suppression lists.</li>
<li class="con">Limited analytics (opens, complaints, deliverability).</li>
<li class="con">CAN‑SPAM / GDPR compliance must be handled manually.</li>
</ul>
<h2>Key technical limits</h2>
<h3>Mailbox-level limits</h3>
<ul>
<li>~10,000 recipients per 24h per mailbox.</li>
<li>~30 messages per minute.</li>
<li>Dynamic throttling when patterns look like bulk sending.</li>
<li>Automated lockout if Exchange detects spam‑like patterns.</li>
</ul>
<h3>Tenant-wide TERRL (Tenant External Recipient Rate Limit)</h3>
<p>TERRL depends on your M365 license count. Higher license volume → more outbound capacity.</p>
<table>
<tr>
<th>Licenses</th>
<th>Recipients / 24h</th>
</tr>
<tr>
<td>1</td>
<td>10,000</td>
</tr>
<tr>
<td>25</td>
<td>≈14,000+</td>
</tr>
<tr>
<td>100</td>
<td>≈28,000+</td>
</tr>
<tr>
<td>1,000</td>
<td>≈72,000+</td>
</tr>
</table>
<div class="note">
      TERRL is not officially published in detail. Microsoft adjusts thresholds dynamically to protect global capacity.<br />
      As a rule: **Exchange Online is not a bulk sender and scales poorly for newsletters**.
    </div>
<h2>Deliverability challenges</h2>
<ul>
<li>Shared Microsoft IP pools → reputation varies.</li>
<li>No ability to warm up IPs for new volumes.</li>
<li>No feedback loops with major ISPs (Outlook.com, Gmail, Yahoo).</li>
<li>Risk of domain reputation damage if recipients mark mails as spam.</li>
<li>Lack of automated bounce categorization (hard/soft/subscription).</li>
</ul>
<h2>Domain strategy: Use a dedicated subdomain</h2>
<p>Separating marketing email protects your primary business domain.</p>
<ul>
<li>Use e.g. <code>news.yourdomain.tld</code>, <code>mail.yourdomain.tld</code> or <code>updates.yourdomain.tld</code>.</li>
<li>Independent SPF, DKIM, DMARC policies.</li>
<li>Protects your main domain from reputation damage.</li>
<li>Allows independent DNS routing (e.g., towards ACS or Mailchimp).</li>
</ul>
<h3>Recommended DNS setup</h3>
<ul>
<li>SPF: include only required platforms.</li>
<li>DKIM: sign from dedicated selector.</li>
<li>DMARC: use <code>p=none</code> for warm‑up → later <code>quarantine</code> → <code>reject</code>.</li>
<li>Optional: BIMI increases trust at Gmail/Yahoo.</li>
</ul>
<h2>Better platforms for newsletters</h2>
<p>For real newsletters or any type of marketing automation:</p>
<ul>
<li>Professional templates & responsive layouts.</li>
<li>List management (subscriptions, bounce lists, suppression lists).</li>
<li>A/B testing, analytics, link tracking.</li>
<li>Compliance (opt‑in, double opt‑in, unsubscribe pages).</li>
<li>High deliverability via dedicated warm IP pools.</li>
</ul>
<h3>Examples</h3>
<ul>
<li>Mailchimp</li>
<li>Brevo (Sendinblue)</li>
<li>HubSpot</li>
<li>Klaviyo</li>
<li>CleverReach</li>
</ul>
<h2>Azure Communication Services (ACS)</h2>
<h3>For automated or transactional email</h3>
<p>ACS is excellent for application‑driven email delivery:</p>
<ul>
<li>API-first, scalable email service.</li>
<li>Supports templating & dynamic content.</li>
<li>Custom domain support with DKIM/DMARC.</li>
<li>High throughput and queue-based delivery.</li>
<li>Ideal for apps: invoices, password resets, confirmations.</li>
</ul>
<h3>When ACS is better than Exchange Online</h3>
<ul>
<li>You send >5,000 external transactional emails/day.</li>
<li>You need automated retries, bounce classification, webhooks.</li>
<li>You require custom integration via Node.js, .NET, Python.</li>
<li>You want to avoid throttling and protect your business domain.</li>
</ul>
<h2>Best practices and recommendations</h2>
<h3>If you must use Exchange Online</h3>
<ul>
<li>Send slowly (intervals between batches).</li>
<li>Use dynamic distribution lists to reduce message count.</li>
<li>Do not send marketing mail from shared mailboxes.</li>
<li>Limit daily volume to 2,000–3,000 recipients to avoid throttling.</li>
<li>Implement SPF, DKIM, DMARC correctly.</li>
<li>Monitor message trace for throttling patterns.</li>
</ul>
<h3>If you want zero risk</h3>
<ul>
<li>Use a marketing platform for newsletters.</li>
<li>Use ACS for system-generated mail.</li>
<li>Separate domains and DNS policies per use case.</li>
</ul>
<h2>Conclusion</h2>
<p>
      Exchange Online is a world-class business email platform but fundamentally not designed for<br />
      marketing, bulk or high-volume transactional email.<br />
      For newsletters use a dedicated marketing platform;<br />
      for scalable transactional email use ACS.<br />
      This protects your domain reputation, increases deliverability and ensures full compliance.
    </p>
<div class="footer">Last updated: 2026</div>
</p></div>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://www.msb365.blog/?feed=rss2&#038;p=6153</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Cleaning Meetings in M365</title>
		<link>https://www.msb365.blog/?p=6149</link>
					<comments>https://www.msb365.blog/?p=6149#respond</comments>
		
		<dc:creator><![CDATA[drago]]></dc:creator>
		<pubDate>Mon, 09 Mar 2026 10:25:09 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">https://www.msb365.blog/?p=6149</guid>

					<description><![CDATA[This documentation describes how to properly cancel and remove meetings and recurring meetings organized by a departed employee from the calendars of all attendees and resource calendars (e.g., conference rooms) in Microsoft 365. Important Prerequisite: The departed employee’s mailbox must not be permanently deleted yet. Execute these steps as part of the offboarding process, before [&#8230;]]]></description>
										<content:encoded><![CDATA[<style>
    .it-doc-container {
        font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        line-height: 1.6;
        color: #333;
        max-width: 900px;
        margin: 0 auto;
        padding: 30px;
        background-color: #ffffff;
        border-radius: 8px;
        box-shadow: 0 4px 6px rgba(0,0,0,0.1);
    }
    .it-doc-container h1, .it-doc-container h2, .it-doc-container h3 {
        color: #005a9e;
    }
    .it-doc-container h1 {
        border-bottom: 2px solid #005a9e;
        padding-bottom: 10px;
        font-size: 1.8em;
    }
    .it-doc-container code {
        background-color: #f0f0f0;
        padding: 3px 6px;
        border-radius: 4px;
        font-family: 'Consolas', 'Courier New', monospace;
        color: #c7254e;
        font-size: 0.9em;
    }
    .it-doc-container pre {
        background-color: #1e1e1e;
        color: #d4d4d4;
        padding: 15px;
        border-radius: 6px;
        overflow-x: auto;
        font-family: 'Consolas', 'Courier New', monospace;
    }
    .it-doc-container pre code {
        background-color: transparent;
        color: inherit;
        padding: 0;
    }
    .it-doc-container .note {
        background-color: #e7f3fe;
        border-left: 6px solid #2b88d8;
        padding: 15px 20px;
        margin: 20px 0;
        border-radius: 4px;
    }
    .it-doc-container .warning {
        background-color: #fff4ce;
        border-left: 6px solid #fbbc05;
        padding: 15px 20px;
        margin: 20px 0;
        border-radius: 4px;
    }
    .it-doc-container .step {
        margin-bottom: 30px;
    }
    .it-doc-container .step-title {
        font-weight: bold;
        font-size: 1.1em;
        margin-bottom: 10px;
        display: block;
    }
</style>
<div class="it-doc-container">
<p>This documentation describes how to properly cancel and remove meetings and recurring meetings organized by a departed employee from the calendars of all attendees and resource calendars (e.g., conference rooms) in Microsoft 365.</p>
<div class="warning">
        <strong>Important Prerequisite:</strong> The departed employee’s mailbox must <strong>not be permanently deleted</strong> yet. Execute these steps as part of the offboarding process, <em>before</em> the account is completely removed from Microsoft 365.
    </div>
<hr>
<h2>Method 1: The Best Practice Approach (PowerShell)</h2>
<p>This is the official and most efficient method. It automatically sends cancellations to all attendees and frees up previously booked rooms.</p>
<div class="step">
        <span class="step-title">Step 1: Check Prerequisites & Install Module</span></p>
<p>Launch PowerShell as an Administrator. If you haven’t already, you need to install the Exchange Online module:</p>
<pre><code>Install-Module -Name ExchangeOnlineManagement -Force</code></pre>
</p></div>
<div class="step">
        <span class="step-title">Step 2: Connect to Exchange Online</span></p>
<p>Log in with your Administrator account (Global Admin or Exchange Admin):</p>
<pre><code>Connect-ExchangeOnline -UserPrincipalName [email protected]</code></pre>
</p></div>
<div class="step">
        <span class="step-title">Step 3: Delete Meetings (Remove-CalendarEvents)</span></p>
<p>Use the <code>Remove-CalendarEvents</code> cmdlet to cancel the meetings. Here are two typical use cases:</p>
<h3>Use Case A: Standard Cleanup (1 Year)</h3>
<p>Employee John Doe is leaving the company. All of his future meetings for the upcoming year should be canceled.</p>
<pre><code>Remove-CalendarEvents -Identity "[email protected]" -CancelOrganizedMeetings -QueryWindowInDays 365</code></pre>
<h3>Use Case B: Preview Affected Meetings (WhatIf)</h3>
<p>If you are unsure and want to see which meetings would be deleted without actually executing the command, use the <code>-WhatIf</code> switch:</p>
<pre><code>Remove-CalendarEvents -Identity "[email protected]" -CancelOrganizedMeetings -QueryWindowInDays 120 -WhatIf</code></pre>
</p></div>
<div class="step">
        <span class="step-title">Step 4: Disconnect Session</span></p>
<p>For security reasons, always disconnect your session after successfully completing your tasks:</p>
<pre><code>Disconnect-ExchangeOnline -Confirm:$false</code></pre>
</p></div>
<hr>
<h2>Method 2: The Manual Workaround (Web Interface / GUI)</h2>
<p>Use this method only if you lack PowerShell permissions or if you need to manually manage a specific, single recurring meeting.</p>
<div class="step">
        <span class="step-title">Step 1: Convert to a Shared Mailbox</span></p>
<ul>
<li>Open the <strong>Microsoft 365 admin center</strong>.</li>
<li>Go to <strong>Users</strong> > <strong>Active users</strong>.</li>
<li>Click on the departed employee’s name.</li>
<li>Select the <strong>Mail</strong> tab and click on <strong>Convert to shared mailbox</strong>.</li>
</ul></div>
<div class="step">
        <span class="step-title">Step 2: Grant Full Access Permissions</span></p>
<ul>
<li>Scroll down in the user’s Mail settings to <strong>Mailbox permissions</strong>.</li>
<li>Click on <strong>Manage mailbox permissions</strong>.</li>
<li>Add your own Admin account under <strong>Read and manage (Full Access)</strong>.</li>
</ul>
<div class="note">
            <strong>Note:</strong> It can take up to 60 minutes for the permissions to fully synchronize across the cloud.
        </div>
</p></div>
<div class="step">
        <span class="step-title">Step 3: Open Mailbox and Cancel the Series</span></p>
<ul>
<li>Open <strong>Outlook on the web (OWA)</strong> with your Admin account.</li>
<li>Click on your profile picture in the top right corner and select <strong>Open another mailbox…</strong></li>
<li>Enter the email address of the departed employee and open it.</li>
<li>Switch to the <strong>Calendar</strong> view.</li>
<li>Locate the recurring meeting in question.</li>
<li>Right-click it and select <strong>Cancel</strong> -> <strong>Cancel series</strong>.</li>
<li>Send the cancellation. The meeting will now be removed from all attendees’ calendars.</li>
</ul></div>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://www.msb365.blog/?feed=rss2&#038;p=6149</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>How to Configure a PIN-Protected PSTN Call Flow in Microsoft Teams (Calling Plans)</title>
		<link>https://www.msb365.blog/?p=6144</link>
					<comments>https://www.msb365.blog/?p=6144#respond</comments>
		
		<dc:creator><![CDATA[drago]]></dc:creator>
		<pubDate>Fri, 27 Feb 2026 07:01:57 +0000</pubDate>
				<category><![CDATA[Microsoft 365]]></category>
		<category><![CDATA[MS Teams]]></category>
		<guid isPermaLink="false">https://www.msb365.blog/?p=6144</guid>

					<description><![CDATA[Securing a specific phone number so that only authorized callers can reach the destination is a common request in modern telecommunications. But how do you achieve this in Microsoft Teams Phone when you are using Microsoft Calling Plans and don’t have a Session Border Controller (SBC) to handle complex pre-routing logic? In this guide, we [&#8230;]]]></description>
										<content:encoded><![CDATA[<style>
/* WordPress Compatible CSS for Teams Blog Post */
.teams-blog-post {
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
    line-height: 1.6;
    color: #333;
    max-width: 900px;
    margin: 0 auto;
    padding: 20px;
}
.teams-blog-post h1 {
    color: #464EB8; /* Microsoft Teams Purple */
    font-size: 2.5em;
    border-bottom: 2px solid #E1DFDD;
    padding-bottom: 10px;
    margin-bottom: 20px;
}
.teams-blog-post h2 {
    color: #333;
    font-size: 1.8em;
    margin-top: 40px;
    border-left: 4px solid #464EB8;
    padding-left: 10px;
}
.teams-blog-post h3 {
    color: #555;
    font-size: 1.4em;
    margin-top: 30px;
}
.teams-blog-post p {
    margin-bottom: 20px;
}
.use-case-box {
    background-color: #F3F2F1;
    border: 1px solid #D2D0CE;
    border-radius: 6px;
    padding: 20px;
    margin-bottom: 30px;
}
.use-case-box h3 {
    margin-top: 0;
    color: #464EB8;
}
.pro-con-table {
    width: 100%;
    border-collapse: collapse;
    margin-bottom: 30px;
}
.pro-con-table th, .pro-con-table td {
    border: 1px solid #D2D0CE;
    padding: 15px;
    text-align: left;
    vertical-align: top;
}
.pro-con-table th {
    background-color: #464EB8;
    color: white;
    font-size: 1.1em;
}
.pro-con-table td:first-child {
    background-color: #f9fef9;
}
.pro-con-table td:last-child {
    background-color: #fffaf9;
}
.step-card {
    background-color: #ffffff;
    border: 1px solid #E1DFDD;
    border-top: 4px solid #464EB8;
    box-shadow: 0 2px 4px rgba(0,0,0,0.05);
    padding: 20px;
    margin-bottom: 20px;
    border-radius: 4px;
}
.step-number {
    display: inline-block;
    background-color: #464EB8;
    color: white;
    width: 30px;
    height: 30px;
    text-align: center;
    border-radius: 50%;
    line-height: 30px;
    font-weight: bold;
    margin-right: 10px;
}
.notice {
    background-color: #FFF4CE;
    border-left: 4px solid #FBC11E;
    padding: 15px;
    margin: 20px 0;
    font-size: 0.95em;
}
code {
    background-color: #F3F2F1;
    padding: 2px 6px;
    border-radius: 3px;
    font-family: Consolas, monospace;
    font-size: 0.9em;
    color: #d63384;
}
</style>
<div class="teams-blog-post">
<p>Securing a specific phone number so that only authorized callers can reach the destination is a common request in modern telecommunications. But how do you achieve this in Microsoft Teams Phone when you are using <strong>Microsoft Calling Plans</strong> and don’t have a Session Border Controller (SBC) to handle complex pre-routing logic?</p>
<p>In this guide, we will walk you through a highly effective configuration workaround that uses native Teams features to create a PIN-protected entry point.</p>
<p><em>[Insert your flowchart diagram here showing PSTN call routing with PIN authentication]</em></p>
<div class="use-case-box">
<h3><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f3af.png" alt="🎯" class="wp-smiley" style="height: 1em; max-height: 1em;" /> The Use Case: Why Are We Doing This?</h3>
<p>Imagine you have a dedicated VIP support hotline, an emergency IT-escalation number, or an exclusive dial-in for remote field workers. You publish a standard PSTN number, but you only want the call to ring the target team if the caller knows a specific secret code (PIN).</p>
<p><strong>The Desired Flow:</strong></p>
<ol>
<li>Caller dials the PSTN number.</li>
<li>Caller hears an announcement: <em>“Please enter your access code.”</em></li>
<li><strong>If correct:</strong> The call is routed to the target user or Call Queue.</li>
<li><strong>If incorrect / no input:</strong> The caller is told the code is invalid, and the call drops.</li>
</ol></div>
<h2>The Challenge: Microsoft Teams Calling Plans Limitations</h2>
<p>If you use Direct Routing, an SBC (like AudioCodes or Ribbon) would intercept the call, ask for the PIN, verify it, and then forward the call to Teams. However, with <strong>Microsoft Calling Plans</strong>, the call goes straight into the Microsoft cloud. Microsoft Teams <strong>does not</strong> have a native “Require PIN” toggle for Auto Attendants.</p>
<p><strong>The Solution: The “Dial by Extension” Hack.</strong> We will configure an Auto Attendant to ask for the PIN, but technically, Teams will be using its <em>Dial by extension</em> feature. The “PIN” will actually be the target user’s configured extension.</p>
<h2>Pros and Cons of This Configuration</h2>
<table class="pro-con-table">
<tr>
<th><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Advantages (Why we do it this way)</th>
<th><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Disadvantages (What you need to know)</th>
</tr>
<tr>
<td>
<ul>
<li><strong>No Extra Costs:</strong> Uses existing Teams Phone licenses and Auto Attendants.</li>
<li><strong>Fully Cloud-Native:</strong> No SBC, on-prem hardware, or Azure Communication Services development required.</li>
<li><strong>Simple to Maintain:</strong> PINs can be updated by changing a user’s extension in Entra ID.</li>
</ul>
</td>
<td>
<ul>
<li><strong>Not Enterprise-Grade Security:</strong> This is a routing trick, not cryptographic multi-factor authentication.</li>
<li><strong>Static System Prompts:</strong> If the user enters a wrong PIN, Teams plays a default system message (e.g., <em>“We didn’t find a match”</em>) before dropping the call. You cannot fully customize the “Wrong PIN” audio prompt.</li>
<li><strong>Directory Search Limits:</strong> The PIN (extension) must be uniquely assigned to a user in your directory.</li>
</ul>
</td>
</tr>
</table>
<hr>
<h2><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2699.png" alt="⚙" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Step-by-Step Configuration Guide</h2>
<p>Follow these steps to set up the PIN-protected routing in your Microsoft 365 environment.</p>
<div class="step-card">
<h3><span class="step-number">1</span> Prepare the Target User (Assigning the “PIN”)</h3>
<p>First, we need to assign the secret PIN as an extension to the user who should receive the calls.</p>
<ol>
<li>Go to the <strong>Microsoft 365 Admin Center</strong> > <strong>Users</strong> > <strong>Active users</strong>.</li>
<li>Select the target user (this user must have a Teams Phone license).</li>
<li>Go to <strong>Manage contact information</strong>.</li>
<li>In the <strong>Office phone</strong> field, enter a dummy number with the desired PIN as the extension. Format it strictly like this: <code>+10000000000;ext=8524</code> (Assuming <strong>8524</strong> is your desired PIN).</li>
<li>Save the changes. <em>Note: It can take up to 24 hours for the Teams directory sync to recognize the new extension, though it often takes only a few hours.</em></li>
</ol>
<div class="notice">
            <strong>Pro Tip:</strong> If you want the call to go to a Call Queue instead of a single person, assign this extension to a “dummy” licensed user account, and set that user’s Teams client to immediately forward all calls to the desired Call Queue.
        </div>
</p></div>
<div class="step-card">
<h3><span class="step-number">2</span> Create the “PIN Gateway” Auto Attendant</h3>
<p>Now, we create the Auto Attendant that will act as the gatekeeper.</p>
<ol>
<li>Open the <strong>Teams Admin Center</strong>.</li>
<li>Navigate to <strong>Voice</strong> > <strong>Auto attendants</strong> and click <strong>Add</strong>.</li>
<li>Name it something like <em>AA – PIN Gateway</em>.</li>
<li>Set the <strong>Operator</strong> to “Disconnect” (since we don’t want callers bypassing the PIN).</li>
<li>Set the Time Zone and Language. (The language determines the voice of the default system error messages).</li>
</ol></div>
<div class="step-card">
<h3><span class="step-number">3</span> Configure Call Flow & Menu Options</h3>
<p>This is where the magic happens. We will use the Menu Options to force the caller to interact, allowing the Directory Search to capture their DTMF (keypad) input.</p>
<ol>
<li>Under <strong>Call flow</strong>, choose <strong>Play menu options</strong>.</li>
<li>For the audio, choose <strong>Play an audio file</strong>. Upload a professionally recorded MP3 or WAV file that says: <em>“Welcome. Please enter your 4-digit access code to proceed. If you do not have a code, please hang up.”</em></li>
<li><strong>Crucial Step:</strong> Do NOT assign any keys (0-9) to routing options. Leave the dial pad assignments empty.</li>
<li>Under <strong>Directory search</strong>, select <strong>Dial by extension</strong>.</li>
</ol>
<p><strong>What happens here?</strong> The Auto Attendant plays your custom audio. Because “Dial by extension” is enabled, it listens for keypad inputs. If the caller types <code>8524</code>, the system searches the directory, finds the user from Step 1, and routes the call to them.</p>
</p></div>
<div class="step-card">
<h3><span class="step-number">4</span> Configure Default Routing (For incorrect / no PIN)</h3>
<p>We must define what happens if the caller just waits and presses nothing.</p>
<ol>
<li>Still in the <strong>Call flow</strong> section, look for the setting regarding what happens when callers don’t make a choice (Timeout).</li>
<li>Set the default action to <strong>Disconnect</strong>.</li>
</ol>
<p><strong>What about wrong PINs?</strong> If a caller enters <code>1111</code>, Teams will look for extension 1111. When it doesn’t find it, the Microsoft default voice will say <em>“We couldn’t find a match.”</em> After a few failed attempts, the system automatically drops the call. This fulfills the requirement that invalid codes cannot proceed.</p>
</p></div>
<div class="step-card">
<h3><span class="step-number">5</span> Assign the PSTN Number via Resource Account</h3>
<p>Finally, we need to make this Auto Attendant reachable from the outside world.</p>
<ol>
<li>Create a new <strong>Resource Account</strong> in the Teams Admin Center.</li>
<li>Assign a <em>Microsoft Teams Phone Resource Account</em> license to it.</li>
<li>Acquire a PSTN number from your Microsoft Calling Plans inventory and assign it to this Resource Account.</li>
<li>Assign this Resource Account to your newly created Auto Attendant.</li>
</ol></div>
<h2>Conclusion</h2>
<p>While Microsoft Teams doesn’t offer a simple “PIN toggle,” utilizing the <em>Dial by extension</em> feature provides a robust, zero-cost workaround for Microsoft Calling Plan users. It successfully gates a phone line behind a numeric code, ensuring only authorized callers reach your internal teams, all while keeping your infrastructure 100% in the cloud.</p>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://www.msb365.blog/?feed=rss2&#038;p=6144</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Bridging the Gap: Mastering M365 Cross-Tenant Calendar Sharing</title>
		<link>https://www.msb365.blog/?p=6141</link>
					<comments>https://www.msb365.blog/?p=6141#respond</comments>
		
		<dc:creator><![CDATA[drago]]></dc:creator>
		<pubDate>Mon, 23 Feb 2026 07:27:10 +0000</pubDate>
				<category><![CDATA[MS Exchange]]></category>
		<guid isPermaLink="false">https://www.msb365.blog/?p=6141</guid>

					<description><![CDATA[In today’s interconnected business world, organizations rarely operate in isolation. Whether it’s a merger, a holding structure with multiple subsidiaries, or a long-term joint venture, the need to see “when” a colleague from another organization is available is critical. Scheduling meetings via email ping-pong (“Are you free Tuesday at 2?” – “No, how about Wednesday?”) [&#8230;]]]></description>
										<content:encoded><![CDATA[<style>
    /* Scoped styles for the blog post container to avoid theme conflicts */
    .blog-post-wrapper {
        font-family: 'Segoe UI', 'Helvetica Neue', Helvetica, Arial, sans-serif;
        line-height: 1.7;
        color: #333;
        background-color: #fff;
        padding: 40px;
        border-radius: 8px;
        box-shadow: 0 4px 20px rgba(0,0,0,0.05);
        border: 1px solid #e1e1e1;
        max-width: 100%;
        margin: 0 auto;
    }</p>
<p>    /* Logo Styling */
    .blog-post-wrapper img.post-logo {
        max-width: 280px;
        height: auto;
        margin-bottom: 30px;
        display: block;
    }</p>
<p>    /* Typography */
    .blog-post-wrapper h1 {
        color: #2c3e50;
        font-size: 2.2em;
        margin-bottom: 20px;
        line-height: 1.3;
    }</p>
<p>    .blog-post-wrapper h2 {
        color: #0078d4;
        margin-top: 40px;
        margin-bottom: 20px;
        font-size: 1.6em;
        border-bottom: 2px solid #f0f0f0;
        padding-bottom: 10px;
    }</p>
<p>    .blog-post-wrapper h3 {
        color: #444;
        margin-top: 25px;
        font-size: 1.25em;
        font-weight: 600;
    }</p>
<p>    /* Use Case Cards */
    .use-case-grid {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
        gap: 20px;
        margin: 30px 0;
    }</p>
<p>    .use-case-card {
        background: #f8f9fa;
        padding: 20px;
        border-radius: 8px;
        border-left: 4px solid #0078d4;
    }</p>
<p>    .use-case-card h4 {
        margin-top: 0;
        color: #0078d4;
    }</p>
<p>    /* Info Boxes */
    .blog-post-wrapper .note {
        background-color: #e6f7ff;
        border-left: 4px solid #0078d4;
        padding: 15px;
        margin: 20px 0;
        border-radius: 0 4px 4px 0;
    }</p>
<p>    .blog-post-wrapper .warning {
        background-color: #fff8e1;
        border-left: 4px solid #fbc02d;
        padding: 15px;
        margin: 20px 0;
        border-radius: 0 4px 4px 0;
    }</p>
<p>    /* Technical Steps */
    .step-container {
        margin-bottom: 20px;
        padding-left: 20px;
        border-left: 2px solid #e9ecef;
    }</p>
<p>    .step-title {
        font-weight: bold;
        color: #0078d4;
        display: block;
        margin-bottom: 5px;
    }</p>
<p>    /* Tables */
    .blog-post-wrapper table {
        width: 100%;
        border-collapse: collapse;
        margin-top: 20px;
        font-size: 0.95em;
        background: #fff;
    }</p>
<p>    .blog-post-wrapper th {
        background-color: #0078d4;
        color: white;
        padding: 12px;
        text-align: left;
    }</p>
<p>    .blog-post-wrapper td {
        border: 1px solid #dee2e6;
        padding: 12px;
        vertical-align: top;
    }</p>
<p>    .blog-post-wrapper tr:nth-child(even) {
        background-color: #f8f9fa;
    }</p>
<p>    /* Mobile Responsive */
    @media screen and (max-width: 768px) {
        .blog-post-wrapper {
            padding: 20px;
        }
        .use-case-grid {
            grid-template-columns: 1fr;
        }
        .blog-post-wrapper table {
            display: block;
            overflow-x: auto;
        }
    }
</style>
<div class="blog-post-wrapper">
<p>In today’s interconnected business world, organizations rarely operate in isolation. Whether it’s a merger, a holding structure with multiple subsidiaries, or a long-term joint venture, the need to see “when” a colleague from another organization is available is critical.</p>
<p>Scheduling meetings via email ping-pong (“Are you free Tuesday at 2?” – “No, how about Wednesday?”) is inefficient. The solution lies within <strong>Exchange Online Organization Relationships</strong>. This guide walks you through the “Why”, the “How”, and the “What to Expect”.</p>
<h2>Real-World Use Cases</h2>
<p>Before we dive into the configuration, let’s look at where this setup delivers the most value:</p>
<div class="use-case-grid">
<div class="use-case-card">
<h4><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f91d.png" alt="🤝" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Mergers & Acquisitions</h4>
<p><strong>Scenario:</strong> Company A buys Company B. Migration takes months, but management needs to schedule meetings <em>today</em>.</p>
<p><strong>Benefit:</strong> Instant visibility of Free/Busy times across both tenants without waiting for full IT integration.</p>
</p></div>
<div class="use-case-card">
<h4><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f3e2.png" alt="🏢" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Holding Structures</h4>
<p><strong>Scenario:</strong> A parent company has 5 subsidiaries, each with its own M365 tenant.</p>
<p><strong>Benefit:</strong> Seamless scheduling across the entire group while keeping data and administration strictly separated.</p>
</p></div>
<div class="use-case-card">
<h4><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f680.png" alt="🚀" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Joint Ventures</h4>
<p><strong>Scenario:</strong> Two independent companies work on a major project for 12 months.</p>
<p><strong>Benefit:</strong> Teams can collaborate as if they were in the same office, without needing Guest Accounts for every single user.</p>
</p></div>
</p></div>
<h2>Technical Guide: Setting Up Organization Relationships</h2>
<p>This configuration establishes a trust relationship specifically for calendar data. It does <strong>not</strong> give access to emails or files.</p>
<div class="warning">
        <strong>Admin Requirement:</strong> This configuration must be performed <strong>mirrored on both tenants</strong> (Tenant A -> Tenant B, and Tenant B -> Tenant A) for the access to work bi-directionally.
    </div>
<h3>Step-by-Step Configuration</h3>
<div class="step-container">
        <span class="step-title">Step 1: Access the Exchange Admin Center</span><br />
        Navigate to <a href="https://admin.exchange.microsoft.com" target="_blank">admin.exchange.microsoft.com</a> with Global Admin or Exchange Admin credentials.
    </div>
<div class="step-container">
        <span class="step-title">Step 2: Locate Sharing Settings</span><br />
        In the left-hand menu, go to <strong>Organization</strong> > <strong>Sharing</strong>.
    </div>
<div class="step-container">
        <span class="step-title">Step 3: Add Relationship</span><br />
        Find the <strong>Organization Sharing</strong> section and click on <strong>Add organization relationship</strong>.
    </div>
<div class="step-container">
        <span class="step-title">Step 4: Configure Domain & Permissions</span></p>
<ul>
<li><strong>Relationship Name:</strong> E.g., “To Partner Company”.</li>
<li><strong>Domains to share with:</strong> Enter the partner’s domain (e.g., <code>partner-company.com</code>).</li>
<li><strong>Sharing Level:</strong> Enable “Calendar free/busy information sharing”.</li>
</ul>
<p><strong>Decision Point:</strong> Choose your level of transparency:</p>
<ul>
<li><em>Time only:</em> Users see “Busy” blocks. Good for loose partnerships.</li>
<li><em>Time, subject, and location:</em> Users see “Meeting with Client X in Room 202”. Recommended for M&A and internal holdings.</li>
</ul></div>
<div class="note">
        <strong>Propagation Time:</strong> Once both sides have configured this, it can take up to <strong>24 hours</strong> for Microsoft’s backend to replicate the settings. Patience is key!
    </div>
<h2>User Experience: How to View the Calendar</h2>
<p>Unlike internal colleagues, external calendars don’t just “appear.” Users need to add them once.</p>
<h3>In Outlook (New / Web / Classic)</h3>
<ol>
<li>Go to the <strong>Calendar View</strong>.</li>
<li>Select <strong>Add Calendar</strong> > <strong>From Directory</strong> (or use the search bar).</li>
<li>Type the <strong>full email address</strong> of the external colleague (e.g., <code>john.doe@partner-company.com</code>).</li>
<li>Click <strong>Open/Add</strong>.</li>
</ol>
<p>Outlook will now query the external tenant and display the availability side-by-side with your own calendar.</p>
<h2>The Capabilities Matrix: Managing Expectations</h2>
<p>It is crucial to understand that an Organization Relationship is a “Look but don’t touch” scenario. Here is a breakdown of what is technically possible:</p>
<table>
<thead>
<tr>
<th>Feature</th>
<th>Status</th>
<th>Details</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>View Free/Busy Status</strong></td>
<td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Yes</td>
<td>You can see when they are available for a meeting.</td>
</tr>
<tr>
<td><strong>View Subject & Location</strong></td>
<td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Yes</td>
<td>Only if enabled by Admins in Step 4.</td>
</tr>
<tr>
<td><strong>Edit/Delete Appointments</strong></td>
<td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> No</td>
<td>Read-Only access. You cannot modify their calendar.</td>
</tr>
<tr>
<td><strong>Create Items in their Calendar</strong></td>
<td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> No</td>
<td>You cannot place an appointment directly into their calendar; you must send a meeting invite.</td>
</tr>
<tr>
<td><strong>View Private Items</strong></td>
<td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> No</td>
<td>Private appointments remain private (shown only as “Private” or “Busy”).</td>
</tr>
<tr>
<td><strong>Open Attachments</strong></td>
<td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> No</td>
<td>You cannot see meeting agendas, files, or body text inside the appointment.</td>
</tr>
<tr>
<td><strong>Mobile App Sync</strong></td>
<td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Partial</td>
<td>External calendars often require adding via Desktop first to appear in the Outlook Mobile App.</td>
</tr>
</tbody>
</table>
<h2>Conclusion</h2>
<p>Setting up an Organization Relationship is a quick, high-impact win for IT departments managing split environments. It solves the number one scheduling headache without the security complexity of full Guest Access or Trust setups.</p>
<p><em>Need to go a step further and allow users to act as delegates or sync users as contacts? Contact us to discuss <strong>Cross-Tenant Synchronization</strong>.</em></p>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://www.msb365.blog/?feed=rss2&#038;p=6141</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Microsoft Teams Shared Locations</title>
		<link>https://www.msb365.blog/?p=6126</link>
					<comments>https://www.msb365.blog/?p=6126#respond</comments>
		
		<dc:creator><![CDATA[drago]]></dc:creator>
		<pubDate>Mon, 26 Jan 2026 07:42:35 +0000</pubDate>
				<category><![CDATA[Microsoft 365]]></category>
		<category><![CDATA[MS Teams]]></category>
		<guid isPermaLink="false">https://www.msb365.blog/?p=6126</guid>

					<description><![CDATA[Technical Deep Dive 2026 A comprehensive guide to mobile sharing, AI-driven Wi-Fi detection, and enterprise privacy. In the modern era of hybrid work, the question “Where are you?” has replaced “How are you?” as the most common workplace icebreaker. As of 2026, Microsoft has significantly expanded how Teams handles physical presence—moving from simple manual pin-drops [&#8230;]]]></description>
										<content:encoded><![CDATA[<style>
    /* CSS Scoped to this container only to protect your site layout */
    .teams-blog-container {
        font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
        line-height: 1.6;
        color: #242424;
        max-width: 850px;
        margin: 0 auto;
        padding: 20px;
        background-color: #fff;
        box-sizing: border-box;
    }</p>
<p>    /* Responsive Header */
    .teams-header {
        background: linear-gradient(135deg, #464EB8 0%, #6264A7 100%);
        color: white;
        padding: 40px 20px;
        border-radius: 12px;
        margin-bottom: 40px;
        text-align: center;
        box-shadow: 0 4px 15px rgba(70, 78, 184, 0.2);
    }
    .teams-header h1 {
        margin: 15px 0 0 0;
        font-size: clamp(1.8rem, 4vw, 2.5rem); /* Responsive font size */
        font-weight: 800;
        letter-spacing: -0.025em;
        line-height: 1.2;
        color: white;
    }
    .teams-header p {
        font-size: 1.1rem;
        opacity: 0.95;
        margin-top: 15px;
        color: #f0f0f0;
    }</p>
<p>    /* Badge Style */
    .teams-badge {
        display: inline-block;
        background: rgba(255,255,255,0.25);
        padding: 5px 15px;
        border-radius: 20px;
        font-size: 0.8rem;
        font-weight: 600;
        text-transform: uppercase;
        letter-spacing: 0.5px;
        backdrop-filter: blur(5px);
    }</p>
<p>    /* Content Typography */
    .teams-blog-container h2 {
        color: #464EB8;
        border-bottom: 2px solid #f0f0f0;
        padding-bottom: 10px;
        margin-top: 50px;
        font-size: 1.8rem;
    }
    .teams-blog-container h3 {
        color: #252423;
        margin-top: 35px;
        font-size: 1.4rem;
    }</p>
<p>    /* Info Box */
    .teams-info-box {
        background-color: #f3f2f1;
        border-left: 5px solid #464EB8;
        padding: 20px;
        margin: 30px 0;
        border-radius: 0 8px 8px 0;
    }</p>
<p>    /* Tables */
    .teams-table-container {
        overflow-x: auto;
        margin: 30px 0;
        box-shadow: 0 2px 10px rgba(0,0,0,0.05);
        border-radius: 8px;
    }
    .teams-table {
        width: 100%;
        border-collapse: collapse;
        text-align: left;
        min-width: 600px; /* Ensures table doesn't squish too much */
    }
    .teams-table th {
        background-color: #f8f8f8;
        padding: 15px;
        border-bottom: 2px solid #e1e1e1;
        color: #464EB8;
        font-weight: 700;
    }
    .teams-table td {
        padding: 15px;
        border-bottom: 1px solid #e1e1e1;
    }
    .teams-table tr:last-child td {
        border-bottom: none;
    }</p>
<p>    /* Feature Grid */
    .teams-feature-grid {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 20px;
        margin: 30px 0;
    }
    .teams-feature-card {
        background: #f9f9f9;
        padding: 20px;
        border-radius: 12px;
        border: 1px solid #eee;
        transition: transform 0.2s;
    }
    .teams-feature-card:hover {
        transform: translateY(-2px);
        box-shadow: 0 5px 15px rgba(0,0,0,0.05);
    }
    .teams-feature-card h4 {
        margin-top: 0;
        color: #464EB8;
    }</p>
<p>    /* Sources */
    .teams-source-list {
        background-color: #fafafa;
        padding: 25px;
        border-radius: 8px;
        border: 1px dashed #ccc;
        margin-top: 60px;
        font-size: 0.9rem;
    }
    .teams-source-list h4 {
        margin-top: 0;
        color: #616161;
        text-transform: uppercase;
        font-size: 0.85rem;
    }
    .teams-source-list a {
        color: #464EB8;
        text-decoration: none;
        font-weight: 500;
    }
    .teams-source-list a:hover {
        text-decoration: underline;
    }</p>
<p>    @media (max-width: 650px) {
        .teams-feature-grid { grid-template-columns: 1fr; }
        .teams-blog-container { padding: 15px; }
        .teams-header { padding: 30px 15px; }
    }
</style>
<div class="teams-blog-container">
<header class="teams-header">
        <span class="teams-badge">Technical Deep Dive 2026</span></p>
<p>A comprehensive guide to mobile sharing, AI-driven Wi-Fi detection, and enterprise privacy.</p>
</header>
<p>In the modern era of hybrid work, the question <em>“Where are you?”</em> has replaced <em>“How are you?”</em> as the most common workplace icebreaker. As of 2026, Microsoft has significantly expanded how Teams handles physical presence—moving from simple manual pin-drops to <strong>AI-driven, network-aware location intelligence</strong>.</p>
<h2>1. The Three Faces of Location in Teams</h2>
<p>To understand the functionality, we must distinguish between three different features that often get confused in the Microsoft 365 ecosystem:</p>
<div class="teams-table-container">
<table class="teams-table">
<thead>
<tr>
<th scope="col">Feature</th>
<th scope="col">Primary Use Case</th>
<th scope="col">Device</th>
<th scope="col">Data Type</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Shared Location (Chat)</strong></td>
<td>Real-time GPS sharing with a specific contact.</td>
<td>Mobile (iOS/Android)</td>
<td>Precise GPS Coordinates</td>
</tr>
<tr>
<td><strong>Work Location (Status)</strong></td>
<td>Indicating “In the Office” or “Remote”.</td>
<td>Desktop & Mobile</td>
<td>Building name or generic status</td>
</tr>
<tr>
<td><strong>Smart Detection (2026)</strong></td>
<td>Auto-updating office location via Wi-Fi.</td>
<td>Desktop & Mobile</td>
<td>Network-based (BSSID)</td>
</tr>
</tbody>
</table></div>
<h2>2. Deep Dive: Shared Location in Mobile Chat</h2>
<p>This remains the most “active” form of sharing. It is a mobile-centric feature that allows users to share their physical coordinates via a Teams chat or group channel.</p>
<h3>Static vs. Live Location</h3>
<ul>
<li><strong>Static Location:</strong> A snapshot of your current position. Once sent, the pin stays where you were at that moment.</li>
<li><strong>Live Location (Real-Time):</strong> A continuous stream. As of the latest updates, users can share this for <strong>30 minutes, 1 hour, or 8 hours</strong>.</li>
</ul>
<div class="teams-info-box">
        <strong>How to trigger it:</strong><br />
        Tap the <strong>“+” (Plus)</strong> icon in a mobile chat > Select <strong>Location</strong>.</p>
<p>        <em>Note: Since 2025, a mandatory App-level Consent Popup appears, ensuring users are aware of the tracking duration.</em>
    </div>
<h2>3. The 2026 Game Changer: Automatic Wi-Fi Detection</h2>
<p>Following the roadmap milestones of late 2025, Microsoft has finalized the rollout of <strong>Smart Work Location Tracking</strong> (Roadmap ID: 409534).</p>
<p>Teams now recognizes your organization’s Wi-Fi access points (BSSIDs). When your laptop connects to a registered corporate network, Teams automatically updates your status to <strong>“Working from Building A, Floor 3”</strong>.</p>
<div class="teams-feature-grid">
<div class="teams-feature-card">
<h4>Privacy Guardrail</h4>
<p>This feature only triggers during your defined “Working Hours” in Outlook. It stays dormant during personal time.</p>
</p></div>
<div class="teams-feature-card">
<h4>Opt-in Culture</h4>
<p>It is <strong>Off by default</strong>. Both Admin policies and User consent must be granted simultaneously to activate tracking.</p>
</p></div>
</p></div>
<h2>4. Administrative Configuration & Compliance</h2>
<p>For IT Admins, the control center has evolved. Location-Based Services (LBS) are now managed under a unified privacy framework.</p>
<h3>The Messaging Policy</h3>
<p>In the Teams Admin Center (TAC), the toggle <strong>“Send location in messages”</strong> controls whether the mobile sharing icon is visible to your users. If disabled, the entire Location sub-menu disappears from the mobile app.</p>
<h3>Data Residency</h3>
<p>A critical point for compliance officers: Microsoft Teams does <strong>not</strong> store a historical movement log. The data is transient. Once a live session ends, the real-time coordinates are purged from the active session, though the chat message itself follows your organization’s standard retention policy.</p>
<h2>5. Frequently Asked Questions</h2>
<h3>Can my manager see a map of my movements all day?</h3>
<p><strong>Absolutely not.</strong> Microsoft Teams does not provide a “surveillance dashboard.” Location data is only used to update your status or shared manually in a chat. There is no admin command to “ping” an employee’s location without their knowledge.</p>
<h3>Why can’t I see the “Location” button on my Desktop app?</h3>
<p>Precise GPS sharing is a mobile-only feature because desktops generally lack GPS hardware. Desktop users can only set their “Work Location” (status) or use the Smart Wi-Fi detection if enabled.</p>
<div class="teams-source-list">
<h4>Official Sources & Technical Documentation</h4>
<ul>
<li><a href="https://support.microsoft.com/en-us/office/manage-location-sharing-in-microsoft-teams-583dd649-87fc-4b23-aed6-f4e2279297f9" target="_blank" rel="noopener">Microsoft Support: Manage Location Sharing in Teams Mobile</a></li>
<li><a href="https://learn.microsoft.com/en-us/microsoftteams/privacy/user-location-data" target="_blank" rel="noopener">Microsoft Learn: User Location Data & Consent Experience</a></li>
<li><a href="https://www.microsoft.com/microsoft-365/roadmap?filters=Microsoft%20Teams" target="_blank" rel="noopener">Microsoft 365 Roadmap (Search ID: 409534) – Smart Location Tracking</a></li>
<li><a href="https://techcommunity.microsoft.com/blog/microsoftteamsblog/what%E2%80%99s-new-in-microsoft-teams--microsoft-ignite-2025/4470387" target="_blank" rel="noopener">Microsoft Tech Community: Ignite 2025 Workplace Coordination Updates</a></li>
</ul></div>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://www.msb365.blog/?feed=rss2&#038;p=6126</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>The Deep-Dive Guide: Microsoft Graph API for PowerShell</title>
		<link>https://www.msb365.blog/?p=6118</link>
					<comments>https://www.msb365.blog/?p=6118#respond</comments>
		
		<dc:creator><![CDATA[drago]]></dc:creator>
		<pubDate>Mon, 12 Jan 2026 07:20:15 +0000</pubDate>
				<category><![CDATA[Entra ID]]></category>
		<category><![CDATA[Microsoft 365]]></category>
		<category><![CDATA[MS Exchange]]></category>
		<category><![CDATA[MS Graph]]></category>
		<category><![CDATA[MS Teams]]></category>
		<category><![CDATA[PowerShell]]></category>
		<guid isPermaLink="false">https://www.msb365.blog/?p=6118</guid>

					<description><![CDATA[In the modern Microsoft 365 landscape, the “Portal-Clicker” is being replaced by the “Automation Architect.” Microsoft Graph is the engine behind this transformation. While legacy modules like AzureAD or MSOnline were siloed, Graph provides a single endpoint, a single authentication model, and a single data schema. The Architect’s Logic: Every PowerShell command in the Microsoft [&#8230;]]]></description>
										<content:encoded><![CDATA[<div class="graph-deep-dive-article" style="color: #201f1e; line-height: 1.8; font-family: 'Segoe UI', Tahoma, sans-serif;">
<p>In the modern Microsoft 365 landscape, the “Portal-Clicker” is being replaced by the “Automation Architect.” Microsoft Graph is the engine behind this transformation. While legacy modules like <code>AzureAD</code> or <code>MSOnline</code> were siloed, Graph provides a <strong>single endpoint</strong>, a <strong>single authentication model</strong>, and a <strong>single data schema</strong>.</p>
<div style="background: #e7f3ff; border-left: 5px solid #0078d4; padding: 25px; margin: 30px 0; border-radius: 0 8px 8px 0;">
        <strong>The Architect’s Logic:</strong> Every PowerShell command in the Microsoft Graph SDK is a wrapper for a REST API URL.<br />
        <code>Get-MgUser -UserId "bob@contoso.com"</code> is actually a <code>GET</code> request to <code>https://graph.microsoft.com/v1.0/users/bob@contoso.com</code>.
    </div>
<h2 style="color: #0078d4; border-bottom: 2px solid #eee; padding-bottom: 10px; margin-top: 40px;">1. Professional Setup & API Profiles</h2>
<p>Before scripting, you must decide which API version to target. The SDK supports <strong>v1.0</strong> (Production-ready) and <strong>Beta</strong> (latest preview features like Sign-in logs or specialized Teams settings).</p>
<pre style="background: #1e1e1e; color: #dcdcdc; padding: 20px; border-radius: 8px; overflow-x: auto; border: 1px solid #333;"><code># Switch to Beta for advanced features
Select-MgProfile -Name "beta"

# Connect with specific permissions (Scopes)
Connect-MgGraph -Scopes "User.Read.All", "Group.ReadWrite.All", "Mail.Read", "Sites.Read.All"</code></pre>
<h2 style="color: #0078d4; border-bottom: 2px solid #eee; padding-bottom: 10px; margin-top: 40px;">2. Unattended Automation (App-Only Auth)</h2>
<p>For background tasks (Azure Automation, Task Scheduler), interactive logins are impossible. You must use an <strong>App Registration</strong> with a certificate for maximum security.</p>
<pre style="background: #1e1e1e; color: #dcdcdc; padding: 20px; border-radius: 8px; overflow-x: auto; border: 1px solid #333;"><code>$params = @{
    ClientId              = "YOUR_APP_ID_GUID"
    TenantId              = "YOUR_TENANT_ID"
    CertificateThumbprint = "A1B2C3D4E5F6G7H8I9J0"
}
Connect-MgGraph @params</code></pre>
<h2 style="color: #0078d4; border-bottom: 2px solid #eee; padding-bottom: 10px; margin-top: 40px;">3. Service Deep-Dives: Read & Write</h2>
<h3 style="color: #106ebe;">A. Entra ID: OData Filtering Mastery</h3>
<p>A true deep dive requires moving beyond <code>Where-Object</code>. Filter at the source to prevent script lag and memory exhaustion.</p>
<pre style="background: #1e1e1e; color: #dcdcdc; padding: 20px; border-radius: 8px; overflow-x: auto; border: 1px solid #333;"><code># Efficient: Server-side filtering for active Finance users
$Filter = "Department eq 'Finance' and AccountEnabled eq true"
$Users = Get-MgUser -Filter $Filter -All -Property "Id", "DisplayName", "JobTitle"</code></pre>
<h3 style="color: #106ebe;">B. Microsoft Teams: Resource Provisioning</h3>
<p>Creating a Team is a multi-step process. In Graph, you often create a Group first and then “Team-enable” it.</p>
<pre style="background: #1e1e1e; color: #dcdcdc; padding: 20px; border-radius: 8px; overflow-x: auto; border: 1px solid #333;"><code>$teamBody = @{
    DisplayName = "New Project Team"
    "template@odata.bind" = "https://graph.microsoft.com/v1.0/teamsTemplates('standard')"
}
New-MgTeam -BodyParameter $teamBody</code></pre>
<h3 style="color: #106ebe;">C. SharePoint & OneDrive: The “Drive” Logic</h3>
<p>SharePoint Sites contain <code>Drives</code> (Document Libraries), which contain <code>DriveItems</code> (Files/Folders).</p>
<pre style="background: #1e1e1e; color: #dcdcdc; padding: 20px; border-radius: 8px; overflow-x: auto; border: 1px solid #333;"><code># Search for a site and list its library root
$Site = Get-MgSite -Search "Marketing"
Get-MgSiteDriveItem -SiteId $Site.Id -DriveId (Get-MgSiteDrive -SiteId $Site.Id).Id</code></pre>
<h2 style="color: #0078d4; border-bottom: 2px solid #eee; padding-bottom: 10px; margin-top: 40px;">4. Advanced Query Parameters</h2>
<p>To optimize performance, use <code>-ExpandProperty</code> to join related data into a single request, avoiding multiple round-trips.</p>
<pre style="background: #1e1e1e; color: #dcdcdc; padding: 20px; border-radius: 8px; overflow-x: auto; border: 1px solid #333;"><code># Fetch user AND their manager in one call
$User = Get-MgUser -UserId "admin@domain.com" -ExpandProperty "manager"
$ManagerMail = $User.Manager.AdditionalProperties["mail"]</code></pre>
<h2 style="color: #0078d4; border-bottom: 2px solid #eee; padding-bottom: 10px; margin-top: 40px;">5. JSON Batching: Combining 20 Requests</h2>
<p>Batching allows you to group up to 20 individual API calls into a single HTTP POST. This is essential for high-speed synchronization tools.</p>
<pre style="background: #1e1e1e; color: #dcdcdc; padding: 20px; border-radius: 8px; overflow-x: auto; border: 1px solid #333;"><code>$batchRequest = @{
    requests = @(
        @{ id = "1"; method = "GET"; url = "/users/user1@domain.com" },
        @{ id = "2"; method = "GET"; url = "/users/user2@domain.com" }
    )
}
$BatchResult = Invoke-MgGraphRequest -Method POST -Uri "https://graph.microsoft.com/v1.0/`$batch" -Body $batchRequest</code></pre>
<h2 style="color: #0078d4; border-bottom: 2px solid #eee; padding-bottom: 10px; margin-top: 40px;">6. Delta Queries: Tracking Changes</h2>
<p>Instead of scanning 50,000 users every hour, use **Delta Queries** to only pull objects that were created, updated, or deleted since your last sync.</p>
<pre style="background: #1e1e1e; color: #dcdcdc; padding: 20px; border-radius: 8px; overflow-x: auto; border: 1px solid #333;"><code># Initial sync gets the deltaLink
$Delta = Get-MgUserDelta
$SyncToken = $Delta.AdditionalProperties["@odata.deltaLink"]

# Future runs use the $SyncToken to fetch ONLY changes
$Changes = Invoke-MgGraphRequest -Method GET -Uri $SyncToken</code></pre>
<h2 style="color: #0078d4; border-bottom: 2px solid #eee; padding-bottom: 10px; margin-top: 40px;">7. Expert Error Handling</h2>
<p>Graph errors are JSON objects. A professional script parses these to understand if a failure was due to a missing resource (404) or throttling (429).</p>
<pre style="background: #1e1e1e; color: #dcdcdc; padding: 20px; border-radius: 8px; overflow-x: auto; border: 1px solid #333;"><code>try {
    Update-MgUser -UserId "ghost-id" -Department "IT"
} catch {
    $Err = $_.Exception.Message | ConvertFrom-Json -ErrorAction SilentlyContinue
    Write-Error "Code: $($Err.error.code) - Message: $($Err.error.message)"
}</code></pre>
<h2 style="color: #0078d4; border-bottom: 2px solid #eee; padding-bottom: 10px; margin-top: 40px;">Summary Checklist</h2>
<table style="width: 100%; border-collapse: collapse; margin: 30px 0; background: #fff; box-shadow: 0 2px 5px rgba(0,0,0,0.1);">
<thead>
<tr style="background-color: #f3f2f1; border-bottom: 2px solid #0078d4;">
<th style="padding: 15px; text-align: left;">Scenario</th>
<th style="padding: 15px; text-align: left;">Best Practice</th>
</tr>
</thead>
<tbody>
<tr style="border-bottom: 1px solid #eee;">
<td style="padding: 15px;"><strong>Large Data Sets</strong></td>
<td style="padding: 15px;">Use <code>-All</code> and <code>-Filter</code>. Avoid <code>Where-Object</code>.</td>
</tr>
<tr style="border-bottom: 1px solid #eee;">
<td style="padding: 15px;"><strong>Security</strong></td>
<td style="padding: 15px;">Use Certificates for Auth; use Least Privilege Scopes.</td>
</tr>
<tr style="border-bottom: 1px solid #eee;">
<td style="padding: 15px;"><strong>Speed</strong></td>
<td style="padding: 15px;">Use <code>-ExpandProperty</code> and <code>$batch</code>.</td>
</tr>
<tr style="border-bottom: 1px solid #eee;">
<td style="padding: 15px;"><strong>Troubleshooting</strong></td>
<td style="padding: 15px;">Append <code>-Debug</code> to see raw HTTP traffic.</td>
</tr>
</tbody>
</table>
<div style="background: #fff8e1; border-left: 5px solid #ffc107; padding: 20px; margin-top: 40px; border-radius: 4px;">
        <strong>Next Steps:</strong> Start by experimenting in the <a href="https://developer.microsoft.com/en-us/graph/graph-explorer" target="_blank" rel="noopener">Graph Explorer</a> to visualize the JSON responses before writing your PowerShell logic.
    </div>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://www.msb365.blog/?feed=rss2&#038;p=6118</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Strategic Implementation Concept: Microsoft Teams Walkie-Talkie for Airport Operations</title>
		<link>https://www.msb365.blog/?p=6113</link>
					<comments>https://www.msb365.blog/?p=6113#respond</comments>
		
		<dc:creator><![CDATA[drago]]></dc:creator>
		<pubDate>Tue, 06 Jan 2026 07:10:55 +0000</pubDate>
				<category><![CDATA[Microsoft 365]]></category>
		<category><![CDATA[MS Teams]]></category>
		<category><![CDATA[PowerShell]]></category>
		<guid isPermaLink="false">https://www.msb365.blog/?p=6113</guid>

					<description><![CDATA[Aviation Digital Operation Blueprint Executive Summary Modernizing airport communication is a critical safety and efficiency factor. This document outlines the transition from traditional LMR/TETRA radio systems to an integrated Microsoft Teams Walkie-Talkie solution. By merging voice communication, digital identity, and compliance archiving, we achieve seamless coverage (WLAN/5G/LTE) while reducing hardware costs and infrastructure complexity. 1. [&#8230;]]]></description>
										<content:encoded><![CDATA[<div class="av-blueprint-wrapper">
<style>
        .av-blueprint-wrapper {
            font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
            line-height: 1.6;
            color: #201f1e;
            background-color: #ffffff;
            border: 1px solid #dfe3e8;
            border-radius: 8px;
            margin: 20px 0;
            overflow: hidden;
        }
        .av-header {
            background: linear-gradient(135deg, #002244 0%, #464EB8 100%);
            color: white;
            padding: 40px 30px;
            border-bottom: 5px solid #ff6600;
            text-align: center;
        }
        .av-content { padding: 30px; }
        .av-header h1 { color: #ffffff !important; margin: 0; font-size: 2.2em; }
        .av-header p { font-size: 1.1em; opacity: 0.9; margin-top: 10px; }</p>
<p>        .av-section-title {
            color: #002244;
            border-left: 5px solid #ff6600;
            padding-left: 15px;
            margin: 40px 0 20px 0;
            text-transform: uppercase;
            font-size: 1.5em;
            font-weight: bold;
        }</p>
<p>        .av-summary {
            background: #f0f4f8;
            border: 1px solid #d1d1d1;
            padding: 25px;
            border-radius: 8px;
            margin-bottom: 30px;
        }</p>
<p>        .av-card-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
            gap: 20px;
            margin: 25px 0;
        }
        .av-card {
            background: #fff;
            border: 1px solid #dfe3e8;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 5px rgba(0,0,0,0.05);
        }</p>
<p>        .av-code-block {
            background: #1e1e1e;
            color: #dcdcdc;
            padding: 20px;
            border-radius: 6px;
            overflow-x: auto;
            font-family: 'Cascadia Code', Consolas, monospace;
            font-size: 14px;
            line-height: 1.4;
            margin: 20px 0;
            border-left: 4px solid #464EB8;
        }
        .av-kw { color: #569cd6; }
        .av-str { color: #ce9178; }
        .av-cmt { color: #6a9955; font-style: italic; }</p>
<p>        .av-alert-box {
            padding: 20px;
            border-radius: 6px;
            margin: 20px 0;
        }
        .av-security { background: #fff4f4; border: 1px solid #a80000; color: #a80000; }
        .av-compliance { background: #f6fff6; border: 1px solid #107c10; color: #107c10; }</p>
<p>        .av-table {
            width: 100%;
            border-collapse: collapse;
            margin: 20px 0;
        }
        .av-table th, .av-table td {
            padding: 12px;
            border: 1px solid #dfe3e8;
            text-align: left;
        }
        .av-table th { background: #f8f9fa; color: #002244; }</p>
<p>        .av-footer {
            background: #1a1a1a;
            color: #999;
            text-align: center;
            padding: 30px;
            font-size: 0.8em;
        }
    </style>
<header class="av-header">
<h1>Aviation Digital Operation Blueprint</h1>
</header>
<div class="av-content">
<section class="av-summary">
<h2 style="margin-top:0;">Executive Summary</h2>
<p>Modernizing airport communication is a critical safety and efficiency factor. This document outlines the transition from traditional LMR/TETRA radio systems to an integrated Microsoft Teams Walkie-Talkie solution. By merging voice communication, digital identity, and compliance archiving, we achieve seamless coverage (WLAN/5G/LTE) while reducing hardware costs and infrastructure complexity.</p>
</section>
<h2 class="av-section-title">1. Operational Use Cases (Deep Dive)</h2>
<div class="av-card-grid">
<div class="av-card">
<h3 style="color:#464EB8;">Airport Security</h3>
<p>Instant PTT group communication for terminal incidents. Integration of location data for rapid responder positioning. Military-grade encryption for sensitive security channels.</p>
</p></div>
<div class="av-card">
<h3 style="color:#464EB8;">Baggage Handling</h3>
<p>Direct coordination between check-in and loading bays. Use of high-performance noise-canceling headsets to ensure clear communication despite heavy machinery noise.</p>
</p></div>
<div class="av-card">
<h3 style="color:#464EB8;">Airside & Ground Ops</h3>
<p>Marshaling instructions and FOD (Foreign Object Debris) checks on the apron. Utilization of ruggedized devices (e.g., Samsung XCover) built for extreme weather.</p>
</p></div>
</p></div>
<h2 class="av-section-title">2. PowerShell Configuration (Admin Guide)</h2>
<p>Automated deployment via PowerShell ensures that all frontline workers have the Walkie-Talkie app pinned to their mobile navigation bar.</p>
<div class="av-code-block">
            <span class="av-cmt"># Connect to Microsoft Teams</span><br />
            <span class="av-kw">Connect-MicrosoftTeams</span></p>
<p>            <span class="av-cmt"># Define Policy Parameters</span><br />
            $policyName = <span class="av-str">“Aviation_Frontline_WT”</span><br />
            $appId = <span class="av-str">“0048126e-44b2-4404-8740-1f951e707a0c”</span></p>
<p>            <span class="av-cmt"># Create Policy and Pin App</span><br />
            <span class="av-kw">New-CsTeamsAppSetupPolicy</span> -Identity $policyName -Description <span class="av-str">“Airport Ops PTT Policy”</span><br />
            <span class="av-kw">Set-CsTeamsAppSetupPolicy</span> -Identity $policyName -PinnedApps @{Add=$appId}</p>
<p>            <span class="av-cmt"># Batch Assignment to Entra ID Group</span><br />
            $groupId = <span class="av-str">“YOUR-GROUP-ID-HERE”</span><br />
            <span class="av-kw">New-CsGroupPolicyAssignment</span> -GroupId $groupId -PolicyType TeamsAppSetupPolicy -PolicyName $policyName -Rank 1
        </div>
<h2 class="av-section-title">3. Security: Conditional Access & Geofencing</h2>
<div class="av-alert-box av-security">
<h3>Geographical Access Control</h3>
<p>To ensure security, Walkie-Talkie access is restricted to the airport perimeter. Communication is blocked once a user leaves the trusted network zone.</p>
<div class="av-code-block">
                <span class="av-cmt"># Define Trusted Airport Location (IP-Range)</span><br />
                <span class="av-kw">New-MgNamedLocation</span> -DisplayName <span class="av-str">“Airport-Fence-Zone”</span> `<br />
                    -IsTrusted $true `<br />
                    -OdataType <span class="av-str">“#microsoft.graph.ipNamedLocation”</span> `<br />
                    -IpRanges @{ <span class="av-str">“cidrAddress”</span> = <span class="av-str">“192.168.1.0/24”</span> }
            </div>
</p></div>
<h2 class="av-section-title">4. Compliance & Recording</h2>
<div class="av-alert-box av-compliance">
<h3>Audit-Ready Communication</h3>
<p>Legal requirements (e.g., ICAO/FAA) often mandate the archiving of operational radio traffic. Teams uses the Compliance Recording Framework for this purpose.</p>
<div class="av-code-block">
                <span class="av-cmt"># Create Compliance Recording Policy</span><br />
                <span class="av-kw">New-CsTeamsComplianceRecordingPolicy</span> -Identity <span class="av-str">“Airport_Safety_Archive”</span> `<br />
                    -Enabled $true -Description <span class="av-str">“Audit-Log for Runway Ops”</span></p>
<p>                <span class="av-cmt"># Assign to Safety Personnel</span><br />
                <span class="av-kw">Grant-CsTeamsComplianceRecordingPolicy</span> -Identity <span class="av-str">“ops-team@airport.com”</span> `<br />
                    -PolicyName <span class="av-str">“Airport_Safety_Archive”</span>
            </div>
</p></div>
<h2 class="av-section-title">5. Hardware Integration & Button Mapping</h2>
<table class="av-table">
<thead>
<tr>
<th>Device Type</th>
<th>Configuration Tool</th>
<th>Intent Action</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Zebra TC-Series</strong></td>
<td>StageNow / KeyMappingMgr</td>
<td><code>com.microsoft.office.outlook.ptt.PUSH_TO_TALK</code></td>
</tr>
<tr>
<td><strong>Samsung XCover</strong></td>
<td>Knox / Android Settings</td>
<td>Direct App Link: Teams Walkie-Talkie</td>
</tr>
<tr>
<td><strong>Jabra Headsets</strong></td>
<td>BlueParrott App/SDK</td>
<td>Trigger via BLE (Bluetooth Low Energy)</td>
</tr>
</tbody>
</table>
<h2 class="av-section-title">6. Implementation Roadmap</h2>
<div class="av-card">
<p><strong>Phase 1: Pilot (Weeks 1-2):</strong> Testing in Terminal 1 with Security Key Users. Focus on Wi-Fi roaming stability.</p>
<p><strong>Phase 2: Transition (Weeks 3-6):</strong> Expansion to Ground Handling. Parallel operation with legacy radio for risk mitigation.</p>
<p><strong>Phase 3: Full Go-Live:</strong> Complete decommissioning of analog frequencies and activation of all recording bots.</p>
</p></div>
<h2 class="av-section-title">7. Training & Radio Etiquette</h2>
<div class="av-summary">
<ul>
<li><strong>Discipline:</strong> Keep messages short. Wait for the “Beep” before speaking.</li>
<li><strong>Hardware:</strong> Use the physical side-button (no need to unlock the screen).</li>
<li><strong>Channels:</strong> Ensure you are connected to the correct operational channel (e.g., ‘Ramp-Ops’).</li>
</ul></div>
</p></div>
<footer class="av-footer">
</footer>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://www.msb365.blog/?feed=rss2&#038;p=6113</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Mastering Exchange Online Security: Automating Send-As &#038; Impersonation Audits</title>
		<link>https://www.msb365.blog/?p=6106</link>
					<comments>https://www.msb365.blog/?p=6106#respond</comments>
		
		<dc:creator><![CDATA[drago]]></dc:creator>
		<pubDate>Wed, 24 Dec 2025 09:17:08 +0000</pubDate>
				<category><![CDATA[Microsoft 365]]></category>
		<category><![CDATA[MS Exchange]]></category>
		<category><![CDATA[PowerShell]]></category>
		<guid isPermaLink="false">https://www.msb365.blog/?p=6106</guid>

					<description><![CDATA[PowerShell • Exchange Online • Security • Auditing As Exchange Online administrators, visibility is our most valuable asset. One of the most common security “blind spots” in growing organizations involves mailbox delegation. Specifically: Who has the right to send emails as someone else? While the Microsoft 365 Admin Center allows you to check permissions one [&#8230;]]]></description>
										<content:encoded><![CDATA[<style>
    /* Scoped CSS for WordPress - Prevents conflicts with theme styles */
    .exchange-audit-post {
        --primary-color: #0078d4;
        --secondary-color: #2b2b2b;
        --accent-color: #00c7b7;
        --bg-color: #f8f9fa;
        --text-color: #333;
        --code-bg: #1e1e1e;
        --code-text: #d4d4d4;</p>
<p>        font-family: 'Segoe UI', Inter, -apple-system, BlinkMacSystemFont, sans-serif;
        line-height: 1.7;
        color: var(--text-color);
        background-color: var(--bg-color); /* Creates the grey background area */
        padding: 20px;
        border-radius: 8px;
    }</p>
<p>    /* Reset basic elements only within our container */
    .exchange-audit-post * {
        box-sizing: border-box;
    }</p>
<p>    /* Container for the Blog Post Content */
    .exchange-audit-post .blog-container {
        max-width: 900px;
        margin: 0 auto; /* Centered */
        background: white;
        padding: 40px;
        border-radius: 12px;
        box-shadow: 0 10px 30px rgba(0,0,0,0.05);
    }</p>
<p>    /* Headings */
    .exchange-audit-post h1 {
        font-size: 2.5rem;
        color: var(--secondary-color);
        margin-bottom: 10px;
        margin-top: 0;
        letter-spacing: -0.5px;
        line-height: 1.2;
    }</p>
<p>    .exchange-audit-post h2 {
        font-size: 1.8rem;
        color: var(--primary-color);
        margin-top: 40px;
        border-bottom: 2px solid #eee;
        padding-bottom: 10px;
        line-height: 1.3;
    }</p>
<p>    .exchange-audit-post h3 {
        font-size: 1.3rem;
        color: var(--secondary-color);
        margin-top: 30px;
        font-weight: 600;
    }</p>
<p>    /* Text Elements */
    .exchange-audit-post p {
        margin-bottom: 20px;
        font-size: 1.1rem;
    }</p>
<p>    .exchange-audit-post ul {
        margin-bottom: 20px;
        padding-left: 20px;
    }</p>
<p>    .exchange-audit-post li {
        margin-bottom: 10px;
    }</p>
<p>    /* Code Blocks */
    .exchange-audit-post pre {
        background-color: var(--code-bg);
        color: var(--code-text);
        padding: 20px;
        border-radius: 8px;
        overflow-x: auto;
        font-family: 'Consolas', 'Monaco', monospace;
        font-size: 0.9rem;
        border-left: 5px solid var(--accent-color);
        margin: 20px 0;
    }</p>
<p>    .exchange-audit-post code {
        font-family: 'Consolas', 'Monaco', monospace;
    }</p>
<p>    .exchange-audit-post p code {
        background-color: #eef1f5;
        padding: 2px 6px;
        border-radius: 4px;
        color: #c7254e;
        font-size: 0.95em;
    }</p>
<p>    /* Key Highlights Box */
    .exchange-audit-post .highlight-box {
        background-color: #e1f0fa;
        border-left: 5px solid var(--primary-color);
        padding: 20px;
        margin: 30px 0;
        border-radius: 4px;
    }</p>
<p>    /* Button / Links */
    .exchange-audit-post .download-btn {
        display: inline-block;
        background-color: var(--primary-color);
        color: white;
        padding: 12px 25px;
        text-decoration: none;
        border-radius: 50px;
        font-weight: bold;
        transition: background 0.3s ease;
        margin-top: 20px;
    }</p>
<p>    .exchange-audit-post .download-btn:hover {
        background-color: #005a9e;
    }</p>
<p>    .exchange-audit-post .meta-tags {
        font-size: 0.9rem;
        color: #777;
        margin-bottom: 30px;
        text-transform: uppercase;
        letter-spacing: 1px;
        font-weight: 600;
    }</p>
<p>    /* Responsive tweaks */
    @media (max-width: 768px) {
        .exchange-audit-post .blog-container {
            padding: 20px;
        }
        .exchange-audit-post h1 {
            font-size: 2rem;
        }
    }</p>
</style>
<p><!-- Wrapper for WP isolation --></p>
<div class="exchange-audit-post">
<article class="blog-container">
<div class="meta-tags">PowerShell • Exchange Online • Security • Auditing</div>
<p>As Exchange Online administrators, visibility is our most valuable asset. One of the most common security “blind spots” in growing organizations involves mailbox delegation. Specifically: <strong>Who has the right to send emails as someone else?</strong></p>
<p>While the Microsoft 365 Admin Center allows you to check permissions one mailbox at a time, auditing an entire tenant for <em>Send As</em> permissions and global <em>ApplicationImpersonation</em> roles can be a nightmare. Today, I’m sharing a PowerShell solution that automates this process and generates a beautiful, searchable HTML report.</p>
<div class="highlight-box">
            <strong>Why is this important?</strong><br />
            “Send As” allows a user (or hacker) to send an email that appears to come <em>directly</em> from the mailbox owner, with no “on behalf of” tag. “ApplicationImpersonation” is even more powerful, allowing applications to act as the user completely.
        </div>
<h2>The Solution: A Custom PowerShell Auditor</h2>
<p>I wrote a PowerShell script that bridges the gap between raw data and actionable insights. Instead of staring at a CSV file, this script generates a modern, interactive HTML dashboard.</p>
<h3>Key Features</h3>
<ul>
<li><strong>Full Tenant Scan:</strong> Iterates through all User and Shared Mailboxes.</li>
<li><strong>Send-As Detection:</strong> Identifies explicit AD permissions (Active Directory Rights).</li>
<li><strong>Impersonation Checks:</strong> Scans RBAC (Role Based Access Control) for the high-privilege <code>ApplicationImpersonation</code> role.</li>
<li><strong>Visual Reporting:</strong> Produces a user-friendly HTML file with directional arrows indicating flow (Who → Can Access → Whom).</li>
<li><strong>Searchable:</strong> Includes an embedded JavaScript search engine to filter results instantly.</li>
</ul>
<h2>How It Works</h2>
<p>The script operates in three distinct phases:</p>
<h3>1. Data Collection (Send As)</h3>
<p>First, it connects to Exchange Online. It then loops through every mailbox using <code>Get-Mailbox</code>. For each mailbox, it runs <code>Get-RecipientPermission</code> to find any security identifier (SID) that has “SendAs” rights, filtering out the owner themselves (Self).</p>
<h3>2. RBAC Analysis (Impersonation)</h3>
<p>Unlike standard folder permissions, <em>ApplicationImpersonation</em> is an administrative role. The script uses <code>Get-ManagementRoleAssignment</code> to find service accounts or users who have been granted this role, and importantly, checks the <strong>Scope</strong> (whether it applies to the whole organization or just specific users).</p>
<h3>3. Report Generation</h3>
<p>Finally, it constructs an HTML file. It embeds CSS for styling and a small JavaScript snippet to handle the search bar logic, ensuring the report is a single, portable file you can share with auditors or management.</p>
<h2>The Script</h2>
<p>Here is the complete PowerShell code. Save this as <code>Audit-ExchangePermissions.ps1</code> and run it in a PowerShell terminal with Exchange Online Administrator rights.</p>
<pre><code><#
.SYNOPSIS
    Generates an HTML Report for "Send As" and "ApplicationImpersonation" permissions.
.DESCRIPTION
    Scans all User and Shared mailboxes for 'SendAs' rights.
    Checks RBAC assignments for 'ApplicationImpersonation'.
    Outputs a searchable HTML file.
#>

# --- Configuration ---
$ReportPath = "$env:USERPROFILE\Desktop\Exchange_SendAs_Impersonation_Report.html"
$LogoUrl = "https://img.icons8.com/color/48/000000/microsoft-exchange.png"

# --- Connection Check ---
try {
    Get-Mailbox -ResultSize 1 -ErrorAction Stop -WarningAction SilentlyContinue | Out-Null
    Write-Host "Connection to Exchange Online verified." -ForegroundColor Green
}
catch {
    Write-Host "Connecting to Exchange Online..." -ForegroundColor Yellow
    try {
        Connect-ExchangeOnline -ErrorAction Stop
    }
    catch {
        Write-Error "Could not connect. Please check internet and permissions."
        exit
    }
}

# --- Data Collection ---
$ReportData = @()

# 1. Mailbox SendAs Checks
Write-Host "Scanning Mailboxes for 'Send As' rights..." -ForegroundColor Cyan
$Mailboxes = Get-Mailbox -ResultSize Unlimited -RecipientTypeDetails UserMailbox,SharedMailbox

$Counter = 0
$Total = $Mailboxes.Count

foreach ($Mailbox in $Mailboxes) {
    $Counter++
    Write-Progress -Activity "Auditing Permissions" -Status "Processing: $($Mailbox.DisplayName)" -PercentComplete (($Counter / $Total) * 100)
    
    # Filter 'SendAs' rights, excluding the user themselves (Self)
    $Permissions = Get-RecipientPermission -Identity $Mailbox.Id -ResultSize Unlimited -Trustee $null | Where-Object { 
        ($_.AccessRights -like "*SendAs*") -and 
        ($_.Trustee -ne "NT AUTHORITY\SELF") -and 
        ($_.Trustee -ne $Mailbox.UserPrincipalName)
    }

    foreach ($Perm in $Permissions) {
        $ReportData += [PSCustomObject]@{
            OwnerName    = $Mailbox.DisplayName
            OwnerUPN     = $Mailbox.UserPrincipalName
            Type         = if ($Mailbox.RecipientTypeDetails -eq "UserMailbox") { "User Mailbox" } else { "Shared Mailbox" }
            Direction    = "Sent By"
            Actor        = $Perm.Trustee
            AccessRights = "Send As"
        }
    }
}

# 2. ApplicationImpersonation Checks (RBAC)
Write-Host "Checking for 'ApplicationImpersonation' roles..." -ForegroundColor Cyan
$ImpersonationRoles = Get-ManagementRoleAssignment -Role "ApplicationImpersonation" -ResultSize Unlimited -ErrorAction SilentlyContinue

foreach ($RoleAssignment in $ImpersonationRoles) {
    $ScopeName = "Entire Organization"
    if ($RoleAssignment.CustomRecipientWriteScope) {
        $ScopeName = "Scope: " + $RoleAssignment.CustomRecipientWriteScope
    } elseif ($RoleAssignment.RecipientReadScope -ne "Organization") {
        $ScopeName = "Scope: " + $RoleAssignment.RecipientReadScope
    }

    $ReportData += [PSCustomObject]@{
        OwnerName    = $ScopeName
        OwnerUPN     = "RBAC Scope"
        Type         = "App Impersonation" 
        Direction    = "Impersonated By"
        Actor        = $RoleAssignment.RoleAssigneeName
        AccessRights = "ApplicationImpersonation"
    }
}

Write-Progress -Activity "Auditing Permissions" -Completed

# --- HTML Generation ---
Write-Host "Generating HTML Report..." -ForegroundColor Cyan

$CSS = @"
<style>
    body { font-family: 'Segoe UI', sans-serif; background-color: #f4f4f9; color: #333; padding: 20px; }
    .container { max-width: 1200px; margin: 0 auto; background: white; padding: 30px; border-radius: 8px; box-shadow: 0 0 15px rgba(0,0,0,0.1); }
    h1 { color: #0078d4; border-bottom: 2px solid #0078d4; padding-bottom: 10px; display: flex; align-items: center; }
    .info-box { background-color: #e1f0fa; border-left: 5px solid #0078d4; padding: 15px; margin-bottom: 20px; }
    #searchInput { width: 100%; padding: 12px; margin: 8px 0; border: 1px solid #ccc; border-radius: 4px; background-color: #f8f8f8; }
    table { width: 100%; border-collapse: collapse; margin-top: 10px; font-size: 14px; }
    th { background-color: #0078d4; color: white; text-align: left; padding: 12px 15px; }
    td { padding: 12px 15px; border-bottom: 1px solid #ddd; }
    tr:nth-child(even) { background-color: #f9f9f9; }
    .badge { padding: 4px 8px; border-radius: 12px; font-size: 12px; font-weight: bold; color: white; }
    .badge-shared { background-color: #ffc107; color: #333; }
    .badge-user { background-color: #17a2b8; }
    .badge-imper { background-color: #6f42c1; }
    .arrow { color: #d9534f; font-weight: bold; }
    .footer { margin-top: 30px; font-size: 12px; color: #777; text-align: center; }
</style>
"@

$ScriptJS = @"
<script>
    function searchTable() {
        var input = document.getElementById("searchInput");
        var filter = input.value.toUpperCase();
        var table = document.getElementById("permissionTable");
        var tr = table.getElementsByTagName("tr");
        for (var i = 1; i < tr.length; i++) {
            var td = tr[i].getElementsByTagName("td");
            var found = false;
            for (var j = 0; j < td.length; j++) {
                if (td[j] && (td[j].textContent || td[j].innerText).toUpperCase().indexOf(filter) > -1) {
                    found = true; break;
                }
            }
            tr[i].style.display = found ? "" : "none";
        }
    }
</script>
"@

$HTMLHeader = @"
<!DOCTYPE html>
<html>
<head><title>Exchange Permissions Report</title>$CSS $ScriptJS</head>
<body>
    <div class="container">
        <h1><img src="$LogoUrl" width="40" style="margin-right:15px"> Exchange Permissions Audit</h1>
        <div class="info-box">
            <strong>Audit Summary:</strong><br>
            Found $($ReportData.Count) permission entries.
        </div>
        <input type="text" id="searchInput" onkeyup="searchTable()" placeholder="Search users, emails, or permissions...">
        <table id="permissionTable">
            <thead>
                <tr>
                    <th>Type</th><th>Target (Owner/Scope)</th><th>Access</th><th>Actor (Delegate)</th>
                </tr>
            </thead>
            <tbody>
"@

$HTMLRows = ""
foreach ($Row in $ReportData) {
    $BadgeClass = switch ($Row.Type) {
        "Shared Mailbox" { "badge-shared" }
        "App Impersonation" { "badge-imper" }
        Default { "badge-user" }
    }
    
    $HTMLRows += @"
                <tr>
                    <td><span class="badge $BadgeClass">$($Row.Type)</span></td>
                    <td><strong>$($Row.OwnerName)</strong><br><span style="font-size:11px; color:#666;">$($Row.OwnerUPN)</span></td>
                    <td style="text-align:center;"><span class="arrow">← $($Row.AccessRights) ←</span></td>
                    <td><strong>$($Row.Actor)</strong></td>
                </tr>
"@
}

$HTMLFooter = @"
            </tbody>
        </table>
        <div class="footer">Generated on $(Get-Date -Format "yyyy-MM-dd")</div>
    </div>
</body>
</html>
"@

$FinalHTML = $HTMLHeader + $HTMLRows + $HTMLFooter
$FinalHTML | Out-File -FilePath $ReportPath -Encoding UTF8
Invoke-Item $ReportPath
</code></pre>
<h2>Conclusion</h2>
<p>Regular auditing of Exchange permissions is critical for maintaining a “Zero Trust” environment. By automating the discovery of <em>Send As</em> and <em>Impersonation</em> rights, you ensure that no unauthorized account holds keys to your organization’s communication channels.</p>
<p>Feel free to customize the script to add more checks (like “Full Access” permissions) or change the branding to match your company colors!</p>
</article>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://www.msb365.blog/?feed=rss2&#038;p=6106</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Setting Up Calendar Sharing Between Microsoft 365 Tenants</title>
		<link>https://www.msb365.blog/?p=6098</link>
					<comments>https://www.msb365.blog/?p=6098#respond</comments>
		
		<dc:creator><![CDATA[drago]]></dc:creator>
		<pubDate>Thu, 04 Dec 2025 13:08:42 +0000</pubDate>
				<category><![CDATA[MS Exchange]]></category>
		<category><![CDATA[PowerShell]]></category>
		<guid isPermaLink="false">https://www.msb365.blog/?p=6098</guid>

					<description><![CDATA[Introduction In today’s interconnected business world, collaboration across organizations is essential. Microsoft 365 offers robust tools for cross-tenant calendar sharing, allowing users from different tenants to view availability (free/busy) or even full calendar entries. This guide walks you through the setup process, drawing from official Microsoft documentation and practical examples. We’ll cover free/busy sharing via [&#8230;]]]></description>
										<content:encoded><![CDATA[<style>
    /* Container Styling um Konflikte mit dem Theme zu vermeiden */<br />
    .custom-blog-post {<br />
        font-family: Arial, sans-serif;<br />
        line-height: 1.6;<br />
        margin: 20px auto; /* Zentriert den Inhalt */<br />
        max-width: 800px;<br />
        color: #333;<br />
    }</p>
<p>    /* Überschriften innerhalb des Posts */<br />
    .custom-blog-post h1,<br />
    .custom-blog-post h2,<br />
    .custom-blog-post h3 {<br />
        color: #333;<br />
        margin-top: 1.5em;<br />
        margin-bottom: 0.5em;<br />
    }</p>
<p>    /* Code Schnipsel */<br />
    .custom-blog-post code {<br />
        background: #f4f4f4;<br />
        padding: 2px 4px;<br />
        border-radius: 4px;<br />
        font-family: monospace;<br />
        color: #d63384; /* Klassische Code-Farbe */<br />
    }</p>
<p>    /* Code Blöcke */<br />
    .custom-blog-post pre {<br />
        background: #f4f4f4;<br />
        padding: 15px;<br />
        border-left: 5px solid #ccc;<br />
        overflow-x: auto;<br />
        margin-bottom: 20px;<br />
    }</p>
<p>    .custom-blog-post pre code {<br />
        background: transparent;<br />
        padding: 0;<br />
        color: #333;<br />
    }</p>
<p>    /* Listen */<br />
    .custom-blog-post ul,<br />
    .custom-blog-post ol {<br />
        margin-left: 20px;<br />
        margin-bottom: 20px;<br />
    }</p>
<p>    .custom-blog-post ul {<br />
        list-style-type: disc;<br />
    }</p>
<p>    /* Absätze */<br />
    .custom-blog-post .blog-section {<br />
        margin-bottom: 20px;<br />
    }</p>
<p>    .custom-blog-post strong {<br />
        font-weight: bold;<br />
    }<br />
</style>
<div class="custom-blog-post">
<h2>Introduction</h2>
<p class="blog-section">In today’s interconnected business world, collaboration across organizations is essential. Microsoft 365 offers robust tools for cross-tenant calendar sharing, allowing users from different tenants to view availability (free/busy) or even full calendar entries. This guide walks you through the setup process, drawing from official Microsoft documentation and practical examples. We’ll cover free/busy sharing via organization relationships and full calendar access, which requires enabling external sharing and per-user configurations.</p>
<h2>Possible Scenarios for Cross-Tenant Calendar Sharing</h2>
<p class="blog-section">Cross-tenant sharing is useful in various contexts. Here are some common scenarios:</p>
<ul>
<li><strong>Business Partnerships:</strong> Two companies collaborating on a project need to schedule meetings without conflicts. Free/busy sharing ensures visibility into availability, while full sharing allows detailed event insights for closer coordination.</li>
<li><strong>Mergers and Acquisitions:</strong> During integration, teams from acquired and parent companies can share calendars to align on timelines, reducing miscommunication.</li>
<li><strong>Supply Chain Management:</strong> Vendors and clients can view each other’s schedules for deliveries or reviews, enhancing efficiency.</li>
<li><strong>Hybrid Work Environments:</strong> Freelancers or consultants from external tenants can integrate calendars for seamless booking.</li>
<li><strong>Multi-Tenant Organizations (MTO):</strong> In advanced setups like MTO, sharing extends to groups, but starts with basic free/busy for all users.</li>
<li><strong>Challenges in Regulated Industries:</strong> Sectors like finance or healthcare may limit to free/busy only for compliance, avoiding full entry details.</li>
</ul>
<p class="blog-section">Note: Full sharing beyond free/busy isn’t automated tenant-wide; it’s user-initiated. For large-scale needs, consider automation scripts or policies.</p>
<h2>Prerequisites</h2>
<ul class="blog-section">
<li>Global or Exchange Admin permissions in both tenants.</li>
<li>Access to Microsoft 365 Admin Center and Exchange Admin Center.</li>
<li>Exchange Online PowerShell module for advanced setups.</li>
<li>Domain names of both tenants (e.g., contoso.com and fabrikam.com).</li>
<li>Changes may take up to 24 hours to propagate.</li>
</ul>
<h2>Step-by-Step Setup</h2>
<h3>Step 1: Enable External Calendar Sharing (Required for Full Access)</h3>
<p class="blog-section">This allows users to share calendars externally.</p>
<ol>
<li>Log into the Microsoft 365 Admin Center (admin.microsoft.com).</li>
<li>Go to <strong>Settings > Org settings > Services > Calendar</strong>.</li>
<li>Enable <strong>Let your users share their calendars with people outside of your organization who have Office 365 or Exchange</strong>.</li>
<li>Select access levels (e.g., full details).</li>
<li>Save and repeat in the other tenant.</li>
</ol>
<h3>Step 2: Set Up Organization Relationship (for Free/Busy Sharing)</h3>
<p class="blog-section">This enables tenant-wide visibility of availability. Perform in both tenants for bidirectional access.</p>
<h4>Using Exchange Admin Center</h4>
<ol>
<li>Log into Exchange Admin Center (admin.exchange.microsoft.com).</li>
<li>Navigate to <strong>Organization > Sharing > Organization sharing tab</strong>.</li>
<li>Click <strong>+ Add organization relationship</strong>.</li>
<li>Enter a name (e.g., “Contoso-Fabrikam”).</li>
<li>Add the other tenant’s domain.</li>
<li>Enable <strong>Calendar free/busy information sharing</strong>.</li>
<li>Choose level: Time only or Time, subject, location.</li>
<li>Select scope: Everyone or a security group.</li>
<li>Create and repeat in the other tenant.</li>
</ol>
<h4>Using PowerShell</h4>
<ol>
<li>Connect:
<pre><code>Connect-ExchangeOnline -UserPrincipalName admin@contoso.com</code></pre>
</li>
<li>Create:
<pre><code>New-OrganizationRelationship -Name "Contoso-Fabrikam" -DomainNames "fabrikam.com" -FreeBusyAccessEnabled $true -FreeBusyAccessLevel LimitedDetails</code></pre>
</li>
<li>Verify:
<pre><code>Get-OrganizationRelationship | Format-List</code></pre>
</li>
</ol>
<h3>Step 3: Perform Full Calendar Sharing (Per-User)</h3>
<p class="blog-section">Once external sharing is enabled:</p>
<ol>
<li>In Outlook, right-click your calendar and select <strong>Share > Permissions</strong>.</li>
<li>Add the external user’s email.</li>
<li>Set permissions (e.g., Can view all details).</li>
<li>Send invitation; recipient accepts in Outlook.</li>
<li>To view: Add the shared calendar via link or invitation.</li>
</ol>
<h2>Verification and Troubleshooting</h2>
<p class="blog-section">Test by inviting cross-tenant users to meetings. If issues arise, check domains, wait for propagation, or use PowerShell diagnostics. For advanced scenarios like MTO, refer to Microsoft docs.</p>
<h2>Conclusion</h2>
<p class="blog-section">Cross-tenant calendar sharing boosts productivity but requires careful setup for security. Start with free/busy for broad access, then enable full sharing as needed. Stay updated with Microsoft changes!</p>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://www.msb365.blog/?feed=rss2&#038;p=6098</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
