about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2025-06-07 16:50:57 +0200
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2025-06-07 16:50:57 +0200
commitf4388ee36cb7ce7af8d4a28aae7023ce65da953b (patch)
treef7952fa6f90ffd6613b32e89f9d179d37ad62351
parenttests/taskchampion-sync: Use correct test function name (diff)
downloadnixos-server-f4388ee36cb7ce7af8d4a28aae7023ce65da953b.zip
pkgs/stalwart-mail-patched: Use different native-ca-roots patch
My patch was no longer working, as it was written against an older
version of stalwart. This patch is now sourced directly from a GitHub
pr, that was closed at the 21st of may.

Upstream says, that they will support that in a future version, but I am
honestly just waiting for the rug pull at this point. They are no longer
accepting PRs, focusing more and more on new features, whilst the
actual software is still very difficult to debug.

But, with all this said, their current source code is available under
the AGPL, so even if they rug pull (which might be difficult, due to fact,
that their CLA is from the FSFE), a base for forking still persists.
Diffstat (limited to '')
-rw-r--r--pkgs/by-name/st/stalwart-mail-patched/mail-send.nix20
-rw-r--r--pkgs/by-name/st/stalwart-mail-patched/package.nix12
-rw-r--r--pkgs/by-name/st/stalwart-mail-patched/patches/crates-Use-the-platform-CA-bundle-instead-of-the-bun.patch879
-rw-r--r--pkgs/by-name/st/stalwart-mail-patched/patches/use-platform-ca-roots.patch747
4 files changed, 749 insertions, 909 deletions
diff --git a/pkgs/by-name/st/stalwart-mail-patched/mail-send.nix b/pkgs/by-name/st/stalwart-mail-patched/mail-send.nix
deleted file mode 100644
index e0d8c57..0000000
--- a/pkgs/by-name/st/stalwart-mail-patched/mail-send.nix
+++ /dev/null
@@ -1,20 +0,0 @@
-{
-  stdenv,
-  fetchFromGitHub,
-}:
-stdenv.mkDerivation (finalAttrs: {
-  pname = "mail-send";
-  version = "0.5.0";
-
-  src = fetchFromGitHub {
-    owner = "stalwartlabs";
-    repo = "mail-send";
-    tag = "v${finalAttrs.version}";
-    hash = "sha256-uDD4GLwjRpNqjtXPMask0twGW2Gcm1PFyDGXcfPS0F4=";
-  };
-
-  installPhase = ''
-    mkdir --parents "$out"
-    cp --recursive ./. "$out/"
-  '';
-})
diff --git a/pkgs/by-name/st/stalwart-mail-patched/package.nix b/pkgs/by-name/st/stalwart-mail-patched/package.nix
index 5b1c409..9058f2c 100644
--- a/pkgs/by-name/st/stalwart-mail-patched/package.nix
+++ b/pkgs/by-name/st/stalwart-mail-patched/package.nix
@@ -4,8 +4,6 @@
   nixLib,
 }: let
   spamfilter = callPackage ./spam-filter.nix {};
-
-  mail-send = callPackage ./mail-send.nix {};
 in
   stalwart-mail.overrideAttrs (final: prev: {
     pname = "stalwart-mail-patched";
@@ -28,21 +26,15 @@ in
       # "elastic"
       # "s3"
       "redis"
+      "tls-native-roots"
     ];
 
-    postUnpack =
-      (prev.postUnpack or "")
-      + ''
-        cp --recursive "${mail-send}" ./source/crates/mail-send
-        chmod --recursive +w "./source/crates/mail-send"
-      '';
-
     cargoPatches =
       (prev.cargoPatches or [])
       ++ [
         # `stalwart-mail` uses their bundled store, which makes it impossible to use our
         # own CA certificate (e.g., for tests). Thus use a native version.
-        ./patches/crates-Use-the-platform-CA-bundle-instead-of-the-bun.patch
+        ./patches/use-platform-ca-roots.patch
       ];
 
     # Check that the enterprise feature is really disabled.
diff --git a/pkgs/by-name/st/stalwart-mail-patched/patches/crates-Use-the-platform-CA-bundle-instead-of-the-bun.patch b/pkgs/by-name/st/stalwart-mail-patched/patches/crates-Use-the-platform-CA-bundle-instead-of-the-bun.patch
deleted file mode 100644
index e6c3d4b..0000000
--- a/pkgs/by-name/st/stalwart-mail-patched/patches/crates-Use-the-platform-CA-bundle-instead-of-the-bun.patch
+++ /dev/null
@@ -1,879 +0,0 @@
-From 6825a35213d604a7149265af2346a69143c0853b Mon Sep 17 00:00:00 2001
-From: Benedikt Peetz <benedikt.peetz@b-peetz.de>
-Date: Tue, 4 Mar 2025 19:15:06 +0100
-Subject: [PATCH] crates/*: Use the platform CA bundle instead of the
- bundled certificates
-
----
- Cargo.lock                       | 284 ++++++++++++++++++++++++++++++-
- crates/cli/Cargo.toml            |   2 +-
- crates/common/Cargo.toml         |   4 +-
- crates/directory/Cargo.toml      |   4 +-
- crates/imap/Cargo.toml           |   2 +-
- crates/jmap/Cargo.toml           |   4 +-
- crates/mail-send/Cargo.toml      |   1 +
- crates/mail-send/src/smtp/tls.rs |  22 +--
- crates/managesieve/Cargo.toml    |   2 +-
- crates/pop3/Cargo.toml           |   2 +-
- crates/smtp/Cargo.toml           |   4 +-
- crates/spam-filter/Cargo.toml    |   4 +-
- crates/store/Cargo.toml          |   2 +-
- crates/trc/Cargo.toml            |   2 +-
- crates/utils/Cargo.toml          |   5 +-
- crates/utils/src/lib.rs          |  16 +-
- tests/Cargo.toml                 |  10 +-
- 17 files changed, 314 insertions(+), 56 deletions(-)
-
-diff --git a/Cargo.lock b/Cargo.lock
-index be36759b..eca9699f 100644
---- a/Cargo.lock
-+++ b/Cargo.lock
-@@ -440,6 +440,47 @@ dependencies = [
-  "url",
- ]
- 
-+[[package]]
-+name = "aws-lc-fips-sys"
-+version = "0.13.3"
-+source = "registry+https://github.com/rust-lang/crates.io-index"
-+checksum = "29003a681b2b9465c1139bfb726da452a841a8b025f35953f3bce71139f10b21"
-+dependencies = [
-+ "bindgen 0.69.5",
-+ "cc",
-+ "cmake",
-+ "dunce",
-+ "fs_extra",
-+ "paste",
-+ "regex",
-+]
-+
-+[[package]]
-+name = "aws-lc-rs"
-+version = "1.12.5"
-+source = "registry+https://github.com/rust-lang/crates.io-index"
-+checksum = "5e4e8200b9a4a5801a769d50eeabc05670fec7e959a8cb7a63a93e4e519942ae"
-+dependencies = [
-+ "aws-lc-fips-sys",
-+ "aws-lc-sys",
-+ "paste",
-+ "zeroize",
-+]
-+
-+[[package]]
-+name = "aws-lc-sys"
-+version = "0.26.0"
-+source = "registry+https://github.com/rust-lang/crates.io-index"
-+checksum = "0f9dd2e03ee80ca2822dd6ea431163d2ef259f2066a4d6ccaca6d9dcb386aa43"
-+dependencies = [
-+ "bindgen 0.69.5",
-+ "cc",
-+ "cmake",
-+ "dunce",
-+ "fs_extra",
-+ "paste",
-+]
-+
- [[package]]
- name = "aws-region"
- version = "0.25.5"
-@@ -673,12 +714,15 @@ dependencies = [
-  "itertools 0.12.1",
-  "lazy_static",
-  "lazycell",
-+ "log",
-+ "prettyplease",
-  "proc-macro2",
-  "quote",
-  "regex",
-  "rustc-hash 1.1.0",
-  "shlex",
-  "syn 2.0.96",
-+ "which",
- ]
- 
- [[package]]
-@@ -1035,6 +1079,12 @@ dependencies = [
-  "smallvec",
- ]
- 
-+[[package]]
-+name = "cesu8"
-+version = "1.1.0"
-+source = "registry+https://github.com/rust-lang/crates.io-index"
-+checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
-+
- [[package]]
- name = "cexpr"
- version = "0.6.0"
-@@ -1347,6 +1397,16 @@ dependencies = [
-  "libc",
- ]
- 
-+[[package]]
-+name = "core-foundation"
-+version = "0.10.0"
-+source = "registry+https://github.com/rust-lang/crates.io-index"
-+checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63"
-+dependencies = [
-+ "core-foundation-sys",
-+ "libc",
-+]
-+
- [[package]]
- name = "core-foundation-sys"
- version = "0.8.7"
-@@ -1912,6 +1972,12 @@ dependencies = [
-  "zeroize",
- ]
- 
-+[[package]]
-+name = "dunce"
-+version = "1.0.5"
-+source = "registry+https://github.com/rust-lang/crates.io-index"
-+checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
-+
- [[package]]
- name = "dyn-clone"
- version = "1.0.17"
-@@ -2117,6 +2183,29 @@ dependencies = [
-  "syn 2.0.96",
- ]
- 
-+[[package]]
-+name = "env_filter"
-+version = "0.1.3"
-+source = "registry+https://github.com/rust-lang/crates.io-index"
-+checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0"
-+dependencies = [
-+ "log",
-+ "regex",
-+]
-+
-+[[package]]
-+name = "env_logger"
-+version = "0.11.6"
-+source = "registry+https://github.com/rust-lang/crates.io-index"
-+checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0"
-+dependencies = [
-+ "anstream",
-+ "anstyle",
-+ "env_filter",
-+ "humantime",
-+ "log",
-+]
-+
- [[package]]
- name = "equivalent"
- version = "1.0.1"
-@@ -2423,6 +2512,12 @@ dependencies = [
-  "syn 2.0.96",
- ]
- 
-+[[package]]
-+name = "fs_extra"
-+version = "1.3.0"
-+source = "registry+https://github.com/rust-lang/crates.io-index"
-+checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
-+
- [[package]]
- name = "funty"
- version = "2.0.0"
-@@ -2974,6 +3069,12 @@ version = "0.4.3"
- source = "registry+https://github.com/rust-lang/crates.io-index"
- checksum = "9994b79e8c1a39b3166c63ae7823bb2b00831e2a96a31399c50fe69df408eaeb"
- 
-+[[package]]
-+name = "humantime"
-+version = "2.1.0"
-+source = "registry+https://github.com/rust-lang/crates.io-index"
-+checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
-+
- [[package]]
- name = "hyper"
- version = "0.14.32"
-@@ -3044,6 +3145,7 @@ dependencies = [
-  "hyper 1.6.0",
-  "hyper-util",
-  "rustls 0.23.21",
-+ "rustls-native-certs 0.8.1",
-  "rustls-pki-types",
-  "tokio",
-  "tokio-rustls 0.26.1",
-@@ -3607,6 +3709,28 @@ dependencies = [
-  "utils",
- ]
- 
-+[[package]]
-+name = "jni"
-+version = "0.21.1"
-+source = "registry+https://github.com/rust-lang/crates.io-index"
-+checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97"
-+dependencies = [
-+ "cesu8",
-+ "cfg-if",
-+ "combine",
-+ "jni-sys",
-+ "log",
-+ "thiserror 1.0.69",
-+ "walkdir",
-+ "windows-sys 0.45.0",
-+]
-+
-+[[package]]
-+name = "jni-sys"
-+version = "0.3.0"
-+source = "registry+https://github.com/rust-lang/crates.io-index"
-+checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
-+
- [[package]]
- name = "jobserver"
- version = "0.1.32"
-@@ -3959,14 +4083,18 @@ dependencies = [
- [[package]]
- name = "mail-send"
- version = "0.5.0"
--source = "registry+https://github.com/rust-lang/crates.io-index"
--checksum = "b12277cdcacfc15af67fe9cf155f31ff68ad8c301304573ea116ed8870f192d5"
- dependencies = [
-  "base64 0.22.1",
-+ "env_logger",
-  "gethostname",
-+ "mail-auth",
-+ "mail-builder",
-+ "mail-parser",
-  "md5",
-+ "rand 0.8.5",
-  "rustls 0.23.21",
-  "rustls-pki-types",
-+ "rustls-platform-verifier",
-  "smtp-proto",
-  "tokio",
-  "tokio-rustls 0.26.1",
-@@ -5552,6 +5680,7 @@ dependencies = [
-  "pin-project-lite",
-  "quinn",
-  "rustls 0.23.21",
-+ "rustls-native-certs 0.8.1",
-  "rustls-pemfile 2.2.0",
-  "rustls-pki-types",
-  "serde",
-@@ -5920,6 +6049,8 @@ version = "0.23.21"
- source = "registry+https://github.com/rust-lang/crates.io-index"
- checksum = "8f287924602bf649d949c63dc8ac8b235fa5387d394020705b80c4eb597ce5b8"
- dependencies = [
-+ "aws-lc-rs",
-+ "log",
-  "once_cell",
-  "ring 0.17.8",
-  "rustls-pki-types",
-@@ -5937,7 +6068,7 @@ dependencies = [
-  "openssl-probe",
-  "rustls-pemfile 1.0.4",
-  "schannel",
-- "security-framework",
-+ "security-framework 2.11.1",
- ]
- 
- [[package]]
-@@ -5950,7 +6081,19 @@ dependencies = [
-  "rustls-pemfile 2.2.0",
-  "rustls-pki-types",
-  "schannel",
-- "security-framework",
-+ "security-framework 2.11.1",
-+]
-+
-+[[package]]
-+name = "rustls-native-certs"
-+version = "0.8.1"
-+source = "registry+https://github.com/rust-lang/crates.io-index"
-+checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3"
-+dependencies = [
-+ "openssl-probe",
-+ "rustls-pki-types",
-+ "schannel",
-+ "security-framework 3.2.0",
- ]
- 
- [[package]]
-@@ -5980,6 +6123,33 @@ dependencies = [
-  "web-time",
- ]
- 
-+[[package]]
-+name = "rustls-platform-verifier"
-+version = "0.5.0"
-+source = "registry+https://github.com/rust-lang/crates.io-index"
-+checksum = "e012c45844a1790332c9386ed4ca3a06def221092eda277e6f079728f8ea99da"
-+dependencies = [
-+ "core-foundation 0.10.0",
-+ "core-foundation-sys",
-+ "jni",
-+ "log",
-+ "once_cell",
-+ "rustls 0.23.21",
-+ "rustls-native-certs 0.8.1",
-+ "rustls-platform-verifier-android",
-+ "rustls-webpki 0.102.8",
-+ "security-framework 3.2.0",
-+ "security-framework-sys",
-+ "webpki-root-certs",
-+ "windows-sys 0.52.0",
-+]
-+
-+[[package]]
-+name = "rustls-platform-verifier-android"
-+version = "0.1.1"
-+source = "registry+https://github.com/rust-lang/crates.io-index"
-+checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f"
-+
- [[package]]
- name = "rustls-webpki"
- version = "0.101.7"
-@@ -5996,6 +6166,7 @@ version = "0.102.8"
- source = "registry+https://github.com/rust-lang/crates.io-index"
- checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9"
- dependencies = [
-+ "aws-lc-rs",
-  "ring 0.17.8",
-  "rustls-pki-types",
-  "untrusted 0.9.0",
-@@ -6125,7 +6296,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
- checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
- dependencies = [
-  "bitflags 2.8.0",
-- "core-foundation",
-+ "core-foundation 0.9.4",
-+ "core-foundation-sys",
-+ "libc",
-+ "security-framework-sys",
-+]
-+
-+[[package]]
-+name = "security-framework"
-+version = "3.2.0"
-+source = "registry+https://github.com/rust-lang/crates.io-index"
-+checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316"
-+dependencies = [
-+ "bitflags 2.8.0",
-+ "core-foundation 0.10.0",
-  "core-foundation-sys",
-  "libc",
-  "security-framework-sys",
-@@ -6817,7 +7001,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
- checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
- dependencies = [
-  "bitflags 1.3.2",
-- "core-foundation",
-+ "core-foundation 0.9.4",
-  "system-configuration-sys",
- ]
- 
-@@ -7569,6 +7753,7 @@ dependencies = [
-  "rustls 0.23.21",
-  "rustls-pemfile 2.2.0",
-  "rustls-pki-types",
-+ "rustls-platform-verifier",
-  "serde",
-  "serde_json",
-  "smtp-proto",
-@@ -7764,6 +7949,15 @@ dependencies = [
-  "untrusted 0.9.0",
- ]
- 
-+[[package]]
-+name = "webpki-root-certs"
-+version = "0.26.8"
-+source = "registry+https://github.com/rust-lang/crates.io-index"
-+checksum = "09aed61f5e8d2c18344b3faa33a4c837855fe56642757754775548fee21386c4"
-+dependencies = [
-+ "rustls-pki-types",
-+]
-+
- [[package]]
- name = "webpki-roots"
- version = "0.25.4"
-@@ -7789,6 +7983,18 @@ dependencies = [
-  "once_cell",
- ]
- 
-+[[package]]
-+name = "which"
-+version = "4.4.2"
-+source = "registry+https://github.com/rust-lang/crates.io-index"
-+checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
-+dependencies = [
-+ "either",
-+ "home",
-+ "once_cell",
-+ "rustix",
-+]
-+
- [[package]]
- name = "whoami"
- version = "1.5.2"
-@@ -7886,6 +8092,15 @@ dependencies = [
-  "windows-targets 0.52.6",
- ]
- 
-+[[package]]
-+name = "windows-sys"
-+version = "0.45.0"
-+source = "registry+https://github.com/rust-lang/crates.io-index"
-+checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
-+dependencies = [
-+ "windows-targets 0.42.2",
-+]
-+
- [[package]]
- name = "windows-sys"
- version = "0.48.0"
-@@ -7913,6 +8128,21 @@ dependencies = [
-  "windows-targets 0.52.6",
- ]
- 
-+[[package]]
-+name = "windows-targets"
-+version = "0.42.2"
-+source = "registry+https://github.com/rust-lang/crates.io-index"
-+checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
-+dependencies = [
-+ "windows_aarch64_gnullvm 0.42.2",
-+ "windows_aarch64_msvc 0.42.2",
-+ "windows_i686_gnu 0.42.2",
-+ "windows_i686_msvc 0.42.2",
-+ "windows_x86_64_gnu 0.42.2",
-+ "windows_x86_64_gnullvm 0.42.2",
-+ "windows_x86_64_msvc 0.42.2",
-+]
-+
- [[package]]
- name = "windows-targets"
- version = "0.48.5"
-@@ -7944,6 +8174,12 @@ dependencies = [
-  "windows_x86_64_msvc 0.52.6",
- ]
- 
-+[[package]]
-+name = "windows_aarch64_gnullvm"
-+version = "0.42.2"
-+source = "registry+https://github.com/rust-lang/crates.io-index"
-+checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
-+
- [[package]]
- name = "windows_aarch64_gnullvm"
- version = "0.48.5"
-@@ -7956,6 +8192,12 @@ version = "0.52.6"
- source = "registry+https://github.com/rust-lang/crates.io-index"
- checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
- 
-+[[package]]
-+name = "windows_aarch64_msvc"
-+version = "0.42.2"
-+source = "registry+https://github.com/rust-lang/crates.io-index"
-+checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
-+
- [[package]]
- name = "windows_aarch64_msvc"
- version = "0.48.5"
-@@ -7968,6 +8210,12 @@ version = "0.52.6"
- source = "registry+https://github.com/rust-lang/crates.io-index"
- checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
- 
-+[[package]]
-+name = "windows_i686_gnu"
-+version = "0.42.2"
-+source = "registry+https://github.com/rust-lang/crates.io-index"
-+checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
-+
- [[package]]
- name = "windows_i686_gnu"
- version = "0.48.5"
-@@ -7986,6 +8234,12 @@ version = "0.52.6"
- source = "registry+https://github.com/rust-lang/crates.io-index"
- checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
- 
-+[[package]]
-+name = "windows_i686_msvc"
-+version = "0.42.2"
-+source = "registry+https://github.com/rust-lang/crates.io-index"
-+checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
-+
- [[package]]
- name = "windows_i686_msvc"
- version = "0.48.5"
-@@ -7998,6 +8252,12 @@ version = "0.52.6"
- source = "registry+https://github.com/rust-lang/crates.io-index"
- checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
- 
-+[[package]]
-+name = "windows_x86_64_gnu"
-+version = "0.42.2"
-+source = "registry+https://github.com/rust-lang/crates.io-index"
-+checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
-+
- [[package]]
- name = "windows_x86_64_gnu"
- version = "0.48.5"
-@@ -8010,6 +8270,12 @@ version = "0.52.6"
- source = "registry+https://github.com/rust-lang/crates.io-index"
- checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
- 
-+[[package]]
-+name = "windows_x86_64_gnullvm"
-+version = "0.42.2"
-+source = "registry+https://github.com/rust-lang/crates.io-index"
-+checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
-+
- [[package]]
- name = "windows_x86_64_gnullvm"
- version = "0.48.5"
-@@ -8022,6 +8288,12 @@ version = "0.52.6"
- source = "registry+https://github.com/rust-lang/crates.io-index"
- checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
- 
-+[[package]]
-+name = "windows_x86_64_msvc"
-+version = "0.42.2"
-+source = "registry+https://github.com/rust-lang/crates.io-index"
-+checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
-+
- [[package]]
- name = "windows_x86_64_msvc"
- version = "0.48.5"
-diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml
-index a2d19a06..76866b80 100644
---- a/crates/cli/Cargo.toml
-+++ b/crates/cli/Cargo.toml
-@@ -13,7 +13,7 @@ resolver = "2"
- [dependencies]
- jmap-client = { version = "0.3", features = ["async"] } 
- mail-parser = { version = "0.10", features = ["full_encoding", "serde_support"] } 
--reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "http2"]}
-+reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-native-roots", "http2"]}
- tokio = { version = "1.23", features = ["full"] }
- num_cpus = "1.13.1"
- clap = { version = "4.1.6", features = ["derive"] }
-diff --git a/crates/common/Cargo.toml b/crates/common/Cargo.toml
-index 3da0183f..93c49bb5 100644
---- a/crates/common/Cargo.toml
-+++ b/crates/common/Cargo.toml
-@@ -16,7 +16,7 @@ sieve-rs = { version = "0.6" }
- mail-parser = { version = "0.10", features = ["full_encoding"] } 
- mail-builder = { version = "0.4" }
- mail-auth = { version = "0.6" }
--mail-send = { version = "0.5", default-features = false, features = ["cram-md5", "ring", "tls12"] }
-+mail-send = { path = "../mail-send", default-features = false, features = ["cram-md5", "ring", "tls12"] }
- smtp-proto = { version = "0.1", features = ["serde_support"] }
- dns-update = { version = "0.1" }
- ahash = { version = "0.8.2", features = ["serde"] }
-@@ -32,7 +32,7 @@ tokio = { version = "1.23", features = ["net", "macros"] }
- tokio-rustls = { version = "0.26", default-features = false, features = ["ring", "tls12"] }
- futures = "0.3"
- rcgen = "0.12"
--reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "http2", "stream"]}
-+reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-native-roots", "http2", "stream"]}
- serde = { version = "1.0", features = ["derive"]}
- serde_json = "1.0"
- base64 = "0.22"
-diff --git a/crates/directory/Cargo.toml b/crates/directory/Cargo.toml
-index dc022e7a..10e0c00a 100644
---- a/crates/directory/Cargo.toml
-+++ b/crates/directory/Cargo.toml
-@@ -12,7 +12,7 @@ trc = { path = "../trc" }
- jmap_proto = { path =  "../jmap-proto" }
- smtp-proto = { version = "0.1" }
- mail-parser = { version = "0.10", features = ["full_encoding", "serde_support"] } 
--mail-send = { version = "0.5", default-features = false, features = ["cram-md5", "ring", "tls12"] }
-+mail-send = { path = "../mail-send", default-features = false, features = ["cram-md5", "ring", "tls12"] }
- mail-builder = { version = "0.4" }
- tokio = { version = "1.23", features = ["net"] }
- tokio-rustls = { version = "0.26", default-features = false, features = ["ring", "tls12"] }
-@@ -34,7 +34,7 @@ futures = "0.3"
- regex = "1.7.0"
- serde = { version = "1.0", features = ["derive"]}
- totp-rs = { version = "5.5.1", features = ["otpauth"] }
--reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "http2"] }
-+reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-native-roots", "http2"] }
- serde_json = "1.0"
- base64 = "0.22"
- 
-diff --git a/crates/imap/Cargo.toml b/crates/imap/Cargo.toml
-index 640ca4fd..d91931c1 100644
---- a/crates/imap/Cargo.toml
-+++ b/crates/imap/Cargo.toml
-@@ -16,7 +16,7 @@ email = { path = "../email" }
- nlp = { path = "../nlp" }
- utils = { path = "../utils" }
- mail-parser = { version = "0.10", features = ["full_encoding"] } 
--mail-send = { version = "0.5", default-features = false, features = ["cram-md5", "ring", "tls12"] }
-+mail-send = { path = "../mail-send", default-features = false, features = ["cram-md5", "ring", "tls12"] }
- rustls = { version = "0.23.5", default-features = false, features = ["std", "ring", "tls12"] }
- rustls-pemfile = "2.0"
- tokio = { version = "1.23", features = ["full"] }
-diff --git a/crates/jmap/Cargo.toml b/crates/jmap/Cargo.toml
-index 7be56e44..ad5ed795 100644
---- a/crates/jmap/Cargo.toml
-+++ b/crates/jmap/Cargo.toml
-@@ -18,7 +18,7 @@ email = { path = "../email" }
- smtp-proto = { version = "0.1" }
- mail-parser = { version = "0.10", features = ["full_encoding", "serde_support"] } 
- mail-builder = { version = "0.4" }
--mail-send = { version = "0.5", default-features = false, features = ["cram-md5", "ring", "tls12"] }
-+mail-send = { path = "../mail-send", default-features = false, features = ["cram-md5", "ring", "tls12"] }
- mail-auth = { version = "0.6", features = ["generate"] }
- sieve-rs = { version = "0.6" } 
- serde = { version = "1.0", features = ["derive"]}
-@@ -38,7 +38,7 @@ p256 = { version = "0.13", features = ["ecdh"] }
- hkdf = "0.12.3"
- sha1 = "0.10"
- sha2 = "0.10"
--reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "http2"]}
-+reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-native-roots", "http2"]}
- tokio-tungstenite = "0.26"
- tungstenite = "0.26"
- chrono = "0.4"
-diff --git a/crates/mail-send/Cargo.toml b/crates/mail-send/Cargo.toml
-index fb5f402d..6760afab 100644
---- a/crates/mail-send/Cargo.toml
-+++ b/crates/mail-send/Cargo.toml
-@@ -27,6 +27,7 @@ rustls = { version = "0.23", default-features = false, features = ["std"]}
- tokio-rustls = { version = "0.26", default-features = false }
- webpki-roots = { version = "0.26"}
- rustls-pki-types = { version = "1" }
-+rustls-platform-verifier = "0.5"
- gethostname = { version = "0.5"}
- 
- [dev-dependencies]
-diff --git a/crates/mail-send/src/smtp/tls.rs b/crates/mail-send/src/smtp/tls.rs
-index b15a6db8..7ddd0798 100644
---- a/crates/mail-send/src/smtp/tls.rs
-+++ b/crates/mail-send/src/smtp/tls.rs
-@@ -12,9 +12,9 @@ use std::{convert::TryFrom, io, sync::Arc};
- 
- use rustls::{
-     client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier},
--    ClientConfig, ClientConnection, RootCertStore, SignatureScheme,
-+    ClientConfig, ClientConnection, SignatureScheme,
- };
--use rustls_pki_types::{ServerName, TrustAnchor};
-+use rustls_pki_types::ServerName;
- use tokio::net::TcpStream;
- use tokio_rustls::{client::TlsStream, TlsConnector};
- 
-@@ -78,20 +78,14 @@ impl SmtpClient<TlsStream<TcpStream>> {
- }
- 
- pub fn build_tls_connector(allow_invalid_certs: bool) -> TlsConnector {
-+    use rustls_platform_verifier::BuilderVerifierExt;
-+
-+    let config = ClientConfig::builder();
-+
-     let config = if !allow_invalid_certs {
--        let mut root_cert_store = RootCertStore::empty();
--
--        root_cert_store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().map(|ta| TrustAnchor {
--            subject: ta.subject.clone(),
--            subject_public_key_info: ta.subject_public_key_info.clone(),
--            name_constraints: ta.name_constraints.clone(),
--        }));
--
--        ClientConfig::builder()
--            .with_root_certificates(root_cert_store)
--            .with_no_client_auth()
-+        config.with_platform_verifier().with_no_client_auth()
-     } else {
--        ClientConfig::builder()
-+        config
-             .dangerous()
-             .with_custom_certificate_verifier(Arc::new(DummyVerifier {}))
-             .with_no_client_auth()
-diff --git a/crates/managesieve/Cargo.toml b/crates/managesieve/Cargo.toml
-index 650ab23b..42738e68 100644
---- a/crates/managesieve/Cargo.toml
-+++ b/crates/managesieve/Cargo.toml
-@@ -15,7 +15,7 @@ store = { path = "../store" }
- utils = { path = "../utils" }
- trc = { path = "../trc" }
- mail-parser = { version = "0.10", features = ["full_encoding"] } 
--mail-send = { version = "0.5", default-features = false, features = ["cram-md5", "ring", "tls12"] }
-+mail-send = { path = "../mail-send", default-features = false, features = ["cram-md5", "ring", "tls12"] }
- sieve-rs = { version = "0.6" } 
- rustls = { version = "0.23.5", default-features = false, features = ["std", "ring", "tls12"] }
- rustls-pemfile = "2.0"
-diff --git a/crates/pop3/Cargo.toml b/crates/pop3/Cargo.toml
-index 5f86ed00..89e7b732 100644
---- a/crates/pop3/Cargo.toml
-+++ b/crates/pop3/Cargo.toml
-@@ -15,7 +15,7 @@ trc = { path = "../trc" }
- jmap_proto = { path = "../jmap-proto" }
- email = { path = "../email" }
- mail-parser = { version = "0.10", features = ["full_encoding"] } 
--mail-send = { version = "0.5", default-features = false, features = ["cram-md5", "ring", "tls12"] }
-+mail-send = { path = "../mail-send", default-features = false, features = ["cram-md5", "ring", "tls12"] }
- rustls = { version = "0.23.5", default-features = false, features = ["std", "ring", "tls12"] }
- tokio = { version = "1.23", features = ["full"] }
- tokio-rustls = { version = "0.26", default-features = false, features = ["ring", "tls12"] }
-diff --git a/crates/smtp/Cargo.toml b/crates/smtp/Cargo.toml
-index 5997c1c3..5f5badc2 100644
---- a/crates/smtp/Cargo.toml
-+++ b/crates/smtp/Cargo.toml
-@@ -21,7 +21,7 @@ email = { path =  "../email" }
- spam-filter = { path =  "../spam-filter" }
- trc = { path = "../trc" }
- mail-auth = { version = "0.6" }
--mail-send = { version = "0.5", default-features = false, features = ["cram-md5", "ring", "tls12"] }
-+mail-send = { path = "../mail-send", default-features = false, features = ["cram-md5", "ring", "tls12"] }
- mail-parser = { version = "0.10", features = ["full_encoding"] } 
- mail-builder = { version = "0.4" } 
- smtp-proto = { version = "0.1", features = ["serde_support"] }
-@@ -47,7 +47,7 @@ blake3 = "1.3"
- lru-cache = "0.1.2"
- rand = "0.8.5"
- x509-parser = "0.16.0"
--reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "http2"] }
-+reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-native-roots", "http2"] }
- serde = { version = "1.0", features = ["derive", "rc"] }
- serde_json = "1.0"
- num_cpus = "1.15.0"
-diff --git a/crates/spam-filter/Cargo.toml b/crates/spam-filter/Cargo.toml
-index f5b63353..c9176cf6 100644
---- a/crates/spam-filter/Cargo.toml
-+++ b/crates/spam-filter/Cargo.toml
-@@ -14,12 +14,12 @@ smtp-proto = { version = "0.1", features = ["serde_support"] }
- mail-parser = { version = "0.10", features = ["full_encoding"] } 
- mail-builder = { version = "0.4" }
- mail-auth = { version = "0.6" }
--mail-send = { version = "0.5", default-features = false, features = ["cram-md5", "ring", "tls12"] }
-+mail-send = { path = "../mail-send", default-features = false, features = ["cram-md5", "ring", "tls12"] }
- tokio = { version = "1.23", features = ["net", "macros"] }
- psl = "2"
- hyper = { version = "1.0.1", features = ["server", "http1", "http2"] }
- idna = "1.0"
--reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "http2", "stream"]}
-+reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-native-roots", "http2", "stream"]}
- decancer = "3.0.1"
- unicode-security = "0.1.0"
- infer = "0.16"
-diff --git a/crates/store/Cargo.toml b/crates/store/Cargo.toml
-index b0cf7d77..67c2d742 100644
---- a/crates/store/Cargo.toml
-+++ b/crates/store/Cargo.toml
-@@ -15,7 +15,7 @@ rust-s3 = { version = "=0.35.0-alpha.2", default-features = false, features = ["
- azure_core = { version = "0.21.0", optional = true }
- azure_storage = { version = "0.21.0", default-features = false, features = ["enable_reqwest_rustls", "hmac_rust"], optional = true }
- azure_storage_blobs = { version = "0.21.0", default-features = false, features = ["enable_reqwest_rustls", "hmac_rust"], optional = true }
--reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "http2", "stream"]}
-+reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-native-roots", "http2", "stream"]}
- tokio = { version = "1.23", features = ["sync", "fs", "io-util"] }
- r2d2 = { version = "0.8.10", optional = true }
- futures = { version = "0.3", optional = true }
-diff --git a/crates/trc/Cargo.toml b/crates/trc/Cargo.toml
-index e4f2ca7c..f294e469 100644
---- a/crates/trc/Cargo.toml
-+++ b/crates/trc/Cargo.toml
-@@ -11,7 +11,7 @@ mail-parser = { version = "0.10", features = ["full_encoding"] }
- base64 = "0.22.1"
- serde = "1.0"
- serde_json = "1.0.120"
--reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "http2"]}
-+reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-native-roots", "http2"]}
- bincode = "1.3.3"
- rtrb = "0.3.1"
- parking_lot = "0.12.3"
-diff --git a/crates/utils/Cargo.toml b/crates/utils/Cargo.toml
-index e0a7ef9d..14b1d675 100644
---- a/crates/utils/Cargo.toml
-+++ b/crates/utils/Cargo.toml
-@@ -9,12 +9,13 @@ trc = { path = "../trc" }
- rustls = { version = "0.23.5", default-features = false, features = ["std", "ring", "tls12"] }
- rustls-pemfile = "2.0"
- rustls-pki-types = { version = "1" }
-+rustls-platform-verifier = "0.5"
- tokio = { version = "1.23", features = ["net", "macros"] }
- tokio-rustls = { version = "0.26", default-features = false, features = ["ring", "tls12"] }
- serde = { version = "1.0", features = ["derive"]}
- mail-auth = { version = "0.6" }
- smtp-proto = { version = "0.1" }
--mail-send = { version = "0.5", default-features = false, features = ["cram-md5", "ring", "tls12"] }
-+mail-send = { path = "../mail-send", default-features = false, features = ["cram-md5", "ring", "tls12"] }
- ahash = { version = "0.8" }
- chrono = "0.4"
- rand = "0.8.5"
-@@ -23,7 +24,7 @@ ring = { version = "0.17" }
- base64 = "0.22"
- serde_json = "1.0"
- rcgen = "0.13"
--reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "http2", "stream"]}
-+reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-native-roots", "http2", "stream"]}
- x509-parser = "0.16.0"
- pem = "3.0"
- parking_lot = "0.12"
-diff --git a/crates/utils/src/lib.rs b/crates/utils/src/lib.rs
-index acec2f04..b2cdaf65 100644
---- a/crates/utils/src/lib.rs
-+++ b/crates/utils/src/lib.rs
-@@ -18,9 +18,9 @@ use futures::StreamExt;
- use reqwest::Response;
- use rustls::{
-     client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier},
--    ClientConfig, RootCertStore, SignatureScheme,
-+    ClientConfig, SignatureScheme,
- };
--use rustls_pki_types::TrustAnchor;
-+use rustls_platform_verifier::BuilderVerifierExt;
- 
- pub const BLOB_HASH_LEN: usize = 32;
- 
-@@ -280,17 +280,7 @@ pub fn rustls_client_config(allow_invalid_certs: bool) -> ClientConfig {
-     let config = ClientConfig::builder();
- 
-     if !allow_invalid_certs {
--        let mut root_cert_store = RootCertStore::empty();
--
--        root_cert_store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().map(|ta| TrustAnchor {
--            subject: ta.subject.clone(),
--            subject_public_key_info: ta.subject_public_key_info.clone(),
--            name_constraints: ta.name_constraints.clone(),
--        }));
--
--        config
--            .with_root_certificates(root_cert_store)
--            .with_no_client_auth()
-+        config.with_platform_verifier().with_no_client_auth()
-     } else {
-         config
-             .dangerous()
-diff --git a/tests/Cargo.toml b/tests/Cargo.toml
-index 6aa6d35b..256a574b 100644
---- a/tests/Cargo.toml
-+++ b/tests/Cargo.toml
-@@ -34,12 +34,12 @@ spam-filter = { path = "../crates/spam-filter", features = ["test_mode", "enterp
- trc = { path = "../crates/trc" }
- managesieve = { path = "../crates/managesieve", features = ["test_mode", "enterprise"] }
- smtp-proto = { version = "0.1" }
--mail-send = { version = "0.5", default-features = false, features = ["cram-md5", "ring", "tls12"] }
-+mail-send = { path = "../crates/mail-send", default-features = false, features = ["cram-md5", "ring", "tls12"] }
- mail-auth = { version = "0.6", features = ["test"] }
--sieve-rs = { version = "0.6" } 
-+sieve-rs = { version = "0.6" }
- utils = { path = "../crates/utils", features = ["test_mode"] }
--jmap-client = { version = "0.3", features = ["websockets", "debug", "async"] } 
--mail-parser = { version = "0.10", features = ["full_encoding", "serde_support"] } 
-+jmap-client = { version = "0.3", features = ["websockets", "debug", "async"] }
-+mail-parser = { version = "0.10", features = ["full_encoding", "serde_support"] }
- tokio = { version = "1.23", features = ["full"] }
- tokio-rustls = { version = "0.26", default-features = false, features = ["ring", "tls12"] }
- rustls = { version = "0.23.5", default-features = false, features = ["std", "ring", "tls12"] }
-@@ -50,7 +50,7 @@ rayon = { version = "1.5.1" }
- flate2 = { version = "1.0.17", features = ["zlib"], default-features = false }
- serde = { version = "1.0", features = ["derive"]}
- serde_json = "1.0"
--reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "multipart", "http2"]}
-+reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-native-roots", "multipart", "http2"]}
- bytes = "1.4.0"
- futures = "0.3"
- ece = "2.2"
--- 
-2.47.2
-
diff --git a/pkgs/by-name/st/stalwart-mail-patched/patches/use-platform-ca-roots.patch b/pkgs/by-name/st/stalwart-mail-patched/patches/use-platform-ca-roots.patch
new file mode 100644
index 0000000..392fbde
--- /dev/null
+++ b/pkgs/by-name/st/stalwart-mail-patched/patches/use-platform-ca-roots.patch
@@ -0,0 +1,747 @@
+From 66227b07c6cb4781a38fe603c2e856c5696e0f94 Mon Sep 17 00:00:00 2001
+From: aszlig <aszlig@nix.build>
+Date: Wed, 21 May 2025 19:03:55 +0200
+Subject: [PATCH] Allow to switch to operating system CA root store
+
+So far, we only used the root CA certificates from the "webpki-roots"
+crate, which makes it very difficult if you want to run a custom CA.
+
+In my case I'm running automated tests of full production systems, which
+also includes an ACME setup that injects a Pebble instance into the
+system's CA certificates.
+
+Since Stalwart doesn't use the system's root CA certificate store, it's
+very difficult to inject the certificate for the Pebble instance.
+
+Given that there's also some interest (issue #247) for doing this in an
+enterprise environment with intranet CAs, I decided to generalise this
+far enough that it can not only be used in my downstream setup.
+
+Currently, this doesn't fully address the issue, since in the long term
+this might be something we'd want to configure at runtime, as per
+@mdecimus's comment[1]:
+
+> A slightly more complex approach is required that allows the user to
+> select at runtime which CA store to use.
+
+However, this makes it at least easier to switch to native root CA store
+by simply recompiling with the "tls-native-roots" feature.
+
+[1]: https://github.com/stalwartlabs/stalwart/issues/247#issuecomment-2437039500
+
+Signed-off-by: aszlig <aszlig@nix.build>
+Issue: https://github.com/stalwartlabs/stalwart/issues/247
+---
+ Cargo.lock                                   |  4 ++
+ crates/cli/Cargo.toml                        | 10 +++--
+ crates/cli/src/main.rs                       |  8 ++--
+ crates/common/Cargo.toml                     |  2 +-
+ crates/common/src/enterprise/llm.rs          |  2 +-
+ crates/common/src/enterprise/mod.rs          | 18 +++++---
+ crates/common/src/lib.rs                     |  3 +-
+ crates/common/src/listener/acme/directory.rs |  6 +--
+ crates/common/src/manager/mod.rs             |  2 +-
+ crates/common/src/scripts/plugins/http.rs    |  2 +-
+ crates/common/src/telemetry/webhooks/mod.rs  |  2 +-
+ crates/directory/Cargo.toml                  |  2 +-
+ crates/directory/src/backend/oidc/lookup.rs  |  4 +-
+ crates/jmap/Cargo.toml                       |  2 +-
+ crates/main/Cargo.toml                       |  1 +
+ crates/services/Cargo.toml                   |  2 +-
+ crates/services/src/state_manager/http.rs    |  2 +-
+ crates/smtp/Cargo.toml                       |  2 +-
+ crates/smtp/src/inbound/hooks/client.rs      |  2 +-
+ crates/smtp/src/outbound/mta_sts/lookup.rs   |  3 +-
+ crates/smtp/src/reporting/tls.rs             |  5 +--
+ crates/spam-filter/Cargo.toml                |  2 +-
+ crates/spam-filter/src/analysis/url.rs       |  2 +-
+ crates/store/Cargo.toml                      |  2 +-
+ crates/store/src/backend/azure/mod.rs        |  2 +-
+ crates/store/src/backend/http/lookup.rs      |  2 +-
+ crates/trc/Cargo.toml                        |  2 +-
+ crates/utils/Cargo.toml                      |  2 +
+ crates/utils/src/lib.rs                      | 46 ++++++++++++++------
+ crates/utils/src/suffixlist.rs               |  7 ++-
+ tests/Cargo.toml                             |  2 +-
+ tests/src/jmap/auth_oauth.rs                 |  6 +--
+ tests/src/jmap/mod.rs                        |  4 +-
+ tests/src/smtp/management/queue.rs           |  2 +-
+ tests/src/webdav/mod.rs                      |  2 +-
+ 35 files changed, 103 insertions(+), 64 deletions(-)
+
+diff --git a/Cargo.lock b/Cargo.lock
+index 0eeb42510..6dd394dc3 100644
+--- a/Cargo.lock
++++ b/Cargo.lock
+@@ -3372,6 +3372,7 @@ dependencies = [
+  "hyper 1.6.0",
+  "hyper-util",
+  "rustls 0.23.27",
++ "rustls-native-certs 0.8.1",
+  "rustls-pki-types",
+  "tokio",
+  "tokio-rustls 0.26.2",
+@@ -6318,6 +6319,7 @@ dependencies = [
+  "pin-project-lite",
+  "quinn",
+  "rustls 0.23.27",
++ "rustls-native-certs 0.8.1",
+  "rustls-pemfile 2.2.0",
+  "rustls-pki-types",
+  "serde",
+@@ -7694,6 +7696,7 @@ dependencies = [
+  "serde",
+  "serde_json",
+  "tokio",
++ "utils",
+ ]
+ 
+ [[package]]
+@@ -8795,6 +8798,7 @@ dependencies = [
+  "rustls 0.23.27",
+  "rustls-pemfile 2.2.0",
+  "rustls-pki-types",
++ "rustls-platform-verifier",
+  "serde",
+  "serde_json",
+  "smtp-proto",
+diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml
+index 5573df819..719441a0c 100644
+--- a/crates/cli/Cargo.toml
++++ b/crates/cli/Cargo.toml
+@@ -11,9 +11,9 @@ readme = "README.md"
+ resolver = "2"
+ 
+ [dependencies]
+-jmap-client = { version = "0.3", features = ["async"] } 
+-mail-parser = { version = "0.11", features = ["full_encoding", "serde"] } 
+-reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "http2"]}
++jmap-client = { version = "0.3", features = ["async"] }
++mail-parser = { version = "0.11", features = ["full_encoding", "serde"] }
++reqwest = { version = "0.12", default-features = false, features = ["http2"]}
+ tokio = { version = "1.45", features = ["full"] }
+ num_cpus = "1.13.1"
+ clap = { version = "4.1.6", features = ["derive"] }
+@@ -30,3 +30,7 @@ futures = "0.3.28"
+ pwhash = "1.0.0"
+ rand = "0.9.0"
+ mail-auth = { version = "0.7" }
++utils.path = "../utils"
++
++[features]
++tls-native-roots = ["utils/tls-native-roots"]
+diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs
+index f295c217f..f62d528c5 100644
+--- a/crates/cli/src/main.rs
++++ b/crates/cli/src/main.rs
+@@ -86,7 +86,7 @@ fn parse_credentials(credentials: &str) -> Credentials {
+ 
+ async fn oauth(url: &str) -> Credentials {
+     let metadata: HashMap<String, serde_json::Value> = serde_json::from_slice(
+-        &reqwest::Client::builder()
++        &utils::reqwest_client_builder()
+             .danger_accept_invalid_certs(is_localhost(url))
+             .build()
+             .unwrap_or_default()
+@@ -104,7 +104,7 @@ async fn oauth(url: &str) -> Credentials {
+     let mut params: HashMap<String, String> =
+         HashMap::from_iter([("client_id".to_string(), "Stalwart_CLI".to_string())]);
+     let response: HashMap<String, serde_json::Value> = serde_json::from_slice(
+-        &reqwest::Client::builder()
++        &utils::reqwest_client_builder()
+             .danger_accept_invalid_certs(is_localhost(url))
+             .build()
+             .unwrap_or_default()
+@@ -138,7 +138,7 @@ async fn oauth(url: &str) -> Credentials {
+     std::io::stdin().lock().lines().next();
+ 
+     let mut response: HashMap<String, serde_json::Value> = serde_json::from_slice(
+-        &reqwest::Client::builder()
++        &utils::reqwest_client_builder()
+             .danger_accept_invalid_certs(is_localhost(url))
+             .build()
+             .unwrap_or_default()
+@@ -230,7 +230,7 @@ impl Client {
+             },
+             url
+         );
+-        let mut request = reqwest::Client::builder()
++        let mut request = utils::reqwest_client_builder()
+             .danger_accept_invalid_certs(is_localhost(&url))
+             .timeout(Duration::from_secs(self.timeout.unwrap_or(60)))
+             .build()
+diff --git a/crates/common/Cargo.toml b/crates/common/Cargo.toml
+index 58028bad3..5add0a5dc 100644
+--- a/crates/common/Cargo.toml
++++ b/crates/common/Cargo.toml
+@@ -33,7 +33,7 @@ tokio = { version = "1.45", features = ["net", "macros"] }
+ tokio-rustls = { version = "0.26", default-features = false, features = ["ring", "tls12"] }
+ futures = "0.3"
+ rcgen = "0.12"
+-reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "http2", "stream"]}
++reqwest = { version = "0.12", default-features = false, features = ["http2", "stream"]}
+ serde = { version = "1.0", features = ["derive"]}
+ serde_json = "1.0"
+ base64 = "0.22"
+diff --git a/crates/common/src/enterprise/llm.rs b/crates/common/src/enterprise/llm.rs
+index 8338f39d3..fe013c0f0 100644
+--- a/crates/common/src/enterprise/llm.rs
++++ b/crates/common/src/enterprise/llm.rs
+@@ -125,7 +125,7 @@ impl AiApiConfig {
+         };
+ 
+         // Send request
+-        let response = reqwest::Client::builder()
++        let response = utils::reqwest_client_builder()
+             .timeout(self.timeout)
+             .danger_accept_invalid_certs(self.tls_allow_invalid_certs)
+             .build()
+diff --git a/crates/common/src/enterprise/mod.rs b/crates/common/src/enterprise/mod.rs
+index 9fc8de495..ddaf27880 100644
+--- a/crates/common/src/enterprise/mod.rs
++++ b/crates/common/src/enterprise/mod.rs
+@@ -188,12 +188,18 @@ impl Server {
+ 
+                 let mut logo = None;
+                 if let Some(logo_url) = logo_url {
+-                    let response = reqwest::get(logo_url.as_str()).await.map_err(|err| {
+-                        trc::ResourceEvent::DownloadExternal
+-                            .into_err()
+-                            .details("Failed to download logo")
+-                            .reason(err)
+-                    })?;
++                    let response = utils::reqwest_client_builder()
++                        .build()
++                        .unwrap_or_default()
++                        .get(logo_url.as_str())
++                        .send()
++                        .await
++                        .map_err(|err| {
++                            trc::ResourceEvent::DownloadExternal
++                                .into_err()
++                                .details("Failed to download logo")
++                                .reason(err)
++                        })?;
+ 
+                     let content_type = response
+                         .headers()
+diff --git a/crates/common/src/lib.rs b/crates/common/src/lib.rs
+index ce4b41b89..185508d1f 100644
+--- a/crates/common/src/lib.rs
++++ b/crates/common/src/lib.rs
+@@ -46,6 +46,8 @@ use utils::{
+     snowflake::SnowflakeIdGenerator,
+ };
+ 
++pub use utils::USER_AGENT;
++
+ pub mod addresses;
+ pub mod auth;
+ pub mod config;
+@@ -67,7 +69,6 @@ pub use psl;
+ pub static VERSION_PRIVATE: &str = env!("CARGO_PKG_VERSION");
+ pub static VERSION_PUBLIC: &str = "1.0.0";
+ 
+-pub static USER_AGENT: &str = "Stalwart/1.0.0";
+ pub static DAEMON_NAME: &str = concat!("Stalwart v", env!("CARGO_PKG_VERSION"),);
+ pub static PROD_ID: &str = "-//Stalwart Labs Ltd.//Stalwart Server//EN";
+ 
+diff --git a/crates/common/src/listener/acme/directory.rs b/crates/common/src/listener/acme/directory.rs
+index f095e1969..6f9cfa0e0 100644
+--- a/crates/common/src/listener/acme/directory.rs
++++ b/crates/common/src/listener/acme/directory.rs
+@@ -7,7 +7,6 @@ use super::jose::{
+ };
+ use base64::Engine;
+ use base64::engine::general_purpose::URL_SAFE_NO_PAD;
+-use hyper::header::USER_AGENT;
+ use rcgen::{Certificate, CustomExtension, PKCS_ECDSA_P256_SHA256};
+ use reqwest::header::CONTENT_TYPE;
+ use reqwest::{Method, Response};
+@@ -316,7 +315,7 @@ async fn https(
+     body: Option<String>,
+ ) -> trc::Result<Response> {
+     let url = url.as_ref();
+-    let mut builder = reqwest::Client::builder()
++    let mut builder = utils::reqwest_client_builder()
+         .timeout(Duration::from_secs(30))
+         .http1_only();
+ 
+@@ -330,8 +329,7 @@ async fn https(
+     let mut request = builder
+         .build()
+         .map_err(|err| trc::EventType::Acme(trc::AcmeEvent::Error).from_http_error(err))?
+-        .request(method, url)
+-        .header(USER_AGENT, crate::USER_AGENT);
++        .request(method, url);
+ 
+     if let Some(body) = body {
+         request = request
+diff --git a/crates/common/src/manager/mod.rs b/crates/common/src/manager/mod.rs
+index 51861a82c..a59e74b56 100644
+--- a/crates/common/src/manager/mod.rs
++++ b/crates/common/src/manager/mod.rs
+@@ -76,7 +76,7 @@ pub async fn fetch_resource(
+             .await
+             .map_err(|err| format!("Failed to read {path}: {err}"))
+     } else {
+-        let response = reqwest::Client::builder()
++        let response = utils::reqwest_client_builder()
+             .timeout(timeout)
+             .danger_accept_invalid_certs(is_localhost_url(url))
+             .user_agent(USER_AGENT)
+diff --git a/crates/common/src/scripts/plugins/http.rs b/crates/common/src/scripts/plugins/http.rs
+index 42e2af553..54d906e17 100644
+--- a/crates/common/src/scripts/plugins/http.rs
++++ b/crates/common/src/scripts/plugins/http.rs
+@@ -26,7 +26,7 @@ pub async fn exec_header(ctx: PluginContext<'_>) -> trc::Result<Variable> {
+         return Ok(Variable::from(url.split_once("/?").unwrap().1.to_string()));
+     }
+ 
+-    reqwest::Client::builder()
++    utils::reqwest_client_builder()
+         .user_agent(agent.as_ref())
+         .timeout(Duration::from_millis(timeout))
+         .redirect(Policy::none())
+diff --git a/crates/common/src/telemetry/webhooks/mod.rs b/crates/common/src/telemetry/webhooks/mod.rs
+index a70005399..2cebfd81f 100644
+--- a/crates/common/src/telemetry/webhooks/mod.rs
++++ b/crates/common/src/telemetry/webhooks/mod.rs
+@@ -148,7 +148,7 @@ async fn post_webhook_events(
+     }
+ 
+     // Send request
+-    let response = reqwest::Client::builder()
++    let response = utils::reqwest_client_builder()
+         .timeout(settings.timeout)
+         .danger_accept_invalid_certs(settings.tls_allow_invalid_certs)
+         .build()
+diff --git a/crates/directory/Cargo.toml b/crates/directory/Cargo.toml
+index ae8eca025..4a033834b 100644
+--- a/crates/directory/Cargo.toml
++++ b/crates/directory/Cargo.toml
+@@ -35,7 +35,7 @@ futures = "0.3"
+ regex = "1.7.0"
+ serde = { version = "1.0", features = ["derive"]}
+ totp-rs = { version = "5.5.1", features = ["otpauth"] }
+-reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "http2"] }
++reqwest = { version = "0.12", default-features = false, features = ["http2"] }
+ serde_json = "1.0"
+ base64 = "0.22"
+ rkyv = { version = "0.8.10", features = ["little_endian"] }
+diff --git a/crates/directory/src/backend/oidc/lookup.rs b/crates/directory/src/backend/oidc/lookup.rs
+index 755064115..907831a46 100644
+--- a/crates/directory/src/backend/oidc/lookup.rs
++++ b/crates/directory/src/backend/oidc/lookup.rs
+@@ -36,10 +36,10 @@ impl OpenIdDirectory {
+             QueryBy::Credentials(Credentials::OAuthBearer { token }) => {
+                 // Send request
+                 #[cfg(feature = "test_mode")]
+-                let client = reqwest::Client::builder().danger_accept_invalid_certs(true);
++                let client = utils::reqwest_client_builder().danger_accept_invalid_certs(true);
+ 
+                 #[cfg(not(feature = "test_mode"))]
+-                let client = reqwest::Client::builder();
++                let client = utils::reqwest_client_builder();
+ 
+                 let client = client
+                     .timeout(self.config.endpoint_timeout)
+diff --git a/crates/jmap/Cargo.toml b/crates/jmap/Cargo.toml
+index 9d9cfa7d7..a3a7b5003 100644
+--- a/crates/jmap/Cargo.toml
++++ b/crates/jmap/Cargo.toml
+@@ -36,7 +36,7 @@ p256 = { version = "0.13", features = ["ecdh"] }
+ hkdf = "0.12.3"
+ sha1 = "0.10"
+ sha2 = "0.10"
+-reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "http2"]}
++reqwest = { version = "0.12", default-features = false, features = ["http2"]}
+ tokio-tungstenite = "0.26"
+ tungstenite = "0.26"
+ chrono = "0.4"
+diff --git a/crates/main/Cargo.toml b/crates/main/Cargo.toml
+index 1023b73bf..4b39dae29 100644
+--- a/crates/main/Cargo.toml
++++ b/crates/main/Cargo.toml
+@@ -64,3 +64,4 @@ enterprise = [ "jmap/enterprise",
+                "dav/enterprise",
+                "groupware/enterprise",
+                "services/enterprise" ]
++tls-native-roots = ["utils/tls-native-roots"]
+diff --git a/crates/services/Cargo.toml b/crates/services/Cargo.toml
+index 11bb76e5a..35aa0b6cb 100644
+--- a/crates/services/Cargo.toml
++++ b/crates/services/Cargo.toml
+@@ -24,7 +24,7 @@ rsa = "0.9.2"
+ p256 = { version = "0.13", features = ["ecdh"] }
+ hkdf = "0.12.3"
+ sha2 = "0.10"
+-reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "http2"]}
++reqwest = { version = "0.12", default-features = false, features = ["http2"]}
+ base64 = "0.22"
+ compact_str = "0.9.0"
+ 
+diff --git a/crates/services/src/state_manager/http.rs b/crates/services/src/state_manager/http.rs
+index edd01865f..ee26b8482 100644
+--- a/crates/services/src/state_manager/http.rs
++++ b/crates/services/src/state_manager/http.rs
+@@ -63,7 +63,7 @@ pub(crate) async fn http_request(
+     keys: Option<EncryptionKeys>,
+     push_timeout: Duration,
+ ) -> bool {
+-    let client_builder = reqwest::Client::builder().timeout(push_timeout);
++    let client_builder = utils::reqwest_client_builder().timeout(push_timeout);
+ 
+     #[cfg(feature = "test_mode")]
+     let client_builder = client_builder.danger_accept_invalid_certs(true);
+diff --git a/crates/smtp/Cargo.toml b/crates/smtp/Cargo.toml
+index e4a781796..d21665c92 100644
+--- a/crates/smtp/Cargo.toml
++++ b/crates/smtp/Cargo.toml
+@@ -47,7 +47,7 @@ blake3 = "1.3"
+ lru-cache = "0.1.2"
+ rand = "0.9.0"
+ x509-parser = "0.17.0"
+-reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "http2"] }
++reqwest = { version = "0.12", default-features = false, features = ["http2"] }
+ serde = { version = "1.0", features = ["derive", "rc"] }
+ serde_json = "1.0"
+ num_cpus = "1.15.0"
+diff --git a/crates/smtp/src/inbound/hooks/client.rs b/crates/smtp/src/inbound/hooks/client.rs
+index 2e3a9e17c..6bfb40a63 100644
+--- a/crates/smtp/src/inbound/hooks/client.rs
++++ b/crates/smtp/src/inbound/hooks/client.rs
+@@ -13,7 +13,7 @@ pub(super) async fn send_mta_hook_request(
+     mta_hook: &MTAHook,
+     request: Request,
+ ) -> Result<Response, String> {
+-    let response = reqwest::Client::builder()
++    let response = utils::reqwest_client_builder()
+         .timeout(mta_hook.timeout)
+         .danger_accept_invalid_certs(mta_hook.tls_allow_invalid_certs)
+         .build()
+diff --git a/crates/smtp/src/outbound/mta_sts/lookup.rs b/crates/smtp/src/outbound/mta_sts/lookup.rs
+index c8b279c2f..10f2aafeb 100644
+--- a/crates/smtp/src/outbound/mta_sts/lookup.rs
++++ b/crates/smtp/src/outbound/mta_sts/lookup.rs
+@@ -67,8 +67,7 @@ impl MtaStsLookup for Server {
+ 
+         // Fetch policy
+         #[cfg(not(feature = "test_mode"))]
+-        let bytes = reqwest::Client::builder()
+-            .user_agent(common::USER_AGENT)
++        let bytes = utils::reqwest_client_builder()
+             .timeout(timeout)
+             .redirect(reqwest::redirect::Policy::none())
+             .build()?
+diff --git a/crates/smtp/src/reporting/tls.rs b/crates/smtp/src/reporting/tls.rs
+index 28e9fa47b..875f395c8 100644
+--- a/crates/smtp/src/reporting/tls.rs
++++ b/crates/smtp/src/reporting/tls.rs
+@@ -8,7 +8,7 @@ use super::{AggregateTimestamp, SerializedSize};
+ use crate::{queue::RecipientDomain, reporting::SmtpReporting};
+ use ahash::AHashMap;
+ use common::{
+-    Server, USER_AGENT,
++    Server,
+     config::smtp::{
+         report::AggregateFrequency,
+         resolver::{Mode, MxPattern},
+@@ -142,8 +142,7 @@ impl TlsReporting for Server {
+         for uri in &rua {
+             match uri {
+                 ReportUri::Http(uri) => {
+-                    if let Ok(client) = reqwest::Client::builder()
+-                        .user_agent(USER_AGENT)
++                    if let Ok(client) = utils::reqwest_client_builder()
+                         .timeout(Duration::from_secs(2 * 60))
+                         .build()
+                     {
+diff --git a/crates/spam-filter/Cargo.toml b/crates/spam-filter/Cargo.toml
+index f6ec739a8..5a3df8453 100644
+--- a/crates/spam-filter/Cargo.toml
++++ b/crates/spam-filter/Cargo.toml
+@@ -19,7 +19,7 @@ tokio = { version = "1.45", features = ["net", "macros"] }
+ psl = "2"
+ hyper = { version = "1.0.1", features = ["server", "http1", "http2"] }
+ idna = "1.0"
+-reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "http2", "stream"]}
++reqwest = { version = "0.12", default-features = false, features = ["http2", "stream"]}
+ decancer = "3.0.1"
+ unicode-security = "0.1.0"
+ infer = "0.19"
+diff --git a/crates/spam-filter/src/analysis/url.rs b/crates/spam-filter/src/analysis/url.rs
+index a0d663917..e6377f13c 100644
+--- a/crates/spam-filter/src/analysis/url.rs
++++ b/crates/spam-filter/src/analysis/url.rs
+@@ -290,7 +290,7 @@ async fn http_get_header(
+             Ok(None)
+         };
+     }
+-    reqwest::Client::builder()
++    utils::reqwest_client_builder()
+         .user_agent("Mozilla/5.0 (X11; Linux i686; rv:109.0) Gecko/20100101 Firefox/118.0")
+         .timeout(timeout)
+         .redirect(Policy::none())
+diff --git a/crates/store/Cargo.toml b/crates/store/Cargo.toml
+index 1f8965049..3bd1a228c 100644
+--- a/crates/store/Cargo.toml
++++ b/crates/store/Cargo.toml
+@@ -16,7 +16,7 @@ async-nats = { version = "0.40", default-features = false, features = ["server_2
+ azure_core = { version = "0.21.0", optional = true }
+ azure_storage = { version = "0.21.0", default-features = false, features = ["enable_reqwest_rustls", "hmac_rust"], optional = true }
+ azure_storage_blobs = { version = "0.21.0", default-features = false, features = ["enable_reqwest_rustls", "hmac_rust"], optional = true }
+-reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "http2", "stream"]}
++reqwest = { version = "0.12", default-features = false, features = ["http2", "stream"]}
+ tokio = { version = "1.45", features = ["sync", "fs", "io-util"] }
+ r2d2 = { version = "0.8.10", optional = true }
+ futures = { version = "0.3", optional = true }
+diff --git a/crates/store/src/backend/azure/mod.rs b/crates/store/src/backend/azure/mod.rs
+index 8bbaea073..fbdb03eb7 100644
+--- a/crates/store/src/backend/azure/mod.rs
++++ b/crates/store/src/backend/azure/mod.rs
+@@ -63,7 +63,7 @@ impl AzureStore {
+         let timeout = config
+             .property_or_default::<Duration>((&prefix, "timeout"), "30s")
+             .unwrap_or_else(|| Duration::from_secs(30));
+-        let transport = match reqwest::Client::builder().timeout(timeout).build() {
++        let transport = match utils::reqwest_client_builder().timeout(timeout).build() {
+             Ok(client) => Arc::new(client),
+             Err(err) => {
+                 config.new_build_error(
+diff --git a/crates/store/src/backend/http/lookup.rs b/crates/store/src/backend/http/lookup.rs
+index dbaa932ed..ff7cca2d8 100644
+--- a/crates/store/src/backend/http/lookup.rs
++++ b/crates/store/src/backend/http/lookup.rs
+@@ -91,7 +91,7 @@ impl HttpStore {
+     async fn try_refresh(&self) -> trc::Result<AHashMap<String, Value<'static>>> {
+         let time = Instant::now();
+         let agent = BROWSER_USER_AGENTS.choose(&mut rand::rng()).unwrap();
+-        let response = reqwest::Client::builder()
++        let response = utils::reqwest_client_builder()
+             .timeout(self.config.timeout)
+             .user_agent(*agent)
+             .build()
+diff --git a/crates/trc/Cargo.toml b/crates/trc/Cargo.toml
+index 61d1cd69a..22d8e6599 100644
+--- a/crates/trc/Cargo.toml
++++ b/crates/trc/Cargo.toml
+@@ -11,7 +11,7 @@ mail-parser = { version = "0.11", features = ["full_encoding"] }
+ base64 = "0.22.1"
+ serde = "1.0"
+ serde_json = "1.0.120"
+-reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "http2"]}
++reqwest = { version = "0.12", default-features = false, features = ["http2"]}
+ rtrb = "0.3.1"
+ parking_lot = "0.12.3"
+ tokio = { version = "1.45", features = ["net", "macros"] }
+diff --git a/crates/utils/Cargo.toml b/crates/utils/Cargo.toml
+index 4766c55b5..f45780d24 100644
+--- a/crates/utils/Cargo.toml
++++ b/crates/utils/Cargo.toml
+@@ -9,6 +9,7 @@ trc = { path = "../trc" }
+ rustls = { version = "0.23.5", default-features = false, features = ["std", "ring", "tls12"] }
+ rustls-pemfile = "2.0"
+ rustls-pki-types = { version = "1" }
++rustls-platform-verifier = { version = "0.5.3", optional = true }
+ tokio = { version = "1.45", features = ["net", "macros", "signal"] }
+ tokio-rustls = { version = "0.26", default-features = false, features = ["ring", "tls12"] }
+ serde = { version = "1.0", features = ["derive"]}
+@@ -45,6 +46,7 @@ privdrop = "0.5.3"
+ 
+ [features]
+ test_mode = []
++tls-native-roots = ["dep:rustls-platform-verifier", "reqwest/rustls-tls-native-roots"]
+ 
+ [dev-dependencies]
+ tokio = { version = "1.45", features = ["full"] }
+diff --git a/crates/utils/src/lib.rs b/crates/utils/src/lib.rs
+index 2b73df148..2efcc96d7 100644
+--- a/crates/utils/src/lib.rs
++++ b/crates/utils/src/lib.rs
+@@ -21,14 +21,14 @@ use compact_str::ToCompactString;
+ use futures::StreamExt;
+ use reqwest::Response;
+ use rustls::{
+-    ClientConfig, RootCertStore, SignatureScheme,
++    ClientConfig, SignatureScheme,
+     client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier},
+ };
+-use rustls_pki_types::TrustAnchor;
+ 
+ pub use downcast_rs;
+ pub use erased_serde;
+ 
++pub static USER_AGENT: &str = "Stalwart/1.0.0";
+ pub const BLOB_HASH_LEN: usize = 32;
+ 
+ #[derive(
+@@ -294,20 +294,28 @@ pub async fn wait_for_shutdown() {
+ }
+ 
+ pub fn rustls_client_config(allow_invalid_certs: bool) -> ClientConfig {
++    #[cfg(feature = "tls-native-roots")]
++    use rustls_platform_verifier::BuilderVerifierExt;
++
+     let config = ClientConfig::builder();
+ 
+     if !allow_invalid_certs {
+-        let mut root_cert_store = RootCertStore::empty();
+-
+-        root_cert_store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().map(|ta| TrustAnchor {
+-            subject: ta.subject.clone(),
+-            subject_public_key_info: ta.subject_public_key_info.clone(),
+-            name_constraints: ta.name_constraints.clone(),
+-        }));
+-
+-        config
+-            .with_root_certificates(root_cert_store)
+-            .with_no_client_auth()
++        #[cfg(feature = "tls-native-roots")]
++        let config = config.with_platform_verifier();
++
++        #[cfg(not(feature = "tls-native-roots"))]
++        let config = config.with_root_certificates(
++            webpki_roots::TLS_SERVER_ROOTS
++                .iter()
++                .map(|ta| rustls_pki_types::TrustAnchor {
++                    subject: ta.subject.clone(),
++                    subject_public_key_info: ta.subject_public_key_info.clone(),
++                    name_constraints: ta.name_constraints.clone(),
++                })
++                .collect::<rustls::RootCertStore>(),
++        );
++
++        config.with_no_client_auth()
+     } else {
+         config
+             .dangerous()
+@@ -316,6 +324,18 @@ pub fn rustls_client_config(allow_invalid_certs: bool) -> ClientConfig {
+     }
+ }
+ 
++pub fn reqwest_client_builder() -> reqwest::ClientBuilder {
++    let builder = reqwest::Client::builder();
++
++    #[cfg(feature = "tls-native-roots")]
++    let builder = builder.tls_built_in_native_certs(true);
++
++    #[cfg(not(feature = "tls-native-roots"))]
++    let builder = builder.tls_built_in_webpki_certs(true);
++
++    builder.user_agent(USER_AGENT)
++}
++
+ #[derive(Debug)]
+ struct DummyVerifier;
+ 
+diff --git a/crates/utils/src/suffixlist.rs b/crates/utils/src/suffixlist.rs
+index e0921abe3..b53126ae9 100644
+--- a/crates/utils/src/suffixlist.rs
++++ b/crates/utils/src/suffixlist.rs
+@@ -111,7 +111,12 @@ impl PublicSuffix {
+ 
+         for (idx, value) in values.into_iter().enumerate() {
+             let bytes = if value.starts_with("https://") || value.starts_with("http://") {
+-                let result = match reqwest::get(&value).await {
++                let result = match crate::reqwest_client_builder()
++                    .build()
++                    .unwrap_or_default()
++                    .get(&value)
++                    .await
++                {
+                     Ok(r) => {
+                         if r.status().is_success() {
+                             r.bytes().await
+diff --git a/tests/Cargo.toml b/tests/Cargo.toml
+index 386b8255a..68692e939 100644
+--- a/tests/Cargo.toml
++++ b/tests/Cargo.toml
+@@ -59,7 +59,7 @@ rayon = { version = "1.5.1" }
+ flate2 = { version = "1.0.17", features = ["zlib"], default-features = false }
+ serde = { version = "1.0", features = ["derive"]}
+ serde_json = "1.0"
+-reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "multipart", "http2"]}
++reqwest = { version = "0.12", default-features = false, features = ["multipart", "http2"]}
+ bytes = "1.4.0"
+ futures = "0.3"
+ ece = "2.2"
+diff --git a/tests/src/jmap/auth_oauth.rs b/tests/src/jmap/auth_oauth.rs
+index 0d05d3a77..fff811fcf 100644
+--- a/tests/src/jmap/auth_oauth.rs
++++ b/tests/src/jmap/auth_oauth.rs
+@@ -411,7 +411,7 @@ async fn post_bytes(
+     auth_token: Option<&str>,
+     params: &AHashMap<String, String>,
+ ) -> Bytes {
+-    let mut client = reqwest::Client::builder()
++    let mut client = utils::reqwest_client_builder()
+         .timeout(Duration::from_millis(500))
+         .danger_accept_invalid_certs(true)
+         .build()
+@@ -437,7 +437,7 @@ async fn post_json<D: DeserializeOwned>(
+     auth_token: Option<&str>,
+     body: &impl Serialize,
+ ) -> D {
+-    let mut client = reqwest::Client::builder()
++    let mut client = utils::reqwest_client_builder()
+         .timeout(Duration::from_millis(500))
+         .danger_accept_invalid_certs(true)
+         .build()
+@@ -473,7 +473,7 @@ async fn post_with_auth<T: DeserializeOwned>(
+ }
+ 
+ async fn get_bytes(url: &str) -> Bytes {
+-    reqwest::Client::builder()
++    utils::reqwest_client_builder()
+         .timeout(Duration::from_millis(500))
+         .danger_accept_invalid_certs(true)
+         .build()
+diff --git a/tests/src/jmap/mod.rs b/tests/src/jmap/mod.rs
+index 554026a00..ffd8d292a 100644
+--- a/tests/src/jmap/mod.rs
++++ b/tests/src/jmap/mod.rs
+@@ -419,7 +419,7 @@ pub async fn jmap_raw_request(body: impl AsRef<str>, username: &str, secret: &st
+       }"#;
+ 
+     String::from_utf8(
+-        reqwest::Client::builder()
++        utils::reqwest_client_builder()
+             .danger_accept_invalid_certs(true)
+             .timeout(Duration::from_millis(1000))
+             .default_headers(headers)
+@@ -620,7 +620,7 @@ impl ManagementApi {
+         query: &str,
+         body: Option<String>,
+     ) -> Result<String, String> {
+-        let mut request = reqwest::Client::builder()
++        let mut request = utils::reqwest_client_builder()
+             .timeout(Duration::from_millis(500))
+             .danger_accept_invalid_certs(true)
+             .build()
+diff --git a/tests/src/smtp/management/queue.rs b/tests/src/smtp/management/queue.rs
+index e86f55169..a0d144127 100644
+--- a/tests/src/smtp/management/queue.rs
++++ b/tests/src/smtp/management/queue.rs
+@@ -493,7 +493,7 @@ async fn manage_queue() {
+ 
+     // Test authentication error
+     assert_eq!(
+-        reqwest::Client::builder()
++        utils::reqwest_client_builder()
+             .timeout(Duration::from_millis(500))
+             .danger_accept_invalid_certs(true)
+             .build()
+diff --git a/tests/src/webdav/mod.rs b/tests/src/webdav/mod.rs
+index 0ed8b1888..25aab71a4 100644
+--- a/tests/src/webdav/mod.rs
++++ b/tests/src/webdav/mod.rs
+@@ -302,7 +302,7 @@ impl DummyWebDavClient {
+         headers: impl IntoIterator<Item = (&'static str, &str)>,
+         body: impl Into<String>,
+     ) -> DavResponse {
+-        let mut request = reqwest::Client::builder()
++        let mut request = utils::reqwest_client_builder()
+             .timeout(Duration::from_millis(500))
+             .danger_accept_invalid_certs(true)
+             .build()