Proxmox Notifications with Office 365 OAuth2 (No SMTP AUTH required) - Working Guide for PVE 9

sunmanx

New Member
Feb 19, 2026
1
1
0
Sonnet 4.6 helped create this guide to get our local proxmox working with 365 oauth. Hope it helps someone else.

With Microsoft retiring basic SMTP AUTH for Office 365 in September 2025, a lot of people are stuck trying to get Proxmox notifications working. I couldn't find a complete working guide anywhere, so after a lot of trial and error I'm posting what finally worked for me.
The solution uses email-oauth2-proxy (https://github.com/simonrob/email-oauth2-proxy) — a lightweight Python service that runs locally on each Proxmox node, accepts plain SMTP from Proxmox, and relays it to Office 365 using OAuth2. Proxmox doesn't need any changes beyond pointing its notification target at localhost.

Tested on PVE 9.1.5 / Debian 13 Trixie on a 2-node cluster. Should work on PVE 8 as well with minor adjustments. GCC tenants are covered — there's a note about a permissions quirk specific to GCC.

Markdown (GitHub flavored):
# Proxmox Notifications via Office 365 with OAuth2
**Guide for PVE 9 / Debian 13 (Trixie)**

Microsoft has disabled basic SMTP AUTH for Office 365 and is retiring it entirely in September 2025. This guide explains how to configure Proxmox notifications to send email through Office 365 using OAuth2, via a local SMTP proxy called [email-oauth2-proxy](https://github.com/simonrob/email-oauth2-proxy).

The proxy runs on each Proxmox node as a systemd service. It listens on localhost as a plain SMTP server, intercepts connections from Proxmox, and relays them to Office 365 using OAuth2 behind the scenes. Proxmox doesn't need to know anything about OAuth2.

---

## Prerequisites

- A Proxmox VE cluster (tested on PVE 9.1.5 / Debian 13)
- An Office 365 mailbox to send from (must be a **regular user mailbox with a license** — shared mailboxes do not support OAuth2 interactive login)
- Admin access to Microsoft Entra (Azure AD)
- SSH access to your Proxmox nodes

---

## Part 1: Configure Microsoft Entra (Azure AD)

### 1. Register a new app

1. Go to [Entra admin center](https://entra.microsoft.com) → **App registrations** → **New registration**
2. Fill in:
   - **Name:** `Proxmox SMTP Relay` (or anything you like)
   - **Supported account types:** Accounts in this organizational directory only (Single tenant)
   - **Redirect URI:** Select **Web**, enter: `https://login.microsoftonline.com/common/oauth2/nativeclient`
3. Click **Register**
4. Note down:
   - **Application (client) ID**
   - **Directory (tenant) ID**

### 2. Create a client secret

1. In the left sidebar click **Certificates & secrets** → **Client secrets** → **New client secret**
2. Give it a description and set an expiry (24 months recommended)
3. Click **Add**
4. **Copy the secret Value immediately** — it is only shown once

### 3. Add API permissions

1. In the left sidebar click **API permissions** → **Add a permission**
2. Click **Microsoft Graph** → **Delegated permissions**
3. Search for and check each of the following:
   - `IMAP.AccessAsUser.All`
   - `POP.AccessAsUser.All`
   - `SMTP.Send`
4. Click **Add permissions**
5. Click **Grant admin consent for [your organization]** and confirm

> **Note:** These permissions appear under Microsoft Graph, not under "Office 365 Exchange Online". The Exchange Online API does not expose these permissions in GCC tenants via the Entra portal. Microsoft Graph works fine with the proxy.

### 4. Enable Authenticated SMTP for the mailbox

1. Go to [Microsoft 365 admin center](https://admin.microsoft.com) → **Users** → **Active users**
2. Click the user you want to send from
3. Click **Mail** tab → **Manage email apps**
4. Ensure **Authenticated SMTP** is checked
5. Save

---

## Part 2: Install email-oauth2-proxy on each Proxmox node

Repeat these steps on **each node** in your cluster.

### 1. Install dependencies and clone the repo

```bash
apt install -y git python3-pip python3-venv
cd /opt
git clone https://github.com/simonrob/email-oauth2-proxy/
cd email-oauth2-proxy
python3 -m venv .env
source .env/bin/activate
pip install -U pip
pip install -r requirements-core.txt
```

### 2. Create the config file

Create `/opt/email-oauth2-proxy/emailproxy.config` with the following content, substituting your own values:

```ini
[emailproxy]
local_address = 127.0.0.1
listen_on_localhost = True
cache_store = /opt/email-oauth2-proxy/emailproxy.cache

[SMTP-2525]
local_address = 127.0.0.1
server_address = smtp.office365.com
server_port = 587
starttls = True

[your-email@yourdomain.com]
permission_url = https://login.microsoftonline.com/YOUR_TENANT_ID/oauth2/v2.0/authorize
token_url = https://login.microsoftonline.com/YOUR_TENANT_ID/oauth2/v2.0/token
oauth2_scope = https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/POP.AccessAsUser.All https://outlook.office.com/SMTP.Send offline_access
redirect_uri = https://login.microsoftonline.com/common/oauth2/nativeclient
client_id = YOUR_CLIENT_ID
client_secret = YOUR_CLIENT_SECRET
```

Replace:
- `your-email@yourdomain.com` with your sending mailbox address
- `YOUR_TENANT_ID` with the Directory (tenant) ID from Entra
- `YOUR_CLIENT_ID` with the Application (client) ID from Entra
- `YOUR_CLIENT_SECRET` with the secret value you copied

> **Important:** The proxy uses whatever SMTP password Proxmox sends as an encryption key for the stored OAuth token. Choose a password now (e.g. `mypassword`) and use the **same value** in both the proxy's initial auth step and in the Proxmox notification target configuration. We will use it in the next step.

### 3. Perform the one-time interactive OAuth authorization

This step must be done **once per node** in an interactive SSH terminal session. It cannot be automated because it requires you to log in via a browser.

**In your first SSH session:**
```bash
cd /opt/email-oauth2-proxy
.env/bin/python3 emailproxy.py --external-auth --no-gui --config-file /opt/email-oauth2-proxy/emailproxy.config
```

**In a second SSH session**, trigger the auth flow by sending a test email:
```python
python3 -c "
import smtplib
s = smtplib.SMTP('127.0.0.1', 2525, timeout=30)
s.ehlo()
s.login('your-email@yourdomain.com', 'mypassword')
s.sendmail('your-email@yourdomain.com', 'your-email@yourdomain.com', 'Subject: test\n\ntest')
s.quit()
"
```

**Back in the first session**, the proxy will print a URL like:
```
Please visit the following URL to authenticate account your-email@yourdomain.com:
https://login.microsoftonline.com/...
```

1. Copy that URL and open it in a **private/incognito browser tab**
2. Sign in with your Office 365 account
3. You will land on a **blank white page** — this is expected
4. Copy the full URL from the browser address bar (it starts with `https://login.microsoftonline.com/common/oauth2/nativeclient?code=...`)
5. Paste it into the first terminal session and press **Enter**
6. The proxy will print: `Successfully authenticated SMTP connection - releasing session`
7. Press **Ctrl+C** to stop the proxy

The OAuth token is now saved (encrypted with your chosen password) in the config file.

### 4. Install as a systemd service

```bash
nano /etc/systemd/system/emailproxy.service
```

Paste the following:

```ini
[Unit]
Description=Email OAuth 2.0 Proxy
After=network.target

[Service]
ExecStart=/opt/email-oauth2-proxy/.env/bin/python3 /opt/email-oauth2-proxy/emailproxy.py --external-auth --no-gui --config-file /opt/email-oauth2-proxy/emailproxy.config
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
```

Enable and start it:
```bash
systemctl daemon-reload
systemctl enable emailproxy
systemctl start emailproxy
systemctl status emailproxy
```

### 5. Verify it works

```python
python3 -c "
import smtplib
s = smtplib.SMTP('127.0.0.1', 2525, timeout=30)
s.ehlo()
s.login('your-email@yourdomain.com', 'mypassword')
s.sendmail('your-email@yourdomain.com', 'recipient@example.com', 'Subject: Proxmox test\n\nWorking!')
s.quit()
"
```

---

## Part 3: Configure Proxmox Notifications

### 1. Add a notification target

In the Proxmox web UI go to **Datacenter → Notifications → Add → SMTP** and fill in:

| Field | Value |
|-------|-------|
| Name | `office365` |
| Server | `127.0.0.1` |
| Port | `2525` |
| Encryption | `None` |
| Username | `your-email@yourdomain.com` |
| Password | `mypassword` (same password used during OAuth auth) |
| From address | `your-email@yourdomain.com` |
| Recipients | `recipient@example.com` |

Click **Add**, then click **Test** to verify it works.

### 2. Update the notification matcher

Go to **Datacenter → Notifications → Notification Matchers** and edit or add a matcher to route notifications to your new `office365` target.

---

## Notes

- The OAuth token is stored encrypted in the config file and includes a refresh token, so it will automatically renew without requiring re-authorization.
- If you ever change the password in the Proxmox notification target, you must redo the OAuth authorization step so the token is re-encrypted with the new password.
- For multi-node clusters, perform the installation and one-time OAuth authorization on **each node separately**. The token can be copied between nodes after the first authorization (the same token works on all nodes since it belongs to the mailbox, not the machine).
- Proxmox's notification system is cluster-wide but each node sends its own notifications through its local proxy instance.
- The `mail-to-root` sendmail target can be disabled once the new SMTP target is working.
 
Last edited:
  • Like
Reactions: the_MiCrO