Skip to content

v40.0

Latest

Choose a tag to compare

@pierre-b pierre-b released this 05 Sep 12:13
  • Licence: Notifuse v40.0 and every later release are published under the Business Source License 1.1, and each one converts to AGPL-3.0-or-later four years after it ships. Every version up to and including v39.x stays AGPL-3.0-or-later permanently; the change is not retroactive and cannot be made so.

    What you may do is close to what you could do before, and the Additional Use Grant says it in full rather than leaving it to interpretation. You may run Notifuse in production, for a business, at any scale. You may read, modify and redistribute the source. You may host it for other people and charge them for it — the grant permits third-party hosting explicitly, which is the clause most licences of this kind exist to forbid. The one thing it withholds is using a Licensed Feature in production without a key, and the five are named in the licence file itself rather than on a web page we could quietly edit: a fourth workspace, a permission set that is not full access, an Amazon SES tenant, single sign-on, and a multilingual template variant.

    The reason is maintenance, and it is worth being direct about it. Notifuse is built and maintained by one person. Under AGPL, anyone could take the whole thing, run it as a paid service, and contribute nothing back — and the practical answer to "who pays for the next five years of security patches, provider integrations and Postgres upgrades" was nobody in particular. BSL closes that one door and leaves every other one open. It is the same step Sentry, HashiCorp, CockroachDB, MariaDB and Grafana each took at the point where the project became something people run in production and depend on, and it is a sign the project is being run as a business that expects to still be here in ten years rather than as a side project that might not be. Software you put your customer communications through should be boring about its own survival.

    We think the four-year conversion is the part that matters most, because it is what makes this reversible in your favour and not in ours. Nothing is withdrawn permanently. Every line published under BSL becomes AGPL on a clock that runs per version and does not depend on us still being here, still being solvent, or still being interested. If Notifuse disappeared tomorrow, the code you are running today becomes free software on schedule regardless.

    Practically, for most people, nothing changes. If you self-host without a licence key, you are unaffected by the licence and affected only by the five capabilities below. There is no telemetry gate, no activation, no account and no phone-home; verification of a key is offline against a signature compiled into the binary. notification_center/ is MIT so you can embed it anywhere, and web_analytics_sdk/ stays AGPL-3.0-or-later because it runs in your visitors' browsers. LICENSING.md sets out which licence applies where.

    One consequence for contributors: pull requests are not currently being accepted, and a contributor licence agreement (CLA.md) will govern them when they are. A project that is not purely AGPL cannot take patches under an inbound licence it has no right to relicense, and pretending otherwise would be storing up a problem for whoever inherits this.

  • Change: Five capabilities now require a licence key. Notifuse stays free to run and to self-host, and an installation with no key keeps everything it has today except these: creating a fourth workspace; granting permissions that are not full access — setting a member's permissions, inviting a member with a restricted set, or creating an API key with a restricted scope; provisioning a new SES tenant; adding or editing a translation of a template; and signing in through single sign-on. The first four refuse at the moment you create or change something and answer 402 naming the capability that is missing; the fifth simply stops offering the SSO button.

    Nothing you already have is taken away, in any licence state. Restricted permissions already held by a member or an API key stay enforced exactly as granted — nothing widens to full access on upgrade. SES tenants already provisioned keep sending through their own tenant, and the send path contains no licence check of any kind. Custom domains keep resolving, so tracking links, unsubscribe URLs already delivered and customer-facing blogs stay up. Magic-code login always works and sessions in progress survive. Scheduled broadcasts, automations, webhooks and every integration keep running. An invitation issued while licensed is still accepted after the key lapses. Removing a member is always allowed — it is what revokes a leaked API key — and no workspace, contact, key or setting is ever deleted, hidden, disabled or made read-only. The console is never put into a restricted mode of any kind. An installation already holding more than three workspaces keeps every one of them; it simply cannot create another. In the console, a control the licence does not cover is greyed out before anything is pressed, with a notice naming the capability and the plan — narrowing a member's permissions, switching a translation on, switching SES tenant isolation on — and everything you already have stays visible and can be removed.

    Template translations are gated on authoring and on nothing else. Translations already saved keep being sent, in every licence state — the send path resolves them without asking about the licence — editing the rest of a template that carries them is never refused, and removing one is always allowed. What an unlicensed installation cannot do is add a language or change the content of one.

    If you sign in with SSO, read this before upgrading. On an installation running SSO without a licence covering it, the SSO button disappears from the sign-in page and everyone signs in with a login code instead. Nobody is locked out: an SSO account always carries a verified email address, magic-code login is available unconditionally in every licence state, and sessions already open are unaffected — the change is only visible at the next sign-in. The startup log says sso_gated=true when this applies, and the system settings panel says so next to the switch. Installing a licence that includes SSO brings the button back immediately, with no restart.

    Install a key by pasting it in Settings → Licence as the root user, or by setting NOTIFUSE_LICENSE_KEY — the environment variable wins over a stored key, and while it is set the console refuses to save one rather than storing a value that would lose to it at the next restart. Verification is offline against a signature compiled into the binary: no phone-home, no account, and nothing about your licence is sent to Notifuse to verify it. One key covers one deployment, meaning one Postgres database whatever the number of API containers. A key that reaches its expiry date keeps granting everything for a further 30 days before the installation falls back to free-tier limits.

    Connecting Zapier still mints its fixed, five-resource API key in every licence state: that scope is the product's, not a permission you chose, so no licence is needed for it.

  • Improvement: Telemetry, when switched on, also reports version, license_tier, oidc_enabled, rbac_custom and ses_tenant — never a key, an organisation, an issuer or a tenant name — and TELEMETRY=false still turns all of it off.

  • Change: The setup wizard no longer pre-ticks "subscribe to the Notifuse newsletter". Opting in is a choice you make, not one you have to undo; the switch is still there.

  • Improvement: The web analytics browser SDK is now shipped as a static file next to the console and notification center bundles, instead of being compiled into the server binary, and the script served on /na.js now carries the licence notices of everything it bundles. Official Docker images behave exactly as before. If you build the server yourself and run the binary from outside the repository, copy web_analytics_sdk/dist/notifuse-analytics.min.js into a web_analytics_sdk/dist/ directory beside it — the server looks for it relative to its working directory, and serves no /na.js at all when it is missing rather than serving a broken one.

  • Fix: A broadcast could lose recipients without saying so. Sent counted the messages a provider had refused, so a campaign that missed a third of its audience still reported itself Complete, and the reason sat in a Logs column that read a field the API has never returned, over an SMTP client that had already thrown the server's explanation away. Sent now counts only what the provider accepted, a campaign reads "Completed — N failed", Logs shows the provider's own words, and a provider that starts refusing everything pauses the campaign and emails the workspace owners instead of quietly spending the remaining recipients' retries. Figures for past broadcasts shift accordingly, and the same correction applies to the Sent measure in analytics.

  • Fix: A rejection that names the recipient — a mailbox that does not exist, a full mailbox — is no longer retried three times over generic SMTP, and no longer counts toward the circuit breaker that throttles the whole workspace. None of these were being recognised, so an imported list carrying a few dead addresses in a row slowed every other send.

  • Improvement: Failed recipients are kept and can be retried. When every delivery attempt for a recipient was refused, the queue entry used to be deleted and there was no way to find who had missed the email, let alone send it to them. Those recipients are now held for seven days and a Retry button on the broadcast sends them the same message again — fix whatever the provider objected to first. Also available as broadcasts.retryFailed.

  • Security: Cleared the high-severity findings a container scanner reports against the published image. golang.org/x/crypto moves to 0.55.0 (CVE-2026-56854) and golang.org/x/net to 0.58.0 (CVE-2026-46600) in both Go modules; neither vulnerable code path is reachable from Notifuse, which imports only bcrypt and idna from them, but the module version is what a scanner matches on. The runtime base image moves from alpine:3.19 to alpine:3.24, which is the only way to clear CVE-2026-40200 in musl — 3.19 reached end of life in November 2025 and its image never received the patched package. A side effect worth knowing: the psql and pg_dump bundled in the image go from 16.11 to 18.6, so they now work against the PostgreSQL 17 server Notifuse runs on instead of refusing with a version mismatch.

  • Security: Cleared the eight open Dependabot alerts. google.golang.org/grpc moves to 1.83.1 in both Go modules, closing CVE-2026-84304 — a stream of fragmented HTTP/2 DATA frames could exhaust the server's memory. The console's @tiptap/core moves to 3.31.2, so a __proto__ key can no longer be turned into an executable DOM attribute by the blog editor's mergeAttributes(), and fflate moves to 0.8.3 in both front-ends (CVE-2026-45820, an infinite loop on a malformed ZIP64 archive). The other two, browserslist 4.28.8 and @humanfs/node 0.16.8, are build-time only.