[PATCH pve-manager v3 14/23] notifications: smtp: api: Add XOAUTH2 parameters

Arthur Bied-Charreton
2026-04-15T07:05:22Z

Add auth-method, oauth2-client-id, oauth2-client-secret,
oauth2-tenant-id and oauth2-refresh-token parameters to prepare for
XOAUTH2 support.

The authentication method was previously implicit and inferred by
proxmox-notify based on the presence of a password. It is now made
explicit, however still kept optional and inferred in the
{update,create}_endpoint handlers to avoid breaking the API.

The calls to {add,update}_smtp_endpoint are updated to pass the configs
as hashes instead of flat parameter lists, following the API changes in
proxmox-perl-rs.

Signed-off-by: Arthur Bied-Charreton <a.bied-charreton@proxmox.com>
---
PVE/API2/Cluster/Notifications.pm | 116 ++++++++++++++++++++++++------
1 file changed, 93 insertions(+), 23 deletions(-)

diff --git a/PVE/API2/Cluster/Notifications.pm b/PVE/API2/Cluster/Notifications.pm
index 8b455227..4967d823 100644
--- a/PVE/API2/Cluster/Notifications.pm
+++ b/PVE/API2/Cluster/Notifications.pm
@@ -941,6 +941,13 @@ my $smtp_properties = {
default => 'tls',
optional => 1,
},
+ 'auth-method' => {
+ description =>
+ 'Determine which authentication method shall be used for the connection.',
+ type => 'string',
+ enum => [qw(google-oauth2 microsoft-oauth2 plain)],
+ optional => 1,
+ },
username => {
description => 'Username for SMTP authentication',
type => 'string',
@@ -951,6 +958,26 @@ my $smtp_properties = {
type => 'string',
optional => 1,
},
+ 'oauth2-client-id' => {
+ description => 'OAuth2 client ID',
+ type => 'string',
+ optional => 1,
+ },
+ 'oauth2-client-secret' => {
+ description => 'OAuth2 client secret',
+ type => 'string',
+ optional => 1,
+ },
+ 'oauth2-tenant-id' => {
+ description => 'OAuth2 tenant ID, only required for Microsoft OAuth2 endpoints',
+ type => 'string',
+ optional => 1,
+ },
+ 'oauth2-refresh-token' => {
+ description => 'OAuth2 refresh token',
+ type => 'string',
+ optional => 1,
+ },
mailto => {
type => 'array',
items => {
@@ -1108,6 +1135,11 @@ __PACKAGE__->register_method({
my $mode = extract_param($param, 'mode');
my $username = extract_param($param, 'username');
my $password = extract_param($param, 'password');
+ my $auth_method = extract_param($param, 'auth-method');
+ my $oauth2_client_secret = extract_param($param, 'oauth2-client-secret');
+ my $oauth2_client_id = extract_param($param, 'oauth2-client-id');
+ my $oauth2_tenant_id = extract_param($param, 'oauth2-tenant-id');
+ my $oauth2_refresh_token = extract_param($param, 'oauth2-refresh-token');
my $mailto = extract_param($param, 'mailto');
my $mailto_user = extract_param($param, 'mailto-user');
my $from_address = extract_param($param, 'from-address');
@@ -1115,23 +1147,40 @@ __PACKAGE__->register_method({
my $comment = extract_param($param, 'comment');
my $disable = extract_param($param, 'disable');

+ # Required for backwards-compatibity: before the auth-method parameter was
+ # introduced, the authentication method was inferred from the presence of
+ # a password.
+ if (!defined($auth_method)) {
+ $auth_method = defined($password) ? 'plain' : undef;
+ }
+
eval {
PVE::Notify::lock_config(sub {
my $config = PVE::Notify::read_config();

$config->add_smtp_endpoint(
- $name,
- $server,
- $port,
- $mode,
- $username,
- $password,
- $mailto,
- $mailto_user,
- $from_address,
- $author,
- $comment,
- $disable,
+ {
+ name => $name,
+ server => $server,
+ port => $port,
+ mode => $mode,
+ username => $username,
+ 'auth-method' => $auth_method,
+ 'oauth2-client-id' => $oauth2_client_id,
+ 'oauth2-tenant-id' => $oauth2_tenant_id,
+ mailto => defined($mailto) ? $mailto : [],
+ 'mailto-user' => defined($mailto_user) ? $mailto_user : [],
+ 'from-address' => $from_address,
+ author => $author,
+ comment => $comment,
+ disable => $disable,
+ },
+ {
+ name => $name,
+ password => $password,
+ 'oauth2-client-secret' => $oauth2_client_secret,
+ },
+ $oauth2_refresh_token,
);

PVE::Notify::write_config($config);
@@ -1187,6 +1236,11 @@ __PACKAGE__->register_method({
my $mode = extract_param($param, 'mode');
my $username = extract_param($param, 'username');
my $password = extract_param($param, 'password');
+ my $auth_method = extract_param($param, 'auth-method');
+ my $oauth2_client_secret = extract_param($param, 'oauth2-client-secret');
+ my $oauth2_client_id = extract_param($param, 'oauth2-client-id');
+ my $oauth2_tenant_id = extract_param($param, 'oauth2-tenant-id');
+ my $oauth2_refresh_token = extract_param($param, 'oauth2-refresh-token');
my $mailto = extract_param($param, 'mailto');
my $mailto_user = extract_param($param, 'mailto-user');
my $from_address = extract_param($param, 'from-address');
@@ -1197,23 +1251,39 @@ __PACKAGE__->register_method({
my $delete = extract_param($param, 'delete');
my $digest = extract_param($param, 'digest');

+ # Required for backwards-compatibity: before the auth-method parameter was
+ # introduced, the authentication method was inferred from the presence of
+ # a password.
+ if (!defined($auth_method)) {
+ $auth_method = defined($password) ? 'plain' : undef;
+ }
+
eval {
PVE::Notify::lock_config(sub {
my $config = PVE::Notify::read_config();

$config->update_smtp_endpoint(
$name,
- $server,
- $port,
- $mode,
- $username,
- $password,
- $mailto,
- $mailto_user,
- $from_address,
- $author,
- $comment,
- $disable,
+ {
+ server => $server,
+ port => $port,
+ mode => $mode,
+ username => $username,
+ 'auth-method' => $auth_method,
+ 'oauth2-client-id' => $oauth2_client_id,
+ 'oauth2-tenant-id' => $oauth2_tenant_id,
+ mailto => defined($mailto) ? $mailto : [],
+ 'mailto-user' => defined($mailto_user) ? $mailto_user : [],
+ 'from-address' => $from_address,
+ author => $author,
+ comment => $comment,
+ disable => $disable,
+ },
+ {
+ password => $password,
+ 'oauth2-client-secret' => $oauth2_client_secret,
+ },
+ $oauth2_refresh_token,
$delete,
$digest,
);
--
2.47.3