Setting up Microsoft 365 Journaling for Piler#
This documentation applies to Piler enterprise edition 2.1.0
Revision #1
Publication date: 2026-FEB-09
Microsoft 365 (Exchange Online) can be configured to send a copy of every email to Piler in real-time using journal transport rules. This is the recommended method for ongoing email archiving. For one-time migration of historical emails, see Import from Microsoft 365.
Overview#
There are two ways to archive M365 emails with Piler:
| Method | Use case | How it works |
|---|---|---|
| Journaling (this guide) | Ongoing real-time archiving | M365 sends a copy of every email as it's sent/received |
| Graph API import | One-time historical migration | Script downloads existing emails via Microsoft Graph API |
You can use both: import historical emails first, then enable journaling for everything going forward.
Prerequisites#
- A running Piler instance with the SMTP daemon (
piler-smtp) accessible on port 25 - A Microsoft 365 tenant with Exchange Online
- Exchange administrator role in your M365 tenant
- DNS MX record for your journal domain pointing to the archive server
How it works#
Single-node deployment#
In a single-node setup, M365 delivers journal emails directly to piler-smtp. No separate MX relay is needed.
M365 tenant Archive server
┌──────────────┐ ┌────────────┐ ┌───────┐
│ Exchange │── journal ──>│ piler-smtp │─────>│ Piler │
│ Online │ (SMTP) │ (port 25) │ │ │
└──────────────┘ └────────────┘ └───────┘
Multi-node deployment#
If you run multiple worker nodes, an MX relay (e.g. postfix) distributes journal emails across them. See the postfix examples for a working setup.
M365 tenant Your infrastructure
┌──────────────┐ ┌─────────┐ ┌────────────────┐
│ Exchange │── journal ──>│ Postfix │─────>│ piler-smtp (1) │
│ Online │ (SMTP) │ (MX) │─────>│ piler-smtp (2) │
└──────────────┘ └─────────┘ └────────────────┘
When a user sends or receives an email in M365, the journal transport rule sends a BCC copy to your designated journal address (e.g. journal@archive.example.com). The piler-smtp daemon receives it, processes, and archives the email.
Step 1: DNS setup#
-
Choose a journal recipient address, e.g.
journal@archive.example.com -
Create a DNS MX record for
archive.example.compointing to your archive server (single-node) or your MX relay (multi-node)
Step 2: Create a journal transport rule in Exchange Online#
Using Exchange Admin Center (web UI)#
-
Sign in to the Exchange Admin Center
-
Go to Mail flow > Rules
-
Click Add a rule > Create a new rule
-
Configure the rule:
- Name:
Piler Email Archiving - Apply this rule if:
[Apply to all messages]— select "The sender" > "is internal or external" > "Inside or outside the organization" - Do the following: Select "BCC the message to..." and enter your journal address, e.g.
journal@archive.example.com
- Name:
-
Click Next, review the settings, and Save
-
Make sure the rule is enabled (toggle it on if needed)
Using PowerShell#
If you prefer PowerShell, connect to Exchange Online and run:
Connect-ExchangeOnline
New-TransportRule -Name "Piler Email Archiving" `
-FromScope "InOrganization" `
-BccMessageTo "journal@archive.example.com"
New-TransportRule -Name "Piler Email Archiving Inbound" `
-FromScope "NotInOrganization" `
-SentToScope "InOrganization" `
-BccMessageTo "journal@archive.example.com"
The first rule captures outbound and internal emails. The second rule captures inbound emails from external senders.
Step 3: Verify emails are being archived#
-
Send a test email from an M365 mailbox to an external address (or between two M365 users)
-
Wait 1-2 minutes for the journal rule to trigger
-
Check the piler-smtp logs for the incoming message:
journalctl -u piler-smtp -f
You should see the journal email being received and processed.
- Log in to the Piler web UI and search for the test email. It should appear in the archive.
Multi-tenant setup (for MSPs)#
If you manage multiple M365 tenants with a multi-tenant Piler deployment, each tenant needs its own journal rule pointing to a tenant-specific address.
The tenant-specific address is
Addressing scheme#
Use a per-tenant journal address, for example:
| M365 tenant | Journal address |
|---|---|
| Client A | clienta@archive.example.com |
| Client B | clientb@archive.example.com |
| Client C | clientc@archive.example.com |
Postfix routing#
Configure postfix to route each tenant's journal emails. All journal addresses go to the same piler-smtp instance — Piler handles tenant separation internally based on the recipient domains configured per tenant.
Per-tenant journal rules#
In each client's M365 tenant, create the transport rule (Step 2) using their specific journal address. This keeps each tenant's email stream identifiable.
Troubleshooting#
Emails not arriving in the archive#
- Check DNS: Verify the MX record for your journal domain resolves correctly:
dig MX archive.example.com - Check firewall: Ensure port 25 is open between M365 (outbound SMTP) and your archive server
- Check piler-smtp logs:
journalctl -u piler-smtp -f— look for incoming connections and processing - Check postfix logs (multi-node only):
journalctl -u postfix -f— look for connection attempts from M365 - M365 delivery delay: Journal rules may take a few minutes to activate after creation. Send another test email after 5-10 minutes.
Duplicate emails in the archive#
- If you see duplicates, check that you don't have overlapping rules (e.g. both a BCC rule and a journal rule for the same scope)
- Piler deduplicates by message-id, so exact duplicates are automatically handled. If you see near-duplicates, check your rule scope.
M365 connector / SPF issues#
If your server rejects journal emails from M365:
- Ensure
piler-smtpis configured to accept connections from M365's IP ranges - Or create an inbound connector in M365 that routes journal emails through a specific IP range you trust
Testing the SMTP path manually#
To verify piler-smtp is working independently of M365:
echo "Subject: test" | sendmail -f test@example.com journal@archive.example.com