Skip to content

[Feature]: Telemetry improvements/suggestion #232

@timbretimber

Description

@timbretimber

Problem / Motivation

I noticed the docs for the telemetry say it checks the server header on /.well-known/jmap for stalwart_version.

Looking at the code it just reads it and checks using regex

const res = await fetch(wellKnown, {
method: 'GET',
signal: AbortSignal.timeout(3000),
});
const server = res.headers.get('server') ?? '';
const m = server.match(/(\d+\.\d+\.\d+(?:-[\w.]+)?)/);
const version = m?.[1] ?? null;

Many reverse proxies setups will strip or replace server headers.

The regex is also too permissive "nginx/1.29.3".match(/(\d+\.\d+\.\d+(?:-[\w.]+)?)/)[1] is 1.29.3 for example.

So I think this would be polluted with versions of reverse proxies.

More importantly at least in my config Stalwart doesn't return a Server header.

Response Headers
 curl -L localhost:8080/.well-known/jmap  -v
* Host localhost:8080 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying [::1]:8080...
* Connected to localhost (::1) port 8080
* using HTTP/1.x
> GET /.well-known/jmap HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/8.14.1
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 307 Temporary Redirect
< cache-control: no-cache
< location: /jmap/session
< content-length: 0
< date: Tue, 29 Apr 2026 00:00:00 GMT
* Ignoring the response-body
* setting size while ignoring
<
* Connection #0 to host localhost left intact
* Issue another request to this URL: 'http://localhost:8080/jmap/session'
* Re-using existing http: connection with host localhost
> GET /jmap/session HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/8.14.1
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 200 OK
< content-type: application/json; charset=utf-8
< content-length: 1292
< date: Tue, 29 Apr 2026 00:00:00 GMT
<

So I don't think there will be any valid responses unless this is something I turned off and forgot. Looking at the response from .well-known/jmap I think the closest thing to a version is the json value capabilities["urn:ietf:params:jmap:sieve"]["implementation"] but that's not really the same as the stalwart version.

Proposed Solution

I'm not sure what a solution is as the exact information doesn't appear to be available without authentication. Assuming capabilities["urn:ietf:params:jmap:sieve"]["implementation"] will be updated based on capabilities that could be reasonable alternative.

Alternatives Considered

No response

Feature Area

Other

Mockups / Examples

No response

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions