Mail Security Is Easier to Understand When You Can See It

image

One of the recurring problems with Microsoft 365 mail security is that too many people treat it like a checklist. SPF. DKIM. DMARC. Spoof intelligence. Anti-phishing. Safe Links. Quarantine. Transport rules. Tick the boxes, move on, hope the tenant is safer than it was before.

I understand why that happens. Email security in Microsoft 365 has a lot of moving parts, and most of them are hidden until something goes wrong. A message lands in junk. A phishing email reaches a user. A legitimate invoice disappears into quarantine. Then everyone starts asking the same uncomfortable question: why did that happen?

That is why I like building simple simulation tools, like the one I just created here:

https://directorcia.github.io/Office365/m365-mail-security-sim.html

The value is not the button. It is the model.

The point of a mail security simulator is not to replace the Microsoft Defender portal. It is to help people build a clearer mental model before they start changing live settings.

When I work with SMBs and MSPs, I often see the same pattern. Someone knows one part of the stack very well, usually Exchange Online mail flow or DNS authentication, but they are less confident about how that choice affects the next decision. Enforcing DMARC sounds sensible. Tightening spoof handling sounds sensible. Adjusting user reporting sounds sensible. The problem is that sensible settings can still create poor outcomes if you do not understand how they interact.

A simulator gives you a low-risk way to explore that. Change the assumptions. Watch the likely outcome. Ask what would happen if the sender fails authentication, if the domain is aligned, if policy handling changes, or if the user has been trained to report suspicious mail through Outlook. You are not learning by breaking production. You are learning by testing the shape of the decision.

Copilot still needs clean security thinking.

This becomes even more important as Copilot becomes part of the working day. People are asking Copilot in Outlook to summarise long email threads, draft replies, and pull meaning from busy inboxes. That only works if the mailbox environment is trustworthy enough in the first place.

Copilot does not remove the need for Defender for Office 365, Exchange Online Protection, authentication alignment, or sensible quarantine handling. If anything, it raises the standard. The more value we expect people to get from their Microsoft 365 data, the more responsibility we have to make sure the signals around that data are well managed.

That is the message I want administrators and MSPs to take seriously. AI does not excuse messy security. It exposes it.

Training beats guessing.

Good security administration is not just knowing where the settings are. It is knowing what trade-offs you are making when you change them.

A tool like this can help an MSP have a better client conversation. Instead of saying, “we should improve your mail security,” you can show the client how different conditions affect message handling. Instead of turning a policy into an abstract recommendation, you can make the risk visible enough for a business owner to understand.

It also helps junior technicians. I would much rather see someone experiment with a simulation than make random changes inside the Defender portal because they found a setting that sounded important. Curiosity is good. Production tenants are a poor classroom.

Microsoft 365 security has become too important to be treated as a collection of isolated switches. Mail protection, user behaviour, reporting, policy tuning, and now Copilot readiness all sit together. If you cannot explain how the pieces connect, you are not really managing the system. You are just hoping the defaults are enough.

The next step for many organisations is not more noise, more dashboards, or more alerts. It is better understanding.

That starts by making the invisible parts of mail security visible enough to reason about.

You’ll find the simulation I just created here:

 https://directorcia.github.io/Office365/m365-mail-security-sim.html

it’s free to use but I’d always appreciate any support you can provide around this and upcoming simulation projects via – https://ko-fi.com/ciaops.

Screenshot 2026-08-03 093012

Also, feel free to provide me any feedback on the simulation so I can continue to improve it for all.

Why your DLP policy isn’t DLP (and how to fix it in Microsoft 365)

image

Most SMBs think they’ve “done DLP” because they ticked a box in Exchange.

They scan outbound email.

They block the occasional credit card number.

They call it done.

That’s not DLP. That’s transport filtering.

Real data loss doesn’t just leave through email anymore. It walks out via USB, clipboard, browser uploads, and users who don’t realise they’re doing anything wrong.

If you’re only protecting email, you’re protecting yesterday’s risk.

The shift is simple: stop thinking about where data leaves, and start thinking about where data lives and how it’s used.

What is Microsoft Purview DLP, really?

At its core, Microsoft Purview DLP is a policy engine that watches how sensitive data is used and shared, then steps in when it shouldn’t be.

Not just email. Not just files.

Behaviour.

It looks across Microsoft 365 — Exchange, SharePoint, Teams — and now endpoint devices as well.

That matters.

Exchange DLP scans emails and attachments and enforces actions.
Endpoint DLP extends this to USB copies, printing, clipboard, and uploads.

“We’ve got DLP on email, so we’re covered.”

No, you’ve just moved the problem somewhere else.

Data will always find another path out.

Step-by-Step: building a real DLP policy (Exchange + endpoint)
1. Go to the Purview portal

Navigate to Data loss prevention → Policies → Create policy.

2. Choose your locations

Select Exchange Online and Devices.

3. Define what matters

Use built-in sensitive information types and add context like external recipients.

4. Choose actions that teach

Warn, block, or allow override with justification.

5. Turn on endpoint coverage

Monitor and control how sensitive data is used directly on devices.

User copies sensitive file to USB → Block
User uploads to personal cloud → Block
User tries to email externally → Warn or encrypt

Notice what’s missing?
Separate tools.

Why this actually changes behaviour

Most security controls are reactive.

DLP — when done right — isn’t.

It works in the moment.

That’s the real win.

Instead of cleaning up incidents, you prevent them.

And you educate users while they work.

“Why did that get blocked?”

Now you’ve got a conversation instead of a breach.

My recommendation?

Start with one policy that covers Exchange and Endpoints. Run in audit mode. Then enforce.

Security doesn’t fail at the perimeter anymore. It fails in the moment of use.

DLP isn’t there to watch data leave.
It’s there to stop it leaving in the first place.

Exchange Online Protection anti-spam / anti-phish policy stacking

MAI_9531b786013aa7ed

Most people think email security in Microsoft 365 is a switch. It’s not. It’s a stack.

And the stack runs in an order you don’t get to vote on.

I see the same thing on tenant after tenant. Someone opened the anti-spam policy years ago, nudged a slider, ticked a box they’d read about on a forum, and walked away. The default phishing policy has never been touched. Connection filter? Empty. Then a dodgy invoice lands in the MD’s inbox and everyone’s surprised.

Here’s the part that catches people out. Those custom tweaks you made? They might be the reason the bad mail got through.

Stop hand-building policies. Turn on the presets and learn the order things fire in. That’s the whole job.

What is policy stacking, really?

Every inbound message runs a gauntlet. Connection filtering checks the source IP. Anti-malware scans the payload. Anti-spam scores the content. Anti-phishing checks for spoofing and impersonation. Each layer has its own policy, and each policy has a priority number.

That’s not one setting. That’s five layers, each with its own verdict, stacked on top of each other.

The catch is precedence. When two policies could apply to the same person, only one wins — the one with the highest priority. Your hand-rolled custom policy beats the preset. The preset beats the default. So if you built a loose custom anti-spam policy back in 2021 and switched on the Standard preset last week, the custom one still wins. The preset you thought protected everyone is being skipped for those users.

Microsoft lays out the full order of precedence — read it once and it’ll save you a dozen support tickets.

Step-by-Step: turn on the stack

You do all of this in the Microsoft Defender portal. No PowerShell. No Exchange admin center.

Open the presets

Go to security.microsoft.comEmail & collaborationPolicies & rulesThreat policiesPreset Security Policies.

Turn on Standard for everyone

Flip Standard protection to On and apply it to All recipients. That covers anti-spam, anti-malware, anti-phishing — and, if you’re licensed for Defender, Safe Links and Safe Attachments — all on Microsoft’s recommended settings, all maintained for you.

Turn on Strict for the people who get targeted

Flip Strict protection on and scope it to the MD, finance, payroll, and anyone with signing authority. Strict catches more and complains more. That trade is worth it for the accounts attackers actually go after.

Add your impersonation names

In the Strict wizard, add the names and addresses of your VIPs to impersonation protection. This is the bit that stops “Hi, it’s the boss, can you buy some gift cards.”

Delete the cruft

Go back to your custom anti-spam and anti-phishing policies. Any old one that’s weaker than the preset is now a hole. Remove it, or you’ve armoured the front door and left a window wide open.

Notice what’s missing from that list?

Inbound mail flow:
  Connection filter → Anti-malware → Anti-spam → Anti-phishing

Standard preset  → All recipients
Strict preset    → VIPs + impersonation list

No sliders. No SCL thresholds. No ASF tick-boxes you read about once and never quite understood. The presets carry all of that, and Microsoft updates them as the threats move. You’re not tuning a spam filter any more. You’re choosing who gets the strong one.

Why this actually changes behaviour

“We’ve always had email security on.”

Sure. But “on” and “correctly ordered” are two different sentences. Most tenants I audit have layers fighting each other — a custom policy quietly overriding the preset, an exclusion nobody remembers, a default policy doing the bare minimum for half the staff.

Presets end that argument. Everyone gets a known-good baseline. Your VIPs get more. And because the settings aren’t yours to drift, the config still makes sense in two years when someone else opens it.

For an MSP, that’s gold. You deploy the same posture across every client in an afternoon, document it in one screenshot, and stop defending slider choices in a review. Consistency is a security control. Drift is the vulnerability.

If you’re still hand-tuning spam policies client by client, you’re doing unpaid work that makes them less safe.

Turn on the presets. Fix the order. Delete the rest.

That’s not a spam setting. It’s a security baseline — and it’s already in the licence you sold them.

Tuning Safe Links and Safe Attachments in Defender for Office 365 Without Breaking Your Tenant

image

If you’re running M365 Business Premium for clients, Safe Links and Safe Attachments are already doing work — whether you configured them or not. The Built-in protection preset applies to every mailbox the moment Defender for Office 365 is licensed. The question isn’t “is it on?” — it’s “is it tuned for the way your client actually receives mail?” Out of the box, it’s closer to a safety net than a security control.

Prerequisites MSPs skip

Before you touch a single policy, confirm three things. First, mail has to flow through Exchange Online Protection. Hybrid tenants with a third-party gateway in front (Mimecast, Proofpoint, anything rewriting URLs) will often cause Safe Links to skip wrapping — Microsoft explicitly warns that pre-wrapping can prevent Safe Links from processing the link at all. Second, confirm licensing: Safe Links and Safe Attachments require Defender for Office 365 Plan 1 (included in Business Premium). Plan 2 features (Safe Documents, Threat Explorer real-time detections) need separate entitlement. Third, set quarantine notifications up before you tighten policies — users need end-user spam notifications or a quarantine policy with access enabled, or your service desk gets the entire phishing queue.

Where to configure — Standard preset, not custom, 90% of the time

The Microsoft Defender portal is your canonical surface: security.microsoft.comEmail & collaborationPolicies & rulesThreat policies. From there:

  • Preset security policies for 90% of clients. Enable Standard, assign to all recipients by domain.

  • Safe Links and Safe Attachments tiles are for custom policies — only use them when a specific user group needs different behaviour (execs on Strict, a lab OU excluded, etc.).

  • Configuration analyzer — this is the tile most MSPs never click. It diffs your current policies against Standard and Strict baselines and flags every setting that’s weaker than Microsoft’s recommendation.

Microsoft’s own guidance is explicit: prefer presets over custom policies. See Set up Safe Links policies and Set up Safe Attachments policies.

The rollout pattern that actually works

Don’t flip Strict on Monday morning. Use a three-ring rollout:

  1. Ring 1 — IT and security-aware staff (week 1). Assign Standard preset. Watch quarantine, false-positive submissions, and user complaints. This ring tolerates noise.

  2. Ring 2 — a tolerant business unit (week 2–3). Finance is usually a bad pilot (high-volume invoices with wrapped URLs confuse people). Pick sales ops, marketing, or IT-adjacent teams.

  3. Ring 3 — everyone else (week 4+). By now you have a real signal on which domains need Tenant Allow/Block entries.

For Strict preset, add a fourth ring limited to exec and finance groups — or leave it off. Strict’s aggressive bulk thresholds (BCL 4) will blow up newsletters and marketing workflows. Details at Preset security policies.

Top three pitfalls

1. Custom policies silently overriding presets. Preset security policies have the highest priority except when a custom policy explicitly targets the same user. If you inherited a tenant with a custom Safe Links policy from 2019 that says AllowClickThrough = true, it beats your shiny new Standard preset. Audit first: open every existing policy before assigning presets.

2. Over-allowlisting domains. Every entry in “Do not rewrite the following URLs” is a permanent click-through exception. Treat it like firewall rules — justify, document, review annually. A forgotten *.sharepointdomain.com wildcard is how payloads land.

3. Ignoring the Configuration analyzer. Run it quarterly. Tenants drift: an admin raises a threshold to silence a complaint, nobody reverses it, six months later the baseline is gone. The Configuration analyzer surfaces this in one screen.

Tune deliberately, measure through Threat Explorer, and treat preset policies as your default — the time to build a custom policy is when you can describe exactly which preset setting it’s overriding and why.

A Cleaner Way to Connect PowerShell to Exchange Online

image

If you still rely on Connect-ExchangeOnline with a username, password, and an MFA prompt, you already know the pain. Scripts break overnight. Scheduled tasks fail when a token expires. Service accounts get flagged by conditional access. And the moment someone enables MFA on the admin account you’ve been quietly using, your automation falls over.

I’ve been written a new script —

https://github.com/directorcia/Office365/blob/master/o365-connect-exo-cert.ps1

with full documentation here:

https://github.com/directorcia/Office365/wiki/Connect-to-Exchange-Online-with-Certificates

— that swaps all of that for certificate-based app authentication. There’s nothing exotic about the underlying approach; Microsoft has supported it for years. What’s been missing is a clean, one-shot way to set it up without spending an afternoon clicking through the Entra portal. That’s what this script gives me, and I think it earns its place in any MSP’s toolkit.

What the Script Actually Does

There are two modes, controlled by switches.

-GenerateLocalCertificate creates a self-signed RSA-2048 certificate in your current user’s certificate store, exports the public key as a .cer file, and optionally exports a password-protected .pfx. By default it’s valid for two years. That’s the local side of the handshake.

-UseCertificateAuth is the everyday mode. You tell it which tenant to connect to — or let it look up the details in a profile map file — and it signs into Exchange Online using that certificate. No password. No browser. No MFA dialog.

The clever bit is the third option: combining -GenerateLocalCertificate with -ProvisionEntraApp -Tenant 'contoso.onmicrosoft.com'. In a single run, the script will generate the local certificate, authenticate to Microsoft Graph via a device-code flow, create the Entra ID app registration if it doesn’t exist, upload the certificate, grant Exchange.ManageAsApp and Application.Read.All with admin consent, create the matching service principal, sign you into Exchange Online to add the app to the Organization Management role group, and save the tenant, app ID, and certificate thumbprint to a JSON profile file so future connections don’t need any of those parameters.

That’s a job that normally takes twenty minutes of clicking, copying GUIDs, and second-guessing whether the right role got assigned. The script does it in about ninety seconds.

Getting Started

If you’re new to certificate auth, the first run is the one that matters. Drop the script onto an admin machine, open PowerShell, and run:

.\o365-connect-exo-cert.ps1 -GenerateLocalCertificate -ProvisionEntraApp -Tenant 'yourtenant.onmicrosoft.com'

You’ll be prompted to sign in twice — once via device code for the Graph permissions (which if you use the –copydevicecodetoclipboard, option will put the required device code straight into the clipboard to paste into the request), then again with Connect-ExchangeOnline so the script can add the app to the role group. Both need a Global Admin account. After that, every future run is just:

.\o365-connect-exo-cert.ps1 -UseCertificateAuth -Tenant 'yourtenant.onmicrosoft.com'

No prompts. No browser. The script reads the tenant, app ID, and thumbprint from o365-exo-cert-auth.json (saved to parent directory), finds the certificate in your local store, builds a signed JWT, and you’re in. One caveat worth flagging: when you’ve just provisioned a brand-new app, give it fifteen to thirty minutes for role assignments to replicate before you try to connect. The script warns about this in its output, but it’s the single most common reason a fresh setup looks broken when it isn’t.

If you’re managing more than one tenant, the profile file is where this really earns its keep. Each provisioning run appends or updates an entry, so you can ask for a connection by -ProfileName, -Tenant, or -Organization and the script picks the right credentials. When several profiles match, it lists them and lets you choose.

Why Certificates Beat Passwords

The security argument is the easy one. A certificate’s private key never leaves the machine that generated it. Nothing crosses the wire that an attacker could intercept and replay. There’s no shared secret to rotate across a team, no admin password sitting in a vault that someone might extract, and no MFA bypass to engineer because the flow doesn’t involve a user account at all.

Permissions are scoped too. The app holds only Exchange.ManageAsApp and read-only access to application metadata. If the certificate is ever compromised, you remove the key credential from the app registration and the access is gone — no password reset required, no impact on any human admin account.

The script enforces TLS 1.2, refuses to assign RBAC if the EXO session has landed in the wrong tenant, warns when the certificate is within thirty days of expiry, and keeps the device-code value off the clipboard by default to avoid leaks on RDP or shared sessions. Small things, but they add up.

Why It’s a Win for Automation

Certificate auth is what makes unattended Exchange Online work actually unattended. A scheduled task running at 2 a.m. doesn’t have a human to click “Approve” on an MFA prompt. With this approach, you point Task Scheduler at the script with -noprompt, pass the tenant, and walk away.

For an MSP, that becomes a per-tenant capability rather than a per-admin one. One profile file, one shared script, separate certificates per tenant or per admin machine — and now mailbox audits, distribution group cleanup, shared mailbox provisioning, and any of the other recurring chores you keep meaning to automate can run on a timer instead of waiting for a quiet Friday afternoon. Pair it with a Power Automate flow or a daily Copilot summary in Teams, and you’ve got reporting that lands in front of the right people without anyone signing in.

Where I’d Take It Next

If you’ve never moved off interactive sign-in for Exchange Online, this is the path I’d take. Spend half an hour standing it up against a test tenant. Get comfortable with the profile file. Then start moving your scheduled work over, one job at a time. The shift from “who’s signing in?” to “which certificate is presenting itself?” is a quiet one, but once your automation stops breaking every time an admin’s MFA settings change, you won’t go back.

PowerShell script to extract Exchange Online data for your own AI analysis

A while ago I wrote a script that reads Microsoft 365 security information and exports it to a JSON data file. The idea is that you can take this data file and use it with your AI of choice. I have now developed a similar script but for Exchange Online information.

Screenshot 2026-02-01 213211

When you run the script it will connect to Exchange online and extract the information from a variety of locations

Screenshot 2026-02-01 213303

It will produce 2 output JSON files in the parent directory. The standard data file can be quite large, in the case above it is around 15MB. The other file produced is more ‘compact’ around 100 – 200KB

Screenshot 2026-02-01 213701

You can then take either of these JSON files and feed them into you AI system of choice. The above shows you the result when I fed it into Copilot Researcher.,

Screenshot 2026-02-01 214046

and I even got a nice Word document when I fed it into Claude online.

You can download the script here:

https://github.com/directorcia/Office365/blob/master/Analysis/Exchange/exo-extract.ps1

and find the documentation here:

https://github.com/directorcia/Office365/wiki/Extract-Exchange-Online-information

as well as a long prompt you can use with your Ai of choice here:

https://github.com/directorcia/Office365/blob/master/Analysis/Exchange/prompt-long.txt

Given that email systems are typically at the highest security risk, this script shoudl allow you to quickly and easily evaluate its posture as well as giving you a range of improvement suggestions.

ASD OWA settings check script

Screenshot 2025-11-13 073547

I’ve taken the Exchange Online Outlook web app policies settings recommendations from the ASD Blueprint for Secure Cloud and created an online JSON settings file here:

https://github.com/directorcia/bp/blob/main/ASD/Exchange-Online/Roles/owamail.json

I’ve then created a PowerShell script here:

https://github.com/directorcia/Office365/blob/master/asd-owamail-get.ps1

with documentation here:

https://github.com/directorcia/Office365/wiki/ASD-OWA-Mailbox-Configuration-Check

that reads the online JSON file (or uses a local version if you want to use that) and compares the recommended ASD settings to those in your own Exchange Online environment. Note, the script makes NO CHANGES to your environment, it simply reads the current settings.

It then produces the console output you see above and a HTML report like this:

Screenshot 2025-11-13 074141

You can refer to this page I also created:

https://github.com/directorcia/bp/wiki/Exchange-Online-OWA-Mailbox-Security-Controls

as to why these settings are important to the security of your M365 environment.

Look out for more scripts like this coming soon. I welcome any suggestion about improving this.

The name is already being used–Shared Mailbox troubleshooting script

Screenshot 2025-10-14 165536

I recently had to move a mailbox alias from an existing mailbox to a hared mailbox. Every time I attempted to do so I received the following error:

The name is already being used. Please try another name

The error isn’t real helpful because it doesn’t tell you exactly what the other object causing the conflict could be. To make life easier and look across the array of places the conflict could be I created the following script:

https://github.com/directorcia/Office365/blob/master/find-name-conflict.ps1

with documentation at:

https://github.com/directorcia/Office365/wiki/Find-Name-Conflict-%E2%80%90-Shared-Mailbox-Diagnostic-Tool

In my case the issue was with a ‘Name’ value in Entra ID but the script will also give your recommendations on what PowerShell commands to run to overcome any issues it detects. I ran these and I was good to!

Hopefully, this script makes it easier to find any conflicts.