Microsoft 365 / Exchange Online Email Setup¶
Professional-level guide for integrating Microsoft 365 (Exchange Online) email with Odoo, including catchall addresses, mail flow rules, and OAuth2 authentication.
Architecture Overview¶
┌─────────────────────────────────────────────────────────────────────┐
│ MICROSOFT 365 / EXCHANGE ONLINE │
└─────────────────────────────────────────────────────────────────────┘
Your Domain: yourdomain.com
│
┌───────────────┼───────────────┐
│ │ │
▼ ▼ ▼
┌───────────┐ ┌───────────┐ ┌───────────┐
│ Aliases │ │ Catchall │ │ Mail Flow │
│ │ │ (Transport│ │ Rules │
│ sales@ │ │ Rule) │ │ │
│ support@ │ │ ↓ │ │ purchase+ │
│ info@ │ │ catchall@ │ │ sale+ │
└─────┬─────┘ └─────┬─────┘ └─────┬─────┘
│ │ │
└───────────────┼───────────────┘
│
▼
┌─────────────────────────┐
│ Shared/Service Mailbox │
│ odoo@yourdomain.com │
└────────────┬────────────┘
│
┌────────────┼────────────┐
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ IMAP │ │ SMTP │ │ Azure │
│ Incoming │ │ Outgoing │ │ OAuth2 │
└────┬─────┘ └────┬─────┘ └────┬─────┘
│ │ │
└────────────┼────────────┘
│
▼
┌─────────────────────────┐
│ ODOO │
│ │
│ • Fetchmail Service │
│ • mail.thread routing │
│ • Email sending │
└─────────────────────────┘
Prerequisites¶
| Requirement | Description |
|---|---|
| Microsoft 365 | Business Basic or higher (Exchange Online) |
| Admin Access | Exchange Admin or Global Admin |
| Azure AD Access | For OAuth2 app registration |
| Domain Verified | Custom domain configured in M365 |
| Odoo Access | Admin access to Odoo instance |
Key Differences from Google Workspace¶
| Feature | Google Workspace | Microsoft 365 |
|---|---|---|
| Catchall | Built-in feature | Transport rule workaround |
| Admin Portal | Google Admin Console | Exchange Admin Center + Azure Portal |
| OAuth Setup | Google Cloud Console | Azure Portal (Entra ID) |
| Pattern Routing | Default Routing rules | Mail Flow (Transport) rules |
| Shared Mailbox | User aliases | Shared Mailbox (no license) |
Step 1: Create Service Account or Shared Mailbox¶
You have two options:
Option A: Shared Mailbox (No License Required)¶
- Go to Exchange Admin Center
- Navigate to Recipients → Mailboxes → Add a shared mailbox
- Create mailbox:
| Field | Value |
|---|---|
| Display name | Odoo System |
| Email address | odoo@yourdomain.com |
Shared Mailbox Benefits
- No license required (cost savings)
- Up to 50GB storage
- Multiple users can access
Option B: Service Account (Licensed User)¶
- Go to Microsoft 365 Admin Center
- Navigate to Users → Active users → Add a user
- Create user:
| Field | Value |
|---|---|
| Display name | Odoo Service |
| Username | odoo@yourdomain.com |
| License | Exchange Online (minimum) |
Shared Mailbox + OAuth Limitation
Shared mailboxes require special OAuth configuration. For simpler setup, use a licensed service account.
Step 2: Enable IMAP and SMTP AUTH¶
For Individual Mailbox¶
Using PowerShell:
# Connect to Exchange Online
Connect-ExchangeOnline
# Enable IMAP
Set-CASMailbox -Identity "odoo@yourdomain.com" -ImapEnabled $true
# Enable SMTP AUTH (required for sending)
Set-CASMailbox -Identity "odoo@yourdomain.com" -SmtpClientAuthenticationDisabled $false
# Verify settings
Get-CASMailbox -Identity "odoo@yourdomain.com" | FL Imap*, Smtp*
For Organization-Wide (if SMTP AUTH is disabled)¶
# Check organization setting
Get-TransportConfig | FL SmtpClientAuthenticationDisabled
# Enable if needed (affects all users)
Set-TransportConfig -SmtpClientAuthenticationDisabled $false
Via Exchange Admin Center¶
- Go to Recipients → Mailboxes
- Select the Odoo mailbox
- Click Manage email apps settings
- Enable IMAP and Authenticated SMTP
Step 3: Set Up Catchall (Transport Rule Method)¶
Microsoft 365 doesn't have built-in catchall. Use transport rules instead.
Step 3.1: Create Dynamic Distribution Group¶
This group contains all valid recipients to exclude from catchall.
Using PowerShell:
# Connect to Exchange Online
Connect-ExchangeOnline
# Create Dynamic Distribution Group with all recipients
New-DynamicDistributionGroup -Name "All Mail Recipients" `
-RecipientFilter "RecipientType -eq 'UserMailbox' -or RecipientType -eq 'MailUniversalDistributionGroup' -or RecipientType -eq 'MailUniversalSecurityGroup' -or RecipientType -eq 'MailContact' -or RecipientType -eq 'SharedMailbox'"
# Verify members
$DDG = Get-DynamicDistributionGroup "All Mail Recipients"
Get-Recipient -RecipientPreviewFilter $DDG.RecipientFilter | Select Name, PrimarySmtpAddress
Step 3.2: Change Domain to Internal Relay¶
This allows Exchange to accept emails for non-existent addresses.
Using PowerShell:
# View current domain type
Get-AcceptedDomain | FL Name, DomainType
# Change to Internal Relay
Set-AcceptedDomain -Identity "yourdomain.com" -DomainType InternalRelay
Via Exchange Admin Center:
- Go to Mail flow → Accepted domains
- Select your domain
- Change type to Internal Relay
Internal Relay Impact
This allows ALL emails to your domain to be accepted, even to non-existent addresses. Make sure your catchall rule is working before enabling this.
Step 3.3: Create Transport Rule for Catchall¶
Via Exchange Admin Center:
- Go to Mail flow → Rules
- Click + Add a rule → Create a new rule
- Configure:
| Setting | Value |
|---|---|
| Name | Catchall to Odoo |
| Apply this rule if | The recipient is not a member of "All Mail Recipients" |
| Do the following | Redirect the message to odoo@yourdomain.com |
| Except if | The sender is inside the organization |
| Priority | Set lower than other rules |
Using PowerShell:
New-TransportRule -Name "Catchall to Odoo" `
-SentToMemberOf "All Mail Recipients" `
-ExceptIfSentToMemberOf "All Mail Recipients" `
-RedirectMessageTo "odoo@yourdomain.com" `
-Priority 10
Dynamic Group Update Delay
Microsoft updates Dynamic Distribution Groups once per day. New users may not receive email until the next update. Force update with:
(Limited to once per hour)Step 4: Set Up Pattern-Based Routing (Recommended)¶
Instead of catchall, route specific Odoo patterns for better control.
Create Mail Flow Rules for Odoo Patterns¶
Rule 1: Purchase Order Replies
- Go to Mail flow → Rules → + Add a rule
- Configure:
| Setting | Value |
|---|---|
| Name | Route Purchase+ to Odoo |
| Apply this rule if | The recipient address includes: purchase+ |
| Do the following | Redirect the message to: odoo@yourdomain.com |
Rule 2: Sales Order Replies
| Setting | Value |
|---|---|
| Name | Route Sale+ to Odoo |
| Apply this rule if | The recipient address includes: sale+ |
| Do the following | Redirect the message to: odoo@yourdomain.com |
Rule 3: Helpdesk Replies
| Setting | Value |
|---|---|
| Name | Route Helpdesk+ to Odoo |
| Apply this rule if | The recipient address includes: helpdesk+ |
| Do the following | Redirect the message to: odoo@yourdomain.com |
Using PowerShell (All Rules):
# Purchase Orders
New-TransportRule -Name "Route Purchase+ to Odoo" `
-RecipientAddressContainsWords "purchase+" `
-RedirectMessageTo "odoo@yourdomain.com"
# Sales Orders
New-TransportRule -Name "Route Sale+ to Odoo" `
-RecipientAddressContainsWords "sale+" `
-RedirectMessageTo "odoo@yourdomain.com"
# Helpdesk
New-TransportRule -Name "Route Helpdesk+ to Odoo" `
-RecipientAddressContainsWords "helpdesk+" `
-RedirectMessageTo "odoo@yourdomain.com"
# CRM Leads
New-TransportRule -Name "Route CRM+ to Odoo" `
-RecipientAddressContainsWords "crm+","lead+" `
-RedirectMessageTo "odoo@yourdomain.com"
Combined Rule with Regex¶
For advanced pattern matching:
New-TransportRule -Name "Route All Odoo Patterns" `
-RecipientAddressMatchesPatterns "^(purchase|sale|helpdesk|crm|lead|project)\+.*@yourdomain\.com$" `
-RedirectMessageTo "odoo@yourdomain.com"
Step 5: Configure Azure OAuth2 for Odoo¶
Microsoft deprecated Basic Auth. Use OAuth2 for secure authentication.
Step 5.1: Register Application in Azure Portal¶
- Go to Azure Portal
- Navigate to Microsoft Entra ID (formerly Azure Active Directory)
- Click App registrations → New registration
- Configure:
| Field | Value |
|---|---|
| Name | Odoo Mail Integration |
| Supported account types | Accounts in this organizational directory only |
| Redirect URI | Web: https://yourodoo.com/microsoft_outlook/confirm |
- Click Register
- Copy the Application (client) ID and Directory (tenant) ID
Step 5.2: Create Client Secret¶
- In your app registration, go to Certificates & secrets
- Click New client secret
- Add description:
Odoo OAuth - Set expiration (24 months recommended)
- Click Add
- Copy the secret value immediately (won't be shown again)
Step 5.3: Configure API Permissions¶
- Go to API permissions
- Click Add a permission
- Select Microsoft Graph
- Choose Delegated permissions
- Add these permissions:
| Permission | Purpose |
|---|---|
User.Read |
Sign in and read user profile |
IMAP.AccessAsUser.All |
Read email via IMAP |
SMTP.Send |
Send email via SMTP |
offline_access |
Maintain access (refresh token) |
- Click Add permissions
- Click Grant admin consent for [Your Organization]
Step 5.4: Add Users to Application (Optional)¶
For additional security:
- Go to Enterprise applications
- Find your Odoo Mail Integration app
- Go to Users and groups
- Click Add user/group
- Add the Odoo service account
Step 6: Configure Odoo¶
Install Microsoft Outlook Module¶
- Go to Apps
- Search for Microsoft Outlook
- Install the module
Configure OAuth Credentials¶
- Go to Settings → General Settings
- Enable Custom Email Servers under Discuss
- Enter OAuth credentials:
| Field | Value |
|---|---|
| Client ID | (from Azure Portal) |
| Client Secret | (from Azure Portal) |
- Click Save
Configure Outgoing Mail Server¶
- Go to Settings → Technical → Outgoing Mail Servers
- Create new server:
| Field | Value |
|---|---|
| Description | Microsoft 365 OAuth |
| SMTP Server | smtp.office365.com |
| SMTP Port | 587 |
| Connection Security | TLS (STARTTLS) |
| Username | odoo@yourdomain.com |
| Outlook OAuth Authentication | Checked |
- Click Connect your Outlook account
- Complete Microsoft authentication
- Click Test Connection
Configure Incoming Mail Server¶
- Go to Settings → Technical → Incoming Mail Servers
- Create new server:
| Field | Value |
|---|---|
| Name | Microsoft 365 OAuth IMAP |
| Server Type | Outlook OAuth Authentication |
| Username | odoo@yourdomain.com |
| Outlook OAuth Authentication | Checked |
- Click Connect your Outlook account
- Click Test & Confirm
Alternative: Basic Auth (Not Recommended)¶
If OAuth isn't possible, use SMTP Relay:
Outgoing Server:
| Field | Value |
|---|---|
| SMTP Server | yourdomain-com.mail.protection.outlook.com |
| SMTP Port | 25 |
| Connection Security | TLS (STARTTLS) |
| Username | (leave empty for relay) |
Basic Auth Deprecation
Microsoft is phasing out Basic Authentication. Use OAuth2 for new setups.
Step 7: Configure Odoo Alias Domain¶
- Go to Settings → General Settings
- Under Discuss, set Alias Domain:
yourdomain.com - Click Save
Step 8: Verify Fetchmail Cron¶
- Go to Settings → Technical → Scheduled Actions
- Find Mail: Fetchmail Service
- Verify:
| Setting | Value |
|---|---|
| Active | Checked |
| Interval | 5 minutes |
Testing the Setup¶
Test 1: Send Email from Odoo¶
- Create a Purchase Order
- Send RFQ to test email
- Verify email received
- Check headers for correct Reply-To
Test 2: Reply Routing¶
- Reply to the RFQ email
- Wait for fetchmail (or run manually)
- Check if reply appears in PO chatter
Test 3: Pattern Routing¶
- Send email to
purchase+test@yourdomain.com - Verify it arrives in Odoo mailbox
Test 4: Catchall (if configured)¶
- Send email to
random123@yourdomain.com - Verify it arrives in Odoo mailbox
Troubleshooting¶
OAuth Connection Failed¶
| Issue | Solution |
|---|---|
| Redirect URI mismatch | Must match exactly in Azure and Odoo |
| Missing permissions | Grant admin consent in Azure |
| Wrong tenant | Verify Directory (tenant) ID |
| HTTPS required | Odoo must use HTTPS for OAuth |
Emails Not Being Received¶
| Issue | Solution |
|---|---|
| IMAP disabled | Enable in Exchange Admin Center |
| Transport rule not working | Check rule priority and conditions |
| Domain not Internal Relay | Change domain type in Accepted Domains |
| DDG not updated | Force update or wait 24 hours |
Cannot Send Emails¶
| Issue | Solution |
|---|---|
| SMTP AUTH disabled | Enable per-mailbox or org-wide |
| Authentication failed | Re-authenticate OAuth in Odoo |
| Relay blocked | Check connector settings |
Check Message Trace¶
- Go to Exchange Admin Center
- Navigate to Mail flow → Message trace
- Search for specific email addresses
- View delivery status and applied rules
PowerShell Diagnostics¶
# Check mailbox settings
Get-CASMailbox -Identity "odoo@yourdomain.com" | FL
# Check transport rules
Get-TransportRule | FL Name, State, Priority
# Check accepted domains
Get-AcceptedDomain | FL Name, DomainType
# Test mail flow
Test-Mailflow -TargetEmailAddress "test@external.com"
# View message trace
Get-MessageTrace -RecipientAddress "odoo@yourdomain.com" -StartDate (Get-Date).AddDays(-1)
Complete Configuration Summary¶
Exchange Admin Center¶
| Setting | Location | Value |
|---|---|---|
| Odoo Mailbox | Recipients → Mailboxes | odoo@yourdomain.com |
| IMAP Enabled | Mailbox → Email apps | Enabled |
| SMTP AUTH | Mailbox → Email apps | Enabled |
| Domain Type | Mail flow → Accepted domains | Internal Relay |
| Transport Rules | Mail flow → Rules | Catchall + Pattern rules |
Azure Portal¶
| Setting | Location | Value |
|---|---|---|
| App Registration | Entra ID → App registrations | Odoo Mail Integration |
| Client Secret | App → Certificates & secrets | Created |
| API Permissions | App → API permissions | IMAP, SMTP, User.Read |
| Redirect URI | App → Authentication | https://yourodoo.com/microsoft_outlook/confirm |
Odoo¶
| Setting | Location | Value |
|---|---|---|
| Outlook module | Apps | Installed |
| OAuth credentials | General Settings | Client ID + Secret |
| Alias domain | General Settings → Discuss | yourdomain.com |
| Outgoing server | Technical → Outgoing Mail | Microsoft 365 OAuth |
| Incoming server | Technical → Incoming Mail | Microsoft 365 OAuth IMAP |
| Fetchmail cron | Technical → Scheduled Actions | Active, 5 min |
Security Best Practices¶
| Practice | Description |
|---|---|
| Use OAuth2 | Never use Basic Auth in production |
| Service account | Dedicated account for Odoo |
| Conditional Access | Apply Azure AD policies to app |
| Audit logs | Enable mailbox audit logging |
| Secret rotation | Rotate client secrets before expiry |
| MFA exemption | May need to exempt service account from MFA |
Monthly Maintenance Checklist¶
- Verify fetchmail cron is running
- Check OAuth token is still valid
- Check client secret expiry date
- Review transport rules are working
- Check message trace for delivery issues
- Verify DDG membership is current
- Check Odoo mailbox storage quota
PowerShell Quick Reference¶
# Connect to Exchange Online
Connect-ExchangeOnline
# Enable IMAP/SMTP for mailbox
Set-CASMailbox -Identity "odoo@yourdomain.com" -ImapEnabled $true -SmtpClientAuthenticationDisabled $false
# Create transport rule
New-TransportRule -Name "Route to Odoo" -RecipientAddressContainsWords "purchase+" -RedirectMessageTo "odoo@yourdomain.com"
# Check transport rules
Get-TransportRule | Select Name, State, Priority
# Message trace
Get-MessageTrace -RecipientAddress "odoo@yourdomain.com" -StartDate (Get-Date).AddDays(-1)
# Force DDG update
Set-DynamicDistributionGroup "All Mail Recipients" -RecipientFilter $((Get-DynamicDistributionGroup "All Mail Recipients").RecipientFilter)
# Disconnect
Disconnect-ExchangeOnline