JMAP "fetch failed"

Your question

Hello all,

Trying to use a JMAP client to my new installation. I tried Parula (which works with IMAP, but not with JAMP), Boogie Mail (IOS, which gives me a fetch failed), Bulwark webmail client. They all give me the “fetch failed” error.

While trying to troubleshoot like below, I get an empty http response:

curl -sv https://myserver.domain.tld/.well-known/jmap

Host myserver.domain.tld:443 was resolved.

IPv6: (none)

IPv4: 10.135.101.53

Trying 10.135.101.53:443…

ALPN: curl offers h2,http/1.1

TLSv1.3 (OUT), TLS handshake, Client hello (1):

SSL Trust Anchors:

CAfile: /etc/ssl/certs/ca-certificates.crt

TLSv1.3 (IN), TLS handshake, Server hello (2):

TLSv1.3 (IN), TLS change cipher, Change cipher spec (1):

TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):

TLSv1.3 (IN), TLS handshake, Certificate (11):

TLSv1.3 (IN), TLS handshake, CERT verify (15):

TLSv1.3 (IN), TLS handshake, Finished (20):

TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):

TLSv1.3 (OUT), TLS handshake, Finished (20):

SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / X25519MLKEM768 / id-ecPublicKey

ALPN: server did not agree on a protocol. Uses default.

Server certificate:

subject: CN=rcgen self signed cert

start date: Jan 1 00:00:00 1975 GMT

expire date: Jan 1 00:00:00 4096 GMT

issuer: CN=rcgen self signed cert

Certificate level 0: Public key type EC/prime256v1 (256/128 Bits/secBits), signed using ecdsa-with-SHA256

subjectAltName does not match hostname myserver.domain.tld

SSL: no alternative certificate subject name matches target hostname ‘myserver.domain.tld’

closing connection #0

The certificate is self-signed, but still, shouldn’t I get some json formated output ? Or what shall I expect from this command ?

Thanks a lot

The empty response you’re seeing from curl isn’t actually a JMAP problem, it’s TLS failing before curl ever gets an HTTP response. The log shows the connection was aborted because the certificate presented doesn’t match your hostname (“subjectAlternativeName does not match hostname”). That’s a client-side abort, not a server bug: curl refuses to read the body when the cert doesn’t validate.

Your server is falling back to its built-in self-signed placeholder certificate (CN=rcgen self signed cert), which means no valid Certificate is bound to that hostname yet. This happens if:

  • No Domain object exists for myserver.domain.tld with a working certificateManagement set (Manual or Automatic/ACME), or
  • The domain has automatic (ACME/Let’s Encrypt) certificate management but hasn’t successfully issued a certificate yet, or
  • No defaultCertificateId is set on SystemSettings and the listener has no matching Certificate for that SNI.

You have two options:

  1. Test JMAP client behavior ignoring the cert with curl -sv -k https://myserver.domain.tld/.well-known/jmap — if that returns proper JSON, it confirms the JMAP endpoint itself is fine and the only problem is the invalid cert.
  2. Fix TLS: either upload a real Certificate object for that hostname or configure Domain certificateManagement to use an AcmeProvider (Let’s Encrypt) so a valid certificate is issued automatically.

Once the certificate matches the hostname, JMAP clients like Parula/Boogie/Bulwark should stop failing with “fetch failed”, since that error is typically the client’s TLS handshake aborting exactly as curl’s did.

See: TLS certificates | Stalwart and Overview | Stalwart

This is an automated reply from the Stalwart Help Bot. Other community members may follow up if this answer is incomplete or wrong.

ok, I’ve created a custom certificate which is trusted by the client. Here’s the response, which is still empty, but this time there are no errors in the response header.

###begin###

curl -sv https://myserver.domain.tld/.well-known/jmap

  • Host myserver.domain.tld:443 was resolved.
  • IPv6: (none)
  • IPv4: 10.135.101.53
  • Trying 10.135.101.53:443…
  • ALPN: curl offers h2,http/1.1
  • TLSv1.3 (OUT), TLS handshake, Client hello (1):
  • SSL Trust Anchors:
  • CAfile: /etc/ssl/certs/ca-certificates.crt
  • TLSv1.3 (IN), TLS handshake, Server hello (2):
  • TLSv1.3 (IN), TLS change cipher, Change cipher spec (1):
  • TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
  • TLSv1.3 (IN), TLS handshake, Certificate (11):
  • TLSv1.3 (IN), TLS handshake, CERT verify (15):
  • TLSv1.3 (IN), TLS handshake, Finished (20):
  • TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
  • TLSv1.3 (OUT), TLS handshake, Finished (20):
  • SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / X25519MLKEM768 / RSASSA-PSS
  • ALPN: server did not agree on a protocol. Uses default.
  • Server certificate:
  • subject: CN=MYSERVer.domain.tld; C=RO; ST=County; L=MyCity; O=MyneTWOrk; OU=IT
  • start date: Jul 4 19:37:21 2026 GMT
  • expire date: Jul 4 19:37:21 2027 GMT
  • issuer: C=RO; ST=Ilfov; L=București; O=MyneTWOrk; CN=CA_sign.domain.tld
  • Certificate level 0: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption
  • Certificate level 1: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption
  • subjectAltName: “myserver.domain.tld” matches cert’s “MYSERVer.domain.tld”
  • SSL certificate verified via OpenSSL.
  • Established connection to myserver.domain.tld (10.135.101.53 port 443) from 10.134.98.5 port 34474
  • using HTTP/1.x

GET /.well-known/jmap HTTP/1.1
Host: myserver.domain.tld
User-Agent: curl/8.17.0
Accept: /

  • Request completely sent off
  • TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
  • TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
    < HTTP/1.1 307 Temporary Redirect
    < cache-control: no-cache
    < location: /jmap/session
    < content-length: 0
    < date: Tue, 07 Jul 2026 12:41:37 GMT
    <
  • Connection #0 to host myserver.domain.tld:443 left intact
##### end ###

This is a redirect to /jmap/session. Add --location to your curl parameters to follow redirects.

I did this: curl -X POST https ://myserver.domain.tld/.well-known/jmap

and the response was:
{“type”:“about:blank”,“status”:404,“title”:“Not Found”,“detail”:“The requested resource does not exist on this server.”}

Also, after some searching I released that this is being reported by numerous people, but no solution yet.

The 307 from /.well-known/jmap to /jmap/session is correct and expected; clients (and curl with --location) follow it to get the session document, so that redirect isn’t the problem.

The actual cause is TLS. Your first trace shows the built-in self-signed fallback certificate (CN=rcgen self signed cert, SAN mismatch), which Stalwart serves when no valid certificate is configured for the hostname. JMAP clients reject that outright, which surfaces as “fetch failed.” Once you put a valid certificate in place (ACME, or an imported cert whose SAN matches the hostname), as in your second trace, the connection verifies and the 307 comes through fine. Set that up and the clients should connect. Two side notes: your POST /.well-known/jmap returning 404 is expected, fetch the session with GET and follow the redirect rather than POSTing; and the “ALPN: server did not agree on a protocol” line is cosmetic, the request still works over HTTP/1.1 as your second trace shows, so it’s not the failure.

Thanks, that one I was able to fix, but using a trusted certificate. Thanks