From 0d131afc03348886fea7248f5a12a6639d717714 Mon Sep 17 00:00:00 2001 From: Maurus Decimus <11444311+mdecimus@users.noreply.github.com> Date: Mon, 15 Jun 2026 15:29:58 +0200 Subject: [PATCH] Fix Autodiscover v2: Read email address from query parameters --- CHANGELOG.md | 1 + Cargo.lock | 1 + crates/common/src/network/autoconfig/autodiscover_v2.rs | 7 ++++++- crates/http/Cargo.toml | 1 + crates/http/src/request.rs | 7 ++++++- 5 files changed, 15 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dbff97cc..99af3232 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ If you are upgrading from v0.16.x, replace the binary (or run `docker pull`). If - MTA: Re-scheduling or editing a queued message reports success but persists nothing for recipients in a non-`default` virtual queue. - CardDAV: Version requests included in `address-data` are ignored. - ACME: Add freshness check when renewing certificates. +- Autodiscover v2: Read email address from query parameters. ## [0.16.8] - 2026-06-06 diff --git a/Cargo.lock b/Cargo.lock index 4e972daa..e2fac12b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3187,6 +3187,7 @@ dependencies = [ "mail-builder", "mail-parser", "mime", + "percent-encoding", "pkcs8", "quick-xml 0.40.1", "registry", diff --git a/crates/common/src/network/autoconfig/autodiscover_v2.rs b/crates/common/src/network/autoconfig/autodiscover_v2.rs index afb57994..2bc0868f 100644 --- a/crates/common/src/network/autoconfig/autodiscover_v2.rs +++ b/crates/common/src/network/autoconfig/autodiscover_v2.rs @@ -11,10 +11,15 @@ impl Server { pub async fn handle_autodiscover_v2_request( &self, query: Option<&str>, + path_email: Option<&str>, ) -> trc::Result>, String>> { // Parse query parameters let params = UrlParams::new(query); - let emailaddress = params.get("Email").unwrap_or_default().to_lowercase(); + let emailaddress = path_email + .filter(|email| !email.is_empty()) + .or_else(|| params.get("Email")) + .unwrap_or_default() + .to_lowercase(); let protocol = params.get("Protocol").unwrap_or_default(); // Validate email address diff --git a/crates/http/Cargo.toml b/crates/http/Cargo.toml index 7667f30c..c0ce5d19 100644 --- a/crates/http/Cargo.toml +++ b/crates/http/Cargo.toml @@ -42,6 +42,7 @@ sha2 = "0.11" rkyv = { version = "0.8.10", features = ["little_endian"] } form-data = { version = "0.6.0", features = ["sync"], default-features = false } mime = "0.3.17" +percent-encoding = "2.3.1" compact_str = "0.9.0" hashify = { version = "0.2" } diff --git a/crates/http/src/request.rs b/crates/http/src/request.rs index 37b5f31e..db0978b7 100644 --- a/crates/http/src/request.rs +++ b/crates/http/src/request.rs @@ -35,6 +35,7 @@ use hyper::{ service::service_fn, }; use hyper_util::rt::TokioIo; +use percent_encoding::percent_decode_str; use jmap::{ api::{ ToJmapHttpResponse, event_source::EventSourceHandler, request::RequestHandler, @@ -471,8 +472,12 @@ impl ParseHttp for Server { self.is_http_anonymous_request_allowed(session.remote_ip) .await?; + let path_email = path.find(|segment| segment.contains('@')).map(|segment| { + percent_decode_str(segment).decode_utf8_lossy().into_owned() + }); + return self - .handle_autodiscover_v2_request(req.uri().query()) + .handle_autodiscover_v2_request(req.uri().query(), path_email.as_deref()) .await .map(|result| match result { Ok(resource) => resource.into_http_response(),