Preparing for Stalwart v0.16: Breaking Changes Overview #2892
Replies: 17 comments 20 replies
-
|
Breaking Change 1: 👍. Is there an expectation that everything available in the UI will have an equivalent JMAP api? Breaking Change 2: Will both JMAP and REST be available within a single release so we can incrementally migrate? Or will it be an immediate cutover? |
Beta Was this translation helpful? Give feedback.
-
|
Thank you for thinking about NixOS as well :) |
Beta Was this translation helpful? Give feedback.
-
|
The first breaking change is generally good, at least for operators managing more than a single mail server. The trade off of declarative configuration at init in exchange for consistent state across multiple nodes and single source of truth. My concern here is with configuration drift after initial bootstrap. Let’s say it’s configured in current state but then months later either you or another admin make an ad-hoc change to settings via UI or CLI. If that setting change is not manually captured in IaC (NixOS, Ansible, …). Then that change could be reverted on next deployment/system activation. I suppose that already exists as a problem today and even less transparent when it happens. Worse experience if you are managing a HA deployment. Since you are going all in here. Would like to request an enhancement to write an audit log history of configuration changes to db store and easily readable via CLI or web admin interface. Additionally, for HA or clustered deployments. Each node is required to configure a different [1] https://stalw.art/docs/cluster/configuration/node-id |
Beta Was this translation helpful? Give feedback.
-
|
With the new admin tooling and CLI, will there still be support with the cli tool to manage the blacklist? I have had it where fail2ban blocked the docker network gateway IP and the only way to restore any functionality was to console into the container and run stalwart-cli commands to remove the IP from the list |
Beta Was this translation helpful? Give feedback.
-
|
Just curious, ETA ? 1,2,3 months ? Weeks ? Hope those using stalwart through Next-cloud AIO ( less technical people) will have a smooth ride :-) (upgrade) |
Beta Was this translation helpful? Give feedback.
-
|
Hi, I will start with the template configuration I do use right now: #############################################
# Stalwart Configuration File
#############################################
#[server]
#hostname = "mail.example.com"
[server.listener."smtp"]
bind = ["[::]:25"]
protocol = "smtp"
[server.listener."submission"]
bind = ["[::]:587"]
protocol = "smtp"
[server.listener."submissions"]
bind = ["[::]:465"]
protocol = "smtp"
tls.implicit = true
[server.listener."imap"]
bind = ["[::]:143"]
protocol = "imap"
[server.listener."imaptls"]
bind = ["[::]:993"]
protocol = "imap"
tls.implicit = true
[server.listener.pop3]
bind = "[::]:110"
protocol = "pop3"
[server.listener.pop3s]
bind = "[::]:995"
protocol = "pop3"
tls.implicit = true
[server.listener."sieve"]
bind = ["[::]:4190"]
protocol = "managesieve"
[server.listener."https"]
protocol = "http"
bind = ["[::]:443"]
tls.implicit = true
[storage]
data = "sqlite"
fts = "sqlite"
blob = "sqlite"
lookup = "sqlite"
directory = "internal"
[store."sqlite"]
type = "sqlite"
path = "/var/lib/stalwart/data"
[directory."internal"]
type = "internal"
store = "sqlite"
[tracer."stdout"]
type = "stdout"
level = "info"
ansi = false
enable = true
#[server.run-as]
#user = "stalwart"
#group = "stalwart"
[authentication.fallback-admin]
user = "admin"
secret = "%{env:ADMIN_SECRET}%"
# Let's encrypt
#[acme."letsencrypt"]
#directory = "https://acme-v02.api.letsencrypt.org/directory"
#challenge = "tls-alpn-01"
#contact = ["postmaster@.example.com"]
#domains = ["mail.example.com"]
#cache = "/var/lib/acme"
#renew-before = "30d"Of this configuration from what I see is almost all needed to stay lets go trough it:
I hope this help everybody, and I do suggest to other user to do exercise this with their own configuration, so the developer can get a more specific feedback on what is actually used as configuration in the wild |
Beta Was this translation helpful? Give feedback.
-
|
I currently update the Let's Encrypt certificate on the host (via Caddy), copy it automatically to Stalwart and reload the certificate with a systemd service |
Beta Was this translation helpful? Give feedback.
-
|
I think all of these changes are great. I'm in the process of getting a cluster ready, and the conflicting settings have caused me some confusion. With that said, I use I am a bit worried about JMAP. A lot of libraries that exist currently focus on the "IMAP portion" of JMAP. Support for calling Stalwart endpoints with JMAP might be rough. With that said, ultimately as long as I can create domains and accounts with it, I can figure it out. What would migrating a 0.15 Stalwart cluster to 0.16 look like? Very excited to see large improvements like this! |
Beta Was this translation helpful? Give feedback.
-
|
Do you have preliminary documentation about the v0.16+ system somewhere that we can start studying to prepare for tooling and integration? |
Beta Was this translation helpful? Give feedback.
-
|
Breaking Change 1 feels like a big step backward to me. I've been impressed with the flexibility of the configuration system. I'm currently working on configuring Stalwart in Kubernetes. I'm storing my config file in a configmap, and storing everything that has to do with kubernetes config in my config file. I'm using a gitops approach to my configuration where all my kubernetes objects are pushed from the same git repo. This approach becomes much more difficult when I have to coordinate configuration changes between kubernetes and my database.
The problem of configuring these things in one place could be resolved by building a kubernetes operator that wraps around your new idempotent cli. However, that will still lead to more confusion. Right now if I try to change a config setting that's in my config file I get an error from the webui because my config file is read-only. That's a helpful safeguard for me that points me to go make the change in the config file instead (or remove it from An even bigger problem occurs when you start to consider Stalwart clusters (at least I think, I haven't looked into clustering yet). These are all settings that are local and specific to the current instance of Stalwart and make sense to be configured with the instance. If I were to make this deployment into a Stalwart cluster with different servers hosted in different environments, then and of these settings might be different. To store them in a shared database would be a serious problem. |
Beta Was this translation helpful? Give feedback.
-
|
Finally some reasons to upgrade for me. I'm stuck in v0.11 and was long planning to upgrade. Also, maybe now that it will act more like a cluster,
Will you be supporting distributed databases like CockroachDB or YugabyteDB as well? |
Beta Was this translation helpful? Give feedback.
-
|
Is there any plan for migration of clients who are configured to use non-email address usernames? I understand the migration will handle updating the directory structure, but what about existing mail clients in the field who are configured to authenticate using just an username? Would this be better handled in an external directory or something like that now? |
Beta Was this translation helpful? Give feedback.
-
|
Re: Breaking change 1:
Understandably.
What is the proposed configuration tree scope of that My overall sense is that some kind of separation of different of management concerns needs to co-exist with version control and idempotent application of config. Managing email users and TLS configuration as a single idempotent unit, for example, creates a lot of administrative challenges and limitations. It also creates problems to declare such boundaries as properties of Stalwart itself. So, I think the scope of the I'm imagining a scope spec passed to As a complementary feature, it might be nice someday to have a mechanism for controlling what methods can be used (e.g. |
Beta Was this translation helpful? Give feedback.
-
|
Fantastic update and changes - administering and maintaining Stalwart will be much easier under this new model, and all of these backward incompatible changes look very reasoable to me. Building on top of JMAP looks very interesting and relevant - there are many cases where shipping one request with multiple changes at once is preferred! |
Beta Was this translation helpful? Give feedback.
-
|
Is there already a go client that I can use for the JMAP endpoints or do you plan to release an openAPI spec so I can generate something? |
Beta Was this translation helpful? Give feedback.
-
|
This looks like an amazing update and I'm really excited for v0.16! The current split configuration model allows file macros to be used (in the TOML file only) for specifying things like paths to SSL certificates that are read from the local file system. Will this macro be carried over to the new configuration style (breaking change 1) and, if so, what will its usage look like? How about other existing macros? Also, how will the new configuration system affect settings that currently can only be defined in the TOML file but may need to be different per cluster node? |
Beta Was this translation helpful? Give feedback.
-
I don't like this too much. Sure, JMAP is well specified, but it's basically a meta-protocol; it's still JSON over HTTP. Now you have to somehow pack your API semantics into JMAP semantics (which in turn packs it into HTTP semantics). A big downside is, that there is hardly any tooling out there to make use of that. For REST-style APIs there is OpenAPI, tons of code gens, API clients, etc. For JMAP there is basically nothing. For integrating with third party systems I consider this a huge step backwards.
Not a fan of that either, but mostly due to subjective reasons. Would be cool if this was an optional change (i.e. it defaults to username = email, but I can still allow usernames to be used even for new accounts). My setup is single-tenant so the domain included in the username is pretty redundant. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Five Years In: Why Now?
Stalwart has been in continuous development for nearly five years. Over that time, the feature set has grown enormously, the user base has diversified, and the gap between what users need and what the current architecture can cleanly support has widened.
v0.16 addresses that gap with a comprehensive redesign of the configuration and management interface, the biggest such change in the project's history. This redesign also unlocks dozens of the most-requested features from the GitHub issue tracker, many of which were simply not possible under the old architecture.
The sections below explain each major breaking change, why it was made, and what you need to do.
Breaking Change 1: No More TOML Configuration Files
What's changing
Stalwart will no longer use TOML files for configuration. The new model is:
Why this was necessary
The old model required every node in a cluster to carry its own copy of the configuration file and stay in sync with every other node. In practice, this caused subtle, hard-to-debug divergence between nodes and made distributed deployments unnecessarily fragile.
Beyond clustering, the split between "settings that live in the file" and "settings that live in the database" was a persistent source of user confusion. It also made documentation difficult, explaining the same conceptual setting in two different places depending on where it happened to be stored.
Centralising everything in the database means:
For Ansible, NixOS, Terraform and other declarative tooling users
This is the concern most likely to affect infrastructure-as-code users, so it deserves a thorough answer.
The JSON database configuration file remains fully manageable by your existing tooling, treat it exactly as you would any other config file today.
For everything else, Stalwart v0.16 will ship an idempotent CLI with an
applycommand that accepts a declarative configuration document and reconciles the live database state to match it, removing anything absent, updating anything changed. This is the same pattern used by mature distributed systems:/_cluster/settings, which is fully idempotent and overwrites completelyThe ecosystem has adapted to this pattern repeatedly. The workflow becomes: commit your declarative config document to version control, deploy the database JSON file via your existing tooling, and run
stalwart config applyas an idempotent step in your playbook or NixOS activation script.Breaking Change 2: REST API Replaced by JMAP API
What's changing
The existing REST API for configuration and management is being replaced by a JMAP-based API. Every setting is represented as a JMAP object, and every management action is performed through JMAP method calls.
Why this was necessary
JMAP (RFC 8620) is a well-specified, transport-efficient protocol with first-class support for batch operations, push notifications, and fine-grained change tracking. Stalwart already speaks JMAP for email, extending it to administration gives you a single, consistent protocol for interacting with the entire server.
For operators and integrators, this means:
Existing scripts and integrations that call the REST API will need to be updated. The JMAP API will be fully documented with migration examples.
Breaking Change 3: Account Names Must Be Email Addresses
What's changing
Login names (account names) must now be email addresses. For example,
alicebecomesalice@example.com.Backward compatibility: Stalwart will automatically append a default domain to bare usernames at login time, so existing users will not be locked out. However, creating new accounts requires a full email address, and LDAP/external directory filters will need to be updated to query by email address rather than by bare account name.
Why this was necessary
Two related reasons drove this change.
First, multiple external directory support. Supporting more than one external directory simultaneously is architecturally difficult when account names are bare strings, there's no reliable way to know which directory a given username belongs to. Email addresses are naturally namespaced by domain, which makes the mapping unambiguous.
Second, and more importantly: the PACC specification.
The IETF is finalising the Automatic Configuration of Email, Calendar, and Contact Server Settings draft. This specification defines how clients automatically discover server settings, replacing the fragmented collection of autodiscovery mechanisms in use today (
autoconfig,autodiscover, SRV records, etc.).PACC expects login names to be shaped as email addresses. If they are not, the server is forced to reveal whether a given account exists in order to disambiguate the login, a privacy leak the spec is specifically designed to prevent. By aligning account names with email addresses, Stalwart can implement PACC correctly without leaking account existence.
PACC also brings OAuth support to the autodiscovery flow. And because this draft originates from Apple, correct PACC implementation is the path to supporting Apple Mail clients with OIDC and MFA, a long-requested feature that will become possible once this groundwork is in place.
What to Expect
A detailed migration guide will accompany the v0.16 release. If you maintain infrastructure-as-code deployments, external directory integrations, or REST API clients, now is a good time to review your setup against the changes described above.
If you have questions or concerns about how a specific setup will be affected, please reply to this thread. The goal is to make this transition as smooth as possible.
Beta Was this translation helpful? Give feedback.
All reactions