about summary refs log tree commit diff stats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--pkgs/by-name/st/stalwart-mail-patched/package.nix97
-rw-r--r--pkgs/by-name/st/stalwart-mail-patched/patches/0001-Allow-to-switch-to-operating-system-CA-root-store.patch (renamed from pkgs/by-name/st/stalwart-mail-patched/patches/use-platform-ca-roots.patch)907
2 files changed, 743 insertions, 261 deletions
diff --git a/pkgs/by-name/st/stalwart-mail-patched/package.nix b/pkgs/by-name/st/stalwart-mail-patched/package.nix
index 85ab840..062ab2c 100644
--- a/pkgs/by-name/st/stalwart-mail-patched/package.nix
+++ b/pkgs/by-name/st/stalwart-mail-patched/package.nix
@@ -2,53 +2,68 @@
   stalwart-mail,
   callPackage,
   nixLib,
+  rustPlatform,
+  lib,
 }: let
   spamfilter = callPackage ./spam-filter.nix {};
 in
-  stalwart-mail.overrideAttrs (final: prev: {
-    pname = "stalwart-mail-patched";
+  stalwart-mail.override {
+    rustPlatform =
+      rustPlatform
+      // {
+        buildRustPackage = prev:
+          rustPlatform.buildRustPackage (
+            lib.attrsets.recursiveUpdate
+            prev
+            {
+              pname = "stalwart-mail-patched";
 
-    passthru = nixLib.warnMerge (prev.passthru or {}) {
-      # Use a reproducible source for the spamfilter instead of fetching it at runtime from GitHub.
-      inherit spamfilter;
-    } "stalwart-mail passthru";
+              passthru = nixLib.warnMerge (prev.passthru or {}) {
+                # Use a reproducible source for the spamfilter instead of fetching it at runtime from GitHub.
+                inherit spamfilter;
+              } "stalwart-mail passthru";
 
-    # The NixOS build tests should check if this works.
-    # And this shaves of around 50% of the build time.
-    doCheck = false;
+              cargoHash = "sha256-Rq18JumjKYt97WKIqnLakS+FQwsjt70irlYBYAYm3H8=";
 
-    # We are already overriding it, so shaving of some unused features is okay.
-    buildNoDefaultFeatures = true;
-    buildFeatures = [
-      # "sqlite"
-      # "postgres"
-      # "mysql"
-      "rocks"
-      # "elastic"
-      # "s3"
-      "redis"
-      "tls-native-roots"
-    ];
+              # The NixOS build tests should check if this works.
+              # And this shaves of around 50% of the build time.
+              doCheck = false;
 
-    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/use-platform-ca-roots.patch
-      ];
+              # We are already overriding it, so shaving of some unused features is okay.
+              buildNoDefaultFeatures = true;
+              buildFeatures = [
+                # "sqlite"
+                # "postgres"
+                # "mysql"
+                "rocks"
+                # "elastic"
+                # "s3"
+                "redis"
+                "tls-native-roots"
+              ];
 
-    # Check that the enterprise feature is really disabled.
-    postCheck =
-      (prev.postCheck or "")
-      +
-      # bash
-      ''
-        if grep "enterprise" ./target/*/release/stalwart-mail.d; then
-          echo "ERROR: Proprietary 'enterprise' feature active."
-          exit 1
-        fi
-      '';
+              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/0001-Allow-to-switch-to-operating-system-CA-root-store.patch
+                ];
 
-    meta.mainProgram = prev.meta.mainProgram or "stalwart-mail";
-  })
+              # Check that the enterprise feature is really disabled.
+              postCheck =
+                (prev.postCheck or "")
+                +
+                # bash
+                ''
+                  if grep "enterprise" ./target/*/release/stalwart-mail.d; then
+                    echo "ERROR: Proprietary 'enterprise' feature active."
+                    exit 1
+                  fi
+                '';
+
+              meta.mainProgram = prev.meta.mainProgram or "stalwart-mail";
+            }
+          );
+      };
+  }
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/0001-Allow-to-switch-to-operating-system-CA-root-store.patch
index 392fbde..17ab1f4 100644
--- a/pkgs/by-name/st/stalwart-mail-patched/patches/use-platform-ca-roots.patch
+++ b/pkgs/by-name/st/stalwart-mail-patched/patches/0001-Allow-to-switch-to-operating-system-CA-root-store.patch
@@ -1,4 +1,4 @@
-From 66227b07c6cb4781a38fe603c2e856c5696e0f94 Mon Sep 17 00:00:00 2001
+From af19ac6465bc3f76b61deef15fcdf0a97eaa0904 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
@@ -32,64 +32,345 @@ by simply recompiling with the "tls-native-roots" feature.
 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(-)
+ Cargo.lock                                   | 237 +++++++++++++++++--
+ crates/cli/Cargo.toml                        |   8 +-
+ crates/cli/src/main.rs                       |   8 +-
+ crates/common/Cargo.toml                     |   2 +-
+ crates/common/src/enterprise/llm.rs          |   2 +-
+ crates/common/src/enterprise/mod.rs          |   4 +-
+ 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                  |   4 +-
+ crates/directory/src/backend/oidc/lookup.rs  |   4 +-
+ crates/jmap/Cargo.toml                       |   2 +-
+ crates/main/Cargo.toml                       |  13 +-
+ crates/smtp/Cargo.toml                       |   8 +-
+ 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                |   4 +-
+ 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                        |   4 +-
+ crates/utils/Cargo.toml                      |   2 +
+ crates/utils/src/lib.rs                      |  41 +++-
+ 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 +-
+ 32 files changed, 309 insertions(+), 88 deletions(-)
 
 diff --git a/Cargo.lock b/Cargo.lock
-index 0eeb42510..6dd394dc3 100644
+index 21c7f726..67fe5739 100644
 --- a/Cargo.lock
 +++ b/Cargo.lock
-@@ -3372,6 +3372,7 @@ dependencies = [
+@@ -410,7 +410,7 @@ checksum = "412b79ce053cef36eda52c25664b45ec92a21769488e20d5a8bf0b3c9e1a28cb"
+ dependencies = [
+  "http 1.2.0",
+  "log",
+- "rustls 0.23.21",
++ "rustls 0.23.27",
+  "serde",
+  "serde_json",
+  "url",
+@@ -1035,6 +1035,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"
+@@ -1250,7 +1256,7 @@ dependencies = [
+  "reqwest 0.12.12",
+  "ring 0.17.8",
+  "rsa",
+- "rustls 0.23.21",
++ "rustls 0.23.27",
+  "rustls-pemfile 2.2.0",
+  "rustls-pki-types",
+  "serde",
+@@ -1347,6 +1353,16 @@ dependencies = [
+  "libc",
+ ]
+ 
++[[package]]
++name = "core-foundation"
++version = "0.10.1"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6"
++dependencies = [
++ "core-foundation-sys",
++ "libc",
++]
++
+ [[package]]
+ name = "core-foundation-sys"
+ version = "0.8.7"
+@@ -1819,7 +1835,7 @@ dependencies = [
+  "pwhash",
+  "regex",
+  "reqwest 0.12.12",
+- "rustls 0.23.21",
++ "rustls 0.23.27",
+  "rustls-pki-types",
+  "scrypt",
+  "serde",
+@@ -3056,7 +3072,8 @@ dependencies = [
+  "http 1.2.0",
   "hyper 1.6.0",
   "hyper-util",
-  "rustls 0.23.27",
+- "rustls 0.23.21",
++ "rustls 0.23.27",
 + "rustls-native-certs 0.8.1",
   "rustls-pki-types",
   "tokio",
-  "tokio-rustls 0.26.2",
-@@ -6318,6 +6319,7 @@ dependencies = [
+  "tokio-rustls 0.26.1",
+@@ -3296,7 +3313,7 @@ dependencies = [
+  "nlp",
+  "parking_lot",
+  "rand 0.9.0",
+- "rustls 0.23.21",
++ "rustls 0.23.27",
+  "rustls-pemfile 2.2.0",
+  "store",
+  "tokio",
+@@ -3620,6 +3637,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"
+@@ -3978,7 +4017,7 @@ dependencies = [
+  "base64 0.22.1",
+  "gethostname",
+  "md5",
+- "rustls 0.23.21",
++ "rustls 0.23.27",
+  "rustls-pki-types",
+  "smtp-proto",
+  "tokio",
+@@ -4022,7 +4061,7 @@ dependencies = [
+  "mail-send",
+  "md5",
+  "parking_lot",
+- "rustls 0.23.21",
++ "rustls 0.23.27",
+  "rustls-pemfile 2.2.0",
+  "sieve-rs",
+  "store",
+@@ -4841,7 +4880,7 @@ dependencies = [
+  "jmap_proto",
+  "mail-parser",
+  "mail-send",
+- "rustls 0.23.21",
++ "rustls 0.23.27",
+  "store",
+  "tokio",
+  "tokio-rustls 0.26.1",
+@@ -5152,7 +5191,7 @@ dependencies = [
+  "quinn-proto",
+  "quinn-udp",
+  "rustc-hash 2.1.0",
+- "rustls 0.23.21",
++ "rustls 0.23.27",
+  "socket2",
+  "thiserror 2.0.11",
+  "tokio",
+@@ -5170,7 +5209,7 @@ dependencies = [
+  "rand 0.8.5",
+  "ring 0.17.8",
+  "rustc-hash 2.1.0",
+- "rustls 0.23.21",
++ "rustls 0.23.27",
+  "rustls-pki-types",
+  "slab",
+  "thiserror 2.0.11",
+@@ -5452,7 +5491,7 @@ dependencies = [
+  "percent-encoding",
+  "pin-project-lite",
+  "rand 0.8.5",
+- "rustls 0.23.21",
++ "rustls 0.23.27",
+  "rustls-native-certs 0.7.3",
+  "rustls-pemfile 2.2.0",
+  "rustls-pki-types",
+@@ -5595,7 +5634,8 @@ dependencies = [
+  "percent-encoding",
   "pin-project-lite",
   "quinn",
-  "rustls 0.23.27",
+- "rustls 0.23.21",
++ "rustls 0.23.27",
++ "rustls-native-certs 0.8.1",
+  "rustls-pemfile 2.2.0",
+  "rustls-pki-types",
+  "serde",
+@@ -5960,14 +6000,14 @@ dependencies = [
+ 
+ [[package]]
+ name = "rustls"
+-version = "0.23.21"
++version = "0.23.27"
+ source = "registry+https://github.com/rust-lang/crates.io-index"
+-checksum = "8f287924602bf649d949c63dc8ac8b235fa5387d394020705b80c4eb597ce5b8"
++checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321"
+ dependencies = [
+  "once_cell",
+  "ring 0.17.8",
+  "rustls-pki-types",
+- "rustls-webpki 0.102.8",
++ "rustls-webpki 0.103.3",
+  "subtle",
+  "zeroize",
+ ]
+@@ -5981,7 +6021,7 @@ dependencies = [
+  "openssl-probe",
+  "rustls-pemfile 1.0.4",
+  "schannel",
+- "security-framework",
++ "security-framework 2.11.1",
+ ]
+ 
+ [[package]]
+@@ -5994,7 +6034,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]]
+@@ -6024,6 +6076,33 @@ dependencies = [
+  "web-time",
+ ]
+ 
++[[package]]
++name = "rustls-platform-verifier"
++version = "0.5.3"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "19787cda76408ec5404443dc8b31795c87cd8fec49762dc75fa727740d34acc1"
++dependencies = [
++ "core-foundation 0.10.1",
++ "core-foundation-sys",
++ "jni",
++ "log",
++ "once_cell",
++ "rustls 0.23.27",
 + "rustls-native-certs 0.8.1",
++ "rustls-platform-verifier-android",
++ "rustls-webpki 0.103.3",
++ "security-framework 3.2.0",
++ "security-framework-sys",
++ "webpki-root-certs 0.26.11",
++ "windows-sys 0.59.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"
+@@ -6045,6 +6124,17 @@ dependencies = [
+  "untrusted 0.9.0",
+ ]
+ 
++[[package]]
++name = "rustls-webpki"
++version = "0.103.3"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435"
++dependencies = [
++ "ring 0.17.8",
++ "rustls-pki-types",
++ "untrusted 0.9.0",
++]
++
+ [[package]]
+ name = "rustversion"
+ version = "1.0.19"
+@@ -6169,7 +6259,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.1",
+  "core-foundation-sys",
+  "libc",
+  "security-framework-sys",
+@@ -6546,7 +6649,7 @@ dependencies = [
+  "rayon",
+  "regex",
+  "reqwest 0.12.12",
+- "rustls 0.23.21",
++ "rustls 0.23.27",
   "rustls-pemfile 2.2.0",
   "rustls-pki-types",
   "serde",
-@@ -7694,6 +7696,7 @@ dependencies = [
+@@ -6684,6 +6787,7 @@ dependencies = [
   "serde",
   "serde_json",
   "tokio",
@@ -97,44 +378,236 @@ index 0eeb42510..6dd394dc3 100644
  ]
  
  [[package]]
-@@ -8795,6 +8798,7 @@ dependencies = [
-  "rustls 0.23.27",
+@@ -6730,7 +6834,7 @@ dependencies = [
+  "rocksdb",
+  "rusqlite",
+  "rust-s3",
+- "rustls 0.23.21",
++ "rustls 0.23.27",
+  "rustls-pki-types",
+  "serde",
+  "serde_json",
+@@ -6861,7 +6965,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",
+ ]
+ 
+@@ -6938,7 +7042,7 @@ dependencies = [
+  "rayon",
+  "reqwest 0.12.12",
+  "ring 0.17.8",
+- "rustls 0.23.21",
++ "rustls 0.23.27",
+  "rustls-pemfile 2.2.0",
+  "rustls-pki-types",
+  "serde",
+@@ -7144,7 +7248,7 @@ version = "0.26.1"
+ source = "registry+https://github.com/rust-lang/crates.io-index"
+ checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37"
+ dependencies = [
+- "rustls 0.23.21",
++ "rustls 0.23.27",
+  "tokio",
+ ]
+ 
+@@ -7610,9 +7714,10 @@ dependencies = [
+  "regex",
+  "reqwest 0.12.12",
+  "ring 0.17.8",
+- "rustls 0.23.21",
++ "rustls 0.23.27",
   "rustls-pemfile 2.2.0",
   "rustls-pki-types",
 + "rustls-platform-verifier",
   "serde",
   "serde_json",
   "smtp-proto",
+@@ -7817,6 +7922,24 @@ dependencies = [
+  "untrusted 0.9.0",
+ ]
+ 
++[[package]]
++name = "webpki-root-certs"
++version = "0.26.11"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "75c7f0ef91146ebfb530314f5f1d24528d7f0767efbfd31dce919275413e393e"
++dependencies = [
++ "webpki-root-certs 1.0.0",
++]
++
++[[package]]
++name = "webpki-root-certs"
++version = "1.0.0"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "01a83f7e1a9f8712695c03eabe9ed3fbca0feff0152f33f12593e5a6303cb1a4"
++dependencies = [
++ "rustls-pki-types",
++]
++
+ [[package]]
+ name = "webpki-roots"
+ version = "0.25.4"
+@@ -7939,6 +8062,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"
+@@ -7966,6 +8098,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"
+@@ -7997,6 +8144,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"
+@@ -8009,6 +8162,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"
+@@ -8021,6 +8180,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"
+@@ -8039,6 +8204,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"
+@@ -8051,6 +8222,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"
+@@ -8063,6 +8240,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"
+@@ -8075,6 +8258,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 5573df819..719441a0c 100644
+index 878def77..d4239cdb 100644
 --- a/crates/cli/Cargo.toml
 +++ b/crates/cli/Cargo.toml
-@@ -11,9 +11,9 @@ readme = "README.md"
+@@ -11,8 +11,8 @@ 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"]}
+-mail-parser = { version = "0.10", features = ["full_encoding", "serde_support"] } 
 +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"] }
++mail-parser = { version = "0.10", features = ["full_encoding", "serde_support"] }
+ reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "http2"]}
+ tokio = { version = "1.23", 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" }
+ mail-auth = { version = "0.6" }
 +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
+index 1ce96eda..da52b2ba 100644
 --- a/crates/cli/src/main.rs
 +++ b/crates/cli/src/main.rs
-@@ -86,7 +86,7 @@ fn parse_credentials(credentials: &str) -> Credentials {
+@@ -85,7 +85,7 @@ fn parse_credentials(credentials: &str) -> Credentials {
  
  async fn oauth(url: &str) -> Credentials {
      let metadata: HashMap<String, serde_json::Value> = serde_json::from_slice(
@@ -143,7 +616,7 @@ index f295c217f..f62d528c5 100644
              .danger_accept_invalid_certs(is_localhost(url))
              .build()
              .unwrap_or_default()
-@@ -104,7 +104,7 @@ async fn oauth(url: &str) -> Credentials {
+@@ -103,7 +103,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(
@@ -152,7 +625,7 @@ index f295c217f..f62d528c5 100644
              .danger_accept_invalid_certs(is_localhost(url))
              .build()
              .unwrap_or_default()
-@@ -138,7 +138,7 @@ async fn oauth(url: &str) -> Credentials {
+@@ -137,7 +137,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(
@@ -161,7 +634,7 @@ index f295c217f..f62d528c5 100644
              .danger_accept_invalid_certs(is_localhost(url))
              .build()
              .unwrap_or_default()
-@@ -230,7 +230,7 @@ impl Client {
+@@ -229,7 +229,7 @@ impl Client {
              },
              url
          );
@@ -171,10 +644,10 @@ index f295c217f..f62d528c5 100644
              .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
+index 7c53a1db..edf72dfa 100644
 --- a/crates/common/Cargo.toml
 +++ b/crates/common/Cargo.toml
-@@ -33,7 +33,7 @@ tokio = { version = "1.45", features = ["net", "macros"] }
+@@ -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"
@@ -184,7 +657,7 @@ index 58028bad3..5add0a5dc 100644
  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
+index bc370b4b..b54cae27 100644
 --- a/crates/common/src/enterprise/llm.rs
 +++ b/crates/common/src/enterprise/llm.rs
 @@ -125,7 +125,7 @@ impl AiApiConfig {
@@ -197,39 +670,25 @@ index 8338f39d3..fe013c0f0 100644
              .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
+index 5eec0f98..7718bbd8 100644
 --- a/crates/common/src/enterprise/mod.rs
 +++ b/crates/common/src/enterprise/mod.rs
-@@ -188,12 +188,18 @@ impl Server {
+@@ -193,7 +193,9 @@ 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 = reqwest::get(&logo_url).await.map_err(|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()
++                       .unwrap_or_default().get(&logo_url).await.map_err(|err| {
+                         trc::ResourceEvent::DownloadExternal
+                             .into_err()
+                             .details("Failed to download logo")
 diff --git a/crates/common/src/lib.rs b/crates/common/src/lib.rs
-index ce4b41b89..185508d1f 100644
+index c7ffdf0a..0fee0564 100644
 --- a/crates/common/src/lib.rs
 +++ b/crates/common/src/lib.rs
-@@ -46,6 +46,8 @@ use utils::{
+@@ -47,6 +47,8 @@ use utils::{
      snowflake::SnowflakeIdGenerator,
  };
  
@@ -238,27 +697,27 @@ index ce4b41b89..185508d1f 100644
  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";
+@@ -63,7 +65,6 @@ pub mod telemetry;
+ 
+ pub use psl;
  
--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";
+-pub static USER_AGENT: &str = concat!("Stalwart/", env!("CARGO_PKG_VERSION"),);
+ pub static DAEMON_NAME: &str = concat!("Stalwart Mail Server v", env!("CARGO_PKG_VERSION"),);
  
+ pub const IPC_CHANNEL_BUFFER: usize = 1024;
 diff --git a/crates/common/src/listener/acme/directory.rs b/crates/common/src/listener/acme/directory.rs
-index f095e1969..6f9cfa0e0 100644
+index 6eedc5a9..7fc3c20f 100644
 --- a/crates/common/src/listener/acme/directory.rs
 +++ b/crates/common/src/listener/acme/directory.rs
-@@ -7,7 +7,6 @@ use super::jose::{
- };
+@@ -4,7 +4,6 @@ use std::time::Duration;
+ 
  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(
+@@ -315,7 +314,7 @@ async fn https(
      body: Option<String>,
  ) -> trc::Result<Response> {
      let url = url.as_ref();
@@ -267,7 +726,7 @@ index f095e1969..6f9cfa0e0 100644
          .timeout(Duration::from_secs(30))
          .http1_only();
  
-@@ -330,8 +329,7 @@ async fn https(
+@@ -329,8 +328,7 @@ async fn https(
      let mut request = builder
          .build()
          .map_err(|err| trc::EventType::Acme(trc::AcmeEvent::Error).from_http_error(err))?
@@ -278,7 +737,7 @@ index f095e1969..6f9cfa0e0 100644
      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
+index 51861a82..a59e74b5 100644
 --- a/crates/common/src/manager/mod.rs
 +++ b/crates/common/src/manager/mod.rs
 @@ -76,7 +76,7 @@ pub async fn fetch_resource(
@@ -291,7 +750,7 @@ index 51861a82c..a59e74b56 100644
              .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
+index 6cba1fe6..8cc3250f 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> {
@@ -304,10 +763,10 @@ index 42e2af553..54d906e17 100644
          .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
+index 6207fd6c..994afae5 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(
+@@ -150,7 +150,7 @@ async fn post_webhook_events(
      }
  
      // Send request
@@ -317,10 +776,19 @@ index a70005399..2cebfd81f 100644
          .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
+index 3bff0fc5..ad3d8a01 100644
 --- a/crates/directory/Cargo.toml
 +++ b/crates/directory/Cargo.toml
-@@ -35,7 +35,7 @@ futures = "0.3"
+@@ -11,7 +11,7 @@ store = { path =  "../store" }
+ trc = { path = "../trc" }
+ jmap_proto = { path =  "../jmap-proto" }
+ smtp-proto = { version = "0.1" }
+-mail-parser = { version = "0.10", features = ["full_encoding", "serde_support"] } 
++mail-parser = { version = "0.10", features = ["full_encoding", "serde_support"] }
+ mail-send = { version = "0.5", default-features = false, features = ["cram-md5", "ring", "tls12"] }
+ mail-builder = { version = "0.4" }
+ tokio = { version = "1.23", features = ["net"] }
+@@ -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"] }
@@ -328,9 +796,9 @@ index ae8eca025..4a033834b 100644
 +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
+index 49253dd3..5122ccab 100644
 --- a/crates/directory/src/backend/oidc/lookup.rs
 +++ b/crates/directory/src/backend/oidc/lookup.rs
 @@ -36,10 +36,10 @@ impl OpenIdDirectory {
@@ -347,10 +815,10 @@ index 755064115..907831a46 100644
                  let client = client
                      .timeout(self.config.endpoint_timeout)
 diff --git a/crates/jmap/Cargo.toml b/crates/jmap/Cargo.toml
-index 9d9cfa7d7..a3a7b5003 100644
+index 25643ac5..1383ae9f 100644
 --- a/crates/jmap/Cargo.toml
 +++ b/crates/jmap/Cargo.toml
-@@ -36,7 +36,7 @@ p256 = { version = "0.13", features = ["ecdh"] }
+@@ -38,7 +38,7 @@ p256 = { version = "0.13", features = ["ecdh"] }
  hkdf = "0.12.3"
  sha1 = "0.10"
  sha2 = "0.10"
@@ -360,55 +828,56 @@ index 9d9cfa7d7..a3a7b5003 100644
  tungstenite = "0.26"
  chrono = "0.4"
 diff --git a/crates/main/Cargo.toml b/crates/main/Cargo.toml
-index 1023b73bf..4b39dae29 100644
+index a5a6160c..ec737cce 100644
 --- a/crates/main/Cargo.toml
 +++ b/crates/main/Cargo.toml
-@@ -64,3 +64,4 @@ enterprise = [ "jmap/enterprise",
-                "dav/enterprise",
-                "groupware/enterprise",
-                "services/enterprise" ]
+@@ -45,10 +45,11 @@ elastic = ["store/elastic"]
+ s3 = ["store/s3"]
+ redis = ["store/redis"]
+ azure = ["store/azure"]
+-enterprise = [ "jmap/enterprise", 
+-               "smtp/enterprise", 
+-               "common/enterprise", 
+-               "store/enterprise", 
+-               "managesieve/enterprise", 
+-               "directory/enterprise", 
++enterprise = [ "jmap/enterprise",
++               "smtp/enterprise",
++               "common/enterprise",
++               "store/enterprise",
++               "managesieve/enterprise",
++               "directory/enterprise",
+                "spam-filter/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
+index e7232a5b..5618fcef 100644
 --- a/crates/smtp/Cargo.toml
 +++ b/crates/smtp/Cargo.toml
+@@ -22,10 +22,10 @@ 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-parser = { version = "0.10", features = ["full_encoding"] } 
+-mail-builder = { version = "0.4" } 
++mail-parser = { version = "0.10", features = ["full_encoding"] }
++mail-builder = { version = "0.4" }
+ smtp-proto = { version = "0.1", features = ["serde_support"] }
+-sieve-rs = { version = "0.6" } 
++sieve-rs = { version = "0.6" }
+ ahash = { version = "0.8" }
+ rustls = { version = "0.23.5", default-features = false, features = ["std", "ring", "tls12"] }
+ rustls-pemfile = "2.0"
 @@ -47,7 +47,7 @@ blake3 = "1.3"
  lru-cache = "0.1.2"
  rand = "0.9.0"
- x509-parser = "0.17.0"
+ 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 = ["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
+index 2e3a9e17..6bfb40a6 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(
@@ -421,7 +890,7 @@ index 2e3a9e17c..6bfb40a63 100644
          .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
+index 03c5d251..45aff403 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 {
@@ -435,19 +904,19 @@ index c8b279c2f..10f2aafeb 100644
              .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
+index 1da29ea9..3b504b13 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::{
+@@ -13,7 +13,7 @@ use common::{
+         resolver::{Mode, MxPattern},
+     },
+     ipc::{TlsEvent, ToHash},
 -    Server, USER_AGENT,
 +    Server,
-     config::smtp::{
-         report::AggregateFrequency,
-         resolver::{Mode, MxPattern},
-@@ -142,8 +142,7 @@ impl TlsReporting for Server {
+ };
+ use mail_auth::{
+     flate2::{write::GzEncoder, Compression},
+@@ -145,8 +145,7 @@ impl TlsReporting for Server {
          for uri in &rua {
              match uri {
                  ReportUri::Http(uri) => {
@@ -458,10 +927,19 @@ index 28e9fa47b..875f395c8 100644
                          .build()
                      {
 diff --git a/crates/spam-filter/Cargo.toml b/crates/spam-filter/Cargo.toml
-index f6ec739a8..5a3df8453 100644
+index 4d0e0fa8..aefd5d0f 100644
 --- a/crates/spam-filter/Cargo.toml
 +++ b/crates/spam-filter/Cargo.toml
-@@ -19,7 +19,7 @@ tokio = { version = "1.45", features = ["net", "macros"] }
+@@ -11,7 +11,7 @@ store = { path = "../store" }
+ trc = { path = "../trc" }
+ common = { path =  "../common" }
+ smtp-proto = { version = "0.1", features = ["serde_support"] }
+-mail-parser = { version = "0.10", features = ["full_encoding"] } 
++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"] }
+@@ -19,7 +19,7 @@ tokio = { version = "1.23", features = ["net", "macros"] }
  psl = "2"
  hyper = { version = "1.0.1", features = ["server", "http1", "http2"] }
  idna = "1.0"
@@ -469,12 +947,12 @@ index f6ec739a8..5a3df8453 100644
 +reqwest = { version = "0.12", default-features = false, features = ["http2", "stream"]}
  decancer = "3.0.1"
  unicode-security = "0.1.0"
- infer = "0.19"
+ infer = "0.16"
 diff --git a/crates/spam-filter/src/analysis/url.rs b/crates/spam-filter/src/analysis/url.rs
-index a0d663917..e6377f13c 100644
+index c3d5f828..51a93141 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(
+@@ -289,7 +289,7 @@ async fn http_get_header(
              Ok(None)
          };
      }
@@ -484,20 +962,20 @@ index a0d663917..e6377f13c 100644
          .timeout(timeout)
          .redirect(Policy::none())
 diff --git a/crates/store/Cargo.toml b/crates/store/Cargo.toml
-index 1f8965049..3bd1a228c 100644
+index d89d8da1..aa1aef33 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
+@@ -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 = ["http2", "stream"]}
- tokio = { version = "1.45", features = ["sync", "fs", "io-util"] }
+ 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/store/src/backend/azure/mod.rs b/crates/store/src/backend/azure/mod.rs
-index 8bbaea073..fbdb03eb7 100644
+index 3b6d5be4..e91d6275 100644
 --- a/crates/store/src/backend/azure/mod.rs
 +++ b/crates/store/src/backend/azure/mod.rs
 @@ -63,7 +63,7 @@ impl AzureStore {
@@ -510,10 +988,10 @@ index 8bbaea073..fbdb03eb7 100644
              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
+index bb5c6104..ce7c6149 100644
 --- a/crates/store/src/backend/http/lookup.rs
 +++ b/crates/store/src/backend/http/lookup.rs
-@@ -91,7 +91,7 @@ impl HttpStore {
+@@ -90,7 +90,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();
@@ -523,60 +1001,61 @@ index dbaa932ed..ff7cca2d8 100644
              .user_agent(*agent)
              .build()
 diff --git a/crates/trc/Cargo.toml b/crates/trc/Cargo.toml
-index 61d1cd69a..22d8e6599 100644
+index 13221373..bb7b6fd8 100644
 --- a/crates/trc/Cargo.toml
 +++ b/crates/trc/Cargo.toml
-@@ -11,7 +11,7 @@ mail-parser = { version = "0.11", features = ["full_encoding"] }
+@@ -7,11 +7,11 @@ resolver = "2"
+ [dependencies]
+ event_macro = { path = "./event-macro" }
+ mail-auth = { version = "0.6" }
+-mail-parser = { version = "0.10", features = ["full_encoding"] } 
++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 = ["http2"]}
+ bincode = "1.3.3"
  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
+index b451e742..cbd981ec 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" }
+@@ -23,6 +23,7 @@ ring = { version = "0.17" }
+ base64 = "0.22"
+ serde_json = "1.0"
+ rcgen = "0.13"
 +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"
+ reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "http2", "stream"]}
+ x509-parser = "0.16.0"
+ pem = "3.0"
+@@ -40,6 +41,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"] }
+ tokio = { version = "1.23", features = ["full"] }
 diff --git a/crates/utils/src/lib.rs b/crates/utils/src/lib.rs
-index 2b73df148..2efcc96d7 100644
+index acec2f04..f3c667f3 100644
 --- a/crates/utils/src/lib.rs
 +++ b/crates/utils/src/lib.rs
-@@ -21,14 +21,14 @@ use compact_str::ToCompactString;
- use futures::StreamExt;
+@@ -18,10 +18,11 @@ use futures::StreamExt;
  use reqwest::Response;
  use rustls::{
+     client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier},
 -    ClientConfig, RootCertStore, SignatureScheme,
 +    ClientConfig, SignatureScheme,
-     client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier},
  };
--use rustls_pki_types::TrustAnchor;
- 
- pub use downcast_rs;
- pub use erased_serde;
+ use rustls_pki_types::TrustAnchor;
  
 +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() {
+ #[derive(Clone, Debug, Default, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
+@@ -277,20 +278,28 @@ pub async fn wait_for_shutdown() {
  }
  
  pub fn rustls_client_config(allow_invalid_certs: bool) -> ClientConfig {
@@ -587,19 +1066,14 @@ index 2b73df148..2efcc96d7 100644
  
      if !allow_invalid_certs {
 -        let mut root_cert_store = RootCertStore::empty();
--
++        #[cfg(feature = "tls-native-roots")]
++        let config = config.with_platform_verifier();
+ 
 -        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
@@ -611,12 +1085,15 @@ index 2b73df148..2efcc96d7 100644
 +                })
 +                .collect::<rustls::RootCertStore>(),
 +        );
-+
+ 
+-        config
+-            .with_root_certificates(root_cert_store)
+-            .with_no_client_auth()
 +        config.with_no_client_auth()
      } else {
          config
              .dangerous()
-@@ -316,6 +324,18 @@ pub fn rustls_client_config(allow_invalid_certs: bool) -> ClientConfig {
+@@ -299,6 +308,18 @@ pub fn rustls_client_config(allow_invalid_certs: bool) -> ClientConfig {
      }
  }
  
@@ -636,7 +1113,7 @@ index 2b73df148..2efcc96d7 100644
  struct DummyVerifier;
  
 diff --git a/crates/utils/src/suffixlist.rs b/crates/utils/src/suffixlist.rs
-index e0921abe3..b53126ae9 100644
+index e0921abe..b53126ae 100644
 --- a/crates/utils/src/suffixlist.rs
 +++ b/crates/utils/src/suffixlist.rs
 @@ -111,7 +111,12 @@ impl PublicSuffix {
@@ -654,10 +1131,10 @@ index e0921abe3..b53126ae9 100644
                          if r.status().is_success() {
                              r.bytes().await
 diff --git a/tests/Cargo.toml b/tests/Cargo.toml
-index 386b8255a..68692e939 100644
+index b054e41f..1d1762d8 100644
 --- a/tests/Cargo.toml
 +++ b/tests/Cargo.toml
-@@ -59,7 +59,7 @@ rayon = { version = "1.5.1" }
+@@ -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"
@@ -667,10 +1144,10 @@ index 386b8255a..68692e939 100644
  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
+index fb6f5fe8..c36654e6 100644
 --- a/tests/src/jmap/auth_oauth.rs
 +++ b/tests/src/jmap/auth_oauth.rs
-@@ -411,7 +411,7 @@ async fn post_bytes(
+@@ -406,7 +406,7 @@ async fn post_bytes(
      auth_token: Option<&str>,
      params: &AHashMap<String, String>,
  ) -> Bytes {
@@ -679,7 +1156,7 @@ index 0d05d3a77..fff811fcf 100644
          .timeout(Duration::from_millis(500))
          .danger_accept_invalid_certs(true)
          .build()
-@@ -437,7 +437,7 @@ async fn post_json<D: DeserializeOwned>(
+@@ -432,7 +432,7 @@ async fn post_json<D: DeserializeOwned>(
      auth_token: Option<&str>,
      body: &impl Serialize,
  ) -> D {
@@ -688,7 +1165,7 @@ index 0d05d3a77..fff811fcf 100644
          .timeout(Duration::from_millis(500))
          .danger_accept_invalid_certs(true)
          .build()
-@@ -473,7 +473,7 @@ async fn post_with_auth<T: DeserializeOwned>(
+@@ -468,7 +468,7 @@ async fn post_with_auth<T: DeserializeOwned>(
  }
  
  async fn get_bytes(url: &str) -> Bytes {
@@ -698,10 +1175,10 @@ index 0d05d3a77..fff811fcf 100644
          .danger_accept_invalid_certs(true)
          .build()
 diff --git a/tests/src/jmap/mod.rs b/tests/src/jmap/mod.rs
-index 554026a00..ffd8d292a 100644
+index f44f0781..fbf22556 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
+@@ -700,7 +700,7 @@ pub async fn jmap_raw_request(body: impl AsRef<str>, username: &str, secret: &st
        }"#;
  
      String::from_utf8(
@@ -710,7 +1187,7 @@ index 554026a00..ffd8d292a 100644
              .danger_accept_invalid_certs(true)
              .timeout(Duration::from_millis(1000))
              .default_headers(headers)
-@@ -620,7 +620,7 @@ impl ManagementApi {
+@@ -901,7 +901,7 @@ impl ManagementApi {
          query: &str,
          body: Option<String>,
      ) -> Result<String, String> {
@@ -720,10 +1197,10 @@ index 554026a00..ffd8d292a 100644
              .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
+index 0a553b74..ed2a88d9 100644
 --- a/tests/src/smtp/management/queue.rs
 +++ b/tests/src/smtp/management/queue.rs
-@@ -493,7 +493,7 @@ async fn manage_queue() {
+@@ -489,7 +489,7 @@ async fn manage_queue() {
  
      // Test authentication error
      assert_eq!(
@@ -732,16 +1209,6 @@ index e86f55169..a0d144127 100644
              .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()
+-- 
+2.49.0
+