Files
2026-10-26 16:01:14 +01:00

47 KiB
Raw Permalink Blame History

theme, title, titleTemplate, favicon, info, author, keywords, class, highlighter, lineNumbers, drawings, transition, mdc, fonts, hideInToc
theme title titleTemplate favicon info author keywords class highlighter lineNumbers drawings transition mdc fonts hideInToc
default Stalwart: One server. Every protocol. %s ./favicon.svg Stalwart presentation: an open-source mail and collaboration server written in Rust. Source at github.com/stalwartlabs/stalwart. Stalwart Labs LLC stalwart, email, jmap, imap, smtp, caldav, carddav, webdav text-left shiki false
persist
false
slide-up true
sans mono weights italic provider
Inter JetBrains Mono 400,500,600,700 false none
true
An open-source mail & collaboration server

Stalwart.
One server. Every protocol.

An open-source mail and collaboration server written in Rust.

Stalwart Labs

class: storm

Running your own mail used to be normal.

In the 90s every university and small company ran their own mail server. Today, almost no one does. What changed?

1971 · First e-mail 1982 · SMTP (RFC 821) 1984 · POP (RFC 918) 1986 · UUCP (RFC 976) 1988 · IMAP (RFC 1064) 2004 · Gmail launches 2019 · JMAP for Mail (RFC 8621)
<style> .timeline { margin-top: 2rem; display: flex; flex-direction: column; gap: 0.6rem; font-family: var(--font-mono); font-size: 0.95rem; color: var(--text-muted); } .timeline span { position: relative; padding-left: 1.25rem; } .timeline span::before { content: ""; position: absolute; left: 0; top: 50%; transform: translateY(-50%); width: 0.45rem; height: 0.45rem; border-radius: 50%; background: var(--brand); } </style>

class: storm

What it actually takes to run a mail server.

12 daemons. 12 configuration formats. 12 places things break.


class: storm

Why it stopped being normal.

  • Mail server software has barely changed in 20+ years.
  • Each tool has its own configuration file, its own quirks.
  • Maintenance demands expertise across unrelated systems.
  • Debugging means correlating across scattered logs.
  • Cross-tool dependencies break in subtle ways.
  • No unified UI; admins juggle CLIs and ad-hoc scripts.
  • None of it was designed for clusters or modern protocols.

class: storm

The wrappers help, but only so much.

Mail-in-a-Box, iRedMail, Mailcow are good-faith attempts that wrap the legacy stack instead of replacing it.

The twelve daemons are still there underneath, with the same failure modes, the same scattered configuration, the same upgrade pain. Useful for evaluation; not a long-term answer.


class: storm transition: fade

There has to be a better way.

EHLO yourcompany.org
220 mail.stalw.art Stalwart ESMTP at your service
<style> .cursor { display: inline-block; width: 0.5em; height: 1em; background: var(--brand); margin-left: 0.25em; vertical-align: middle; animation: blink 1s steps(1) infinite; } @keyframes blink { 50% { opacity: 0; } } </style>

layout: center class: text-center


Stalwart, in two sentences.

One server that speaks every protocol your clients already use.

With a built-in spam and phishing filter, encryption at rest, automated TLS and DNS, and a web admin. Open source, written in Rust.


From zero to a running server.

$ curl --proto '=https' --tlsv1.2 -sSf https://get.stalw.art/install.sh -o install.sh
$ sudo sh install.sh

Two commands. The installer creates a service user, writes the systemd unit, and starts Stalwart.


Find the bootstrap admin in the logs.

$ sudo journalctl -u stalwart -n 200 | grep -A8 'bootstrap mode'
════════════════════════════════════════════════════════════
🔑 Stalwart bootstrap mode - temporary administrator account
 
username: admin
password: uj2Q0ffCl4sZvIJi
 
Use these credentials to complete the initial setup at the
/admin web UI.
════════════════════════════════════════════════════════════

Sign in at http://<host>:8080/admin with these credentials; the wizard takes over.


clicks: 5

The first run is a wizard, not a config file.


Done. Your mail server is running.

Mail, calendars, contacts, files: every protocol up and serving, on the very first start.


Easy to install. Anything but limited.

Configuration scale

2,494 settings, 117 objects, 176 screens.

2,494settings
117Config objects
176WebUI screens
659permissions
339metrics
671event types

And you do not have to touch any of them on day one.

Every setting ships with a safe default chosen for a hardened, production-ready configuration. Customise only what your deployment actually requires.


Under the hood.


layout: center class: text-center


JMAP: the modern replacement for IMAP.

  • Open IETF standard.
  • Much Simpler: 5× smaller than IMAP
  • A fast-growing ecosystem.
  • Real-time push: Instant updates. Zero overhead.
  • 2–3× less power usage than IMAP, measured on real devices.
  • Sync changes more easily, more efficiently, and much, much faster.
{
  "using": ["urn:ietf:params:jmap:core",
            "urn:ietf:params:jmap:mail"],
  "methodCalls": [
    ["Email/changes",
     { "accountId": "u1", "sinceState": "42" },
     "0"],
    ["Email/get", {
      "accountId": "u1",
      "#ids": { "resultOf": "0",
                "name": "Email/changes",
                "path": "/created" },
      "properties": ["subject", "from", "receivedAt"]
    }, "1"]
  ]
}

One HTTP request returns every new message since the client last synced.


Every JMAP extension that exists today is supported.

  • JMAP Core (RFC 8620)
  • JMAP for Mail (RFC 8621)
  • JMAP for Sieve Scripts
  • JMAP over WebSocket (RFC 8887)
  • JMAP Blob Management (RFC 9404)
  • JMAP for Quotas (RFC 9425)
  • JMAP for Calendars, Contacts, File Storage
  • JMAP Sharing

Stalwart is the most complete JMAP server in the open-source world.


And every legacy protocol your fleet still needs.

  • IMAP4rev2 (RFC 9051) and IMAP4rev1 (RFC 3501).
  • QUOTA, ACL, CONDSTORE, QRESYNC and dozens of other extensions.
  • POP3 with STLS and SASL.
  • ManageSieve for user-managed server-side filters.

DNS, automated.

DNS is the most common reason a mail deployment breaks.

  • Automatic publication of MX, SPF, DKIM, DMARC, TLSA, MTA-STS, autoconfig, autodiscover.
  • Direct integration with Cloudflare, Route 53, Google Cloud DNS, DigitalOcean, OVH, deSEC and more.
  • Self-hosted authoritative servers via TSIG / SIG(0) (RFC 2136).

DKIM keys rotate themselves.

  • New keys generated on a schedule (default: 90 days).
  • Published in DNS automatically.
  • Activated only after propagation is observed.
  • Old keys retired on a configurable grace period.
  • Emergency rotation on demand.

The single biggest avoidable cause of email-auth outages, automated.


Certificates renew themselves.

  • Every supported ACME challenge: TLS-ALPN-01, DNS-01, HTTP-01, DNS-PERSIST-01.
  • External Account Binding for CAs that require it.
  • TLSA records refresh automatically when a certificate rolls over, so DANE keeps validating.
  • On-demand renewal triggered after a DNS update.

Clients configures themselves.

Point any standard mail client at example.com and it gets back JMAP, IMAP, POP3, SMTP, CalDAV and CardDAV settings without a host name typed.

  • UA Autoconfig (PACC).
  • Mozilla Autoconfig (Thunderbird family).
  • Microsoft Autodiscover v1 and v2 (Outlook).

All three formats served from the same endpoint.

GET /.well-known/user-agent-configuration.json
GET /.well-known/autoconfig/mail/config-v1.1.xml
POST /autodiscover/autodiscover.xml

Multi-tenant from the ground up.

  • Account, domain and tenant isolation by design.
  • Disk quotas per user and per tenant.
  • Email aliases with descriptions; alias mechanism can be disabled per account.
  • Domain aliases (one domain pointing at another).
  • Plus-addressing, sub-addressing, catch-all, mailing lists.
  • Per-domain directory backends: each domain can use its own LDAP, OIDC or SQL.
  • Per-tenant branding on the web admin and the end-user account portal.

Server-side mail rules, in standard Sieve.

  • Every IANA-registered Sieve extension.
  • Users edit their own scripts via ManageSieve or JMAP.
  • Trusted scripts run at SMTP stages with elevated permissions.
require ["fileinto", "imap4flags", "vacation", "envelope"];

if header :contains "List-Id" "@" {
  fileinto "INBOX/Newsletters";
  stop;
}

if envelope :is "from" "alerts@monitoring.example.com" {
  addflag "\\Flagged";
  fileinto "INBOX/Alerts";
  stop;
}

vacation :days 7
  "I am away until Monday. Will reply on return.";

layout: center class: text-center


An SMTP server built into the same product.

  • Sender authentication built in (DMARC, DKIM, SPF, ARC, reverse-DNS).
  • Transport security verified end to end (DANE, MTA-STS, TLS-RPT).
  • A distributed, fault-tolerant queue.
  • A programmable filter pipeline at every SMTP stage.

No second product to deploy, no glue between MTA and message store.


Every inbound message: authenticated.

  • DMARC alignment + reporting.
  • DKIM verification, signing, failure reporting.
  • SPF policy evaluation + failure reporting.
  • ARC chain verification.
  • Reverse-DNS validation.
  • Tag-based scoring shared with the spam filter.

Reports both ways: ingested and emitted.

Stalwart ingests received DMARC, TLS-RPT and ARF reports and emits outbound DMARC and TLS reports automatically. All visualised in the same admin.


Mail in transit, encrypted and verified.

  • DANE (DNS-Based Authentication of Named Entities) for outbound TLS.
  • MTA-STS policy fetching and enforcement.
  • SMTP TLS Reporting: delivery and ingestion.
  • Automatic TLSA refresh on certificate rotation.

Flexible distributed queues.

  • Queue is shared across the cluster, not a per-node spool.
  • Unlimited virtual queues, each with its own concurrency, retries, quota.
  • Delayed delivery, priority delivery, per-queue throttling.
  • Smart-host and relay routing for upstream submission.
  • Managed from WebUI, CLI or JMAP API.

Filter at every SMTP stage.

Every stage can run rules. Late stages can do anything; early stages can reject before the message body is even transferred, so abuse pays the lowest possible cost.


Configuration is programmable, not just declarative.

Small conditional programs, compiled to bytecode at startup; evaluated at runtime against context variables.

  • remote_ip, rcpt, retry_num, is_tls, ...
  • Functions: dns_query, is_local_domain, matches, counter_incr, ...
  • The same shape applies wherever a setting can be conditional.
{
  "saslMechanisms": {
    "match": [{ "if": "local_port != 25 && is_tls",
                "then": "[plain, login]" }],
    "else": "false"
  },
  "route": {
    "match": [
      { "if": "is_local_domain(rcpt_domain)",
        "then": "'local'" },
      { "if": "retry_num > 1",
        "then": "'fallback'" }
    ],
    "else": "'mx'"
  }
}

Expressions in action: spam filtering.

Expressions are also used to build spam filter rules.

  • ip_reverse_name(remote_ip) builds the reverse-DNS query.
  • dns_query(...) issues a live A-record lookup.
  • The matched return code (127.0.0.2, 127.0.0.3, ...) maps to a Spamhaus list (SBL, CSS, XBL, ...).
  • The matching list name becomes the spam-filter tag, scored elsewhere.
{
  "tag": {
    "match": [
      { "if": "contains(dns_query(
        ip_reverse_name(remote_ip) + '.zen.spamhaus.org', 'ipv4'), '127.0.0.2')",
        "then": "'SBL'" },
      { "if": "contains(dns_query(
        ip_reverse_name(remote_ip) + '.zen.spamhaus.org', 'ipv4'), '127.0.0.3')",
        "then": "'CSS'" },
      { "if": "contains(dns_query(
        ip_reverse_name(remote_ip) + '.zen.spamhaus.org', 'ipv4'), '127.0.0.4')",
        "then": "'XBL'" }
    ],
    "else": "false"
  }
}

Plug the filters that you already run.

  • Sieve scripts callable from any SMTP stage with elevated permissions.
  • Milter for Rspamd, SpamAssassin, ClamAV, any sendmail-compatible filter.
  • MTA Hooks: same lifecycle, over HTTP + JSON.
  • Per-stage invocation: hook into CONNECT, EHLO, AUTH, MAIL FROM, RCPT TO, DATA, post-DATA.

Rewrite policy enforced at the server.

  • Sender, recipient, domain rewriting.
  • Header add / modify / remove.
  • Body modification and attachment policy.
  • Programmable per listener, sender, recipient or any other message metadata.

Compliance disclaimers, address normalisation and attachment policy: enforced by the server, not asked of every user.


layout: center class: text-center


The filter ships inside the MTA.

  • One product, one process, one config surface.
  • Spam is rejected at SMTP time, before a message ever reaches a mailbox.
  • Rules are compiled, not regex'd at request time.
  • Filter signal is shared with the rest of the server: auto-banning, sender reputation, address-book signal, trusted-reply tracking.

A spam classifier that learns from your users.

  • FTRL-Proximal linear classifier: an online-learning algorithm originally from Google research.
  • Continuous training from user feedback.
  • Address-book signal: senders already in the recipient's contacts pre-classify as known correspondents.
  • Trusted sender signal: addresses the user has previously emailed (Sent Items) count as known correspondents too.
<style> .classifier-shrunk { max-height: 26vh !important; } </style>

AI for the messages a classifier alone cannot judge.

  • LLM module integrated into the spam classifier.
  • Sieve functions to call an LLM directly from a script.
  • Any OpenAI-compatible endpoint: hosted (OpenAI, Anthropic) or self-hosted (Llama via vLLM / LocalAI).

Trusted Sieve scripts call the model at SMTP DATA time; users with the right permission can call it from their own scripts too.

require ["vnd.stalwart.expressions", "fileinto"];

# Ask the LLM whether this is a phishing attempt
if eval "llm('phishing-classifier',
              'Classify this message as phishing (true/false): ' + body)
        == 'true'" {
  fileinto "INBOX/Suspected-Phishing";
  stop;
}

Public blocklists and collaborative filtering.

  • IP, domain, URL and content-hash DNSBLs.
  • Pyzor for digest-based collaborative filtering.
  • Tunable thresholds and weights per source.

Phishing is structural, not lexical.

  • Homograph URL detection: visually-confusable Unicode characters in URLs (paypal.com with a Cyrillic 'а').
  • Display-name vs From-address mismatch.
  • Lookalike-domain detection against your own domain.
  • Trusted-reply tracking: real replies to messages your user sent are recognised.

Phishing rarely relies on the words in the body; it relies on the structure around them.


Reputation, learned from your own traffic.

  • Per IP, per ASN, per domain, per email address.
  • Updates with every message processed.
  • Greylisting for unknown senders.
  • Spam traps that auto-train the classifier on what they catch.
IP
+0.42
ASN
-0.18
Domain
+0.65
Address
+0.83

Brute-force and probing, blocked automatically.

  • Authentication failures (keyed on source and login, so distributed brute-force is caught even with rotating IPs).
  • SMTP relay / recipient-probing abuse.
  • Loitering connections.
  • Port and exploit-URL scanning.
  • Built-in, does not require third party software.

Or keep what you already run.

If a team already runs Rspamd / SpamAssassin / ClamAV, the built-in filter sits next to it, not in front of it.

  • Milter for sendmail-compatible filters: Rspamd, SpamAssassin, ClamAV, any Milter you have.
  • MTA Hooks for HTTP-based filters; same lifecycle as Milter, JSON over HTTP.
  • Per-stage invocation across every SMTP phase.

layout: center class: text-center


Calendars, on every device.

  • CalDAV with scheduling for desktop and mobile clients.
  • JMAP for Calendars for modern clients.
  • Personal, group and shared calendars.
  • Free/busy lookup.
  • Per-account and per-tenant caps.

Invitations, replies, free/busy.

  • iTIP / iMIP email notifications for invitations and updates.
  • Free/busy availability for organisers.
  • Federated cross-server scheduling.
  • Reply tracking visible to organisers.

Contacts, synchronised everywhere.

  • CardDAV (vCard 2.1 / 3.0) for legacy clients.
  • JMAP for Contacts for modern clients.
  • Personal, group and shared address books.
  • The address-book signal feeds the spam filter and the calendar scheduler: a sender already in a recipient's contacts is treated as a known correspondent.

File storage, alongside the mail.

  • WebDAV for desktop and mobile file managers.
  • JMAP for File Storage for modern clients.
  • Personal, group and shared file spaces.
  • Unified disk quota with email storage: no end-run around the cap.

One sharing model: calendars, contacts, files.

  • Read, write and manage rights, per principal.
  • User and group sharing.
  • Backed by WebDAV ACL and JMAP Sharing standards.
  • The same UI for all three resource types.

Works with every standard client your fleet runs.

No proprietary client. No vendor lock-in. Anything that speaks the standards works.

  • Apple Mail, Calendar, Contacts (macOS, iOS).
  • Mozilla Thunderbird with the calendar and contact add-ons.
  • GNOME Evolution and KDE Kontact.
  • Microsoft Outlook (Autodiscover v1 / v2).
  • Mobile iOS and Android clients via standard IMAP, CalDAV, CardDAV.
  • Any RFC-compliant JMAP, POP3 or WebDAV client.
  • Autoconfig discovery: clients fetch IMAP, SMTP, CalDAV and CardDAV settings automatically when pointed at the domain.
  • iMIP fallback for attendees on servers Stalwart cannot reach directly.
  • Server-side email reminders (VALARM with EMAIL), so a reminder fires even when the calendar app is closed.

layout: center class: text-center


Mailboxes encrypted with the user's own public key.

  • S/MIME and OpenPGP support.
  • Automatic encryption of plain-text messages on receipt.
  • Optional obfuscation in the full-text search store.
  • No private keys stored on the server. An operator with disk access cannot read mailboxes.

Modern authentication with OIDC and MFA.

  • OpenID Connect.
  • OAuth 2.0 with authorization-code and device-code flows.
  • LDAP / OIDC / SQL or built-in directory.
  • TOTP two-factor authentication.
  • Application passwords with labels, IP restrictions, expiry.
  • API keys with the same controls.

Disposable addresses, for users who care about privacy.

A different email address for every site a user signs up to, so a leak at one site does not become spam at the rest.

  • End users create disposable addresses directly from their account portal.
  • Each mask carries a description and an enabled toggle.
  • Disable a leaking address without losing the record of where it was handed out.
  • Standard interoperability with password managers that support the protocol.

Auto-banning, rate limits, ACLs.

  • Automatic IP banning across four abuse categories (auth, relay/probing, loitering, scanning).
  • Rate and concurrency limiting per listener and per principal.
  • ASN and GeoIP blocking; per-account IP restrictions.
  • Roles, groups, ACLs, granular permissions: 659 of them, scoped independently.

Rust-native, audited, open.

  • Written in Rust: removes whole classes of vulnerability common to older mail servers (use-after-free, buffer overruns, type confusion in protocol parsers) at compile time.
  • Independent security audit with the report published openly on the Stalwart blog.
  • Source on GitHub under AGPL-3.0; anyone can read or fork it.

layout: center class: text-center


Day-to-day operations live in a browser.

Dashboard, queue, accounts, domains, settings, log viewer, report visualisation: all in the same console.


Every setting, surfaced as a form.

176 screens, organised by topic. Most operators only ever touch a handful.

  • Network, Storage, TLS, MTA, Cluster, Spam Filter
  • Email, Calendar & Contacts, Files & Sharing
  • Sieve, Security, Lookups, Search
  • Telemetry, Task Manager, AI, Web Applications

Get deleted mail back, without restoring from backup.

Most "we need to restore from backup" tickets are really about a single deleted mailbox or a handful of messages.

  • Deleted emails kept in an archive for a configurable retention window.
  • Browse archived items with original sender, subject and date.
  • Restore individual messages or whole accounts in a few clicks.
  • The same archive backs full account un-deletion.

Or treat the whole thing as code.

# Reconcile a declarative bundle of objects against
# a running server, dry-run first.
stalwart-cli apply --file plan.ndjson --dry-run
stalwart-cli apply --file plan.ndjson

# Snapshot the running state back to disk.
stalwart-cli snapshot --output current.ndjson
{"@type":"Domain","id":"example-org",
 "name":"example.org"}
{"@type":"DkimSignature","domain":"example.org",
 "algorithm":"ed25519","selector":"v1-ed25519-20260418"}
{"@type":"Account","email":"alice@example.org",
 "fullName":"Alice","quota":2147483648}

NDJSON in, NDJSON out. NixOS, Ansible and Terraform fit naturally on top.


Logs, metrics, traces, webhooks, alerts.

  • Logging and tracing to OpenTelemetry, journald, files, console.
  • Metrics with OpenTelemetry and a Prometheus pull endpoint.
  • Webhooks for event-driven automation.
  • Live tracing over Server-Sent Events for real-time triage.
  • Email and webhook alerts on metric expressions: combine multiple metrics, fire only on patterns operators care about.

layout: center class: text-center


From one node to a multi-region cluster.


High availability without proxies or directors.

  • No leaders, no read-replica routing required.
  • Any user can connect to any node.
  • Adding a node adds capacity. Losing a node sheds load.
  • Network-partition-tolerant failure detection.

Unlike traditional IMAP servers that pin users to a "director", Stalwart treats every node as an equal peer.


Clients can connect to any node.

Four storage tiers, each with a backend chosen for its job.


FoundationDB for the metadata tier.

  • Distributed ACID transactions; strict serializable consistency.
  • Apache 2.0; battle-tested at production scale.
  • Apple uses FoundationDB for iCloud / CloudKit.
  • Stalwart uses FDB's transactional model directly, not through an intermediary.

Stalwart can run on the same metadata tier as iCloud.


Ceph and S3 for the blob tier.

  • Message bodies, attachments, Sieve scripts, WebDAV files: all in the blob tier.
  • Ceph for self-hosted deployments at petabyte-to-exabyte scale (CERN, OVHcloud, DigitalOcean).
  • S3-compatible for cloud and hybrid: AWS S3, GCS, MinIO, Garage, anything that speaks the S3 API.
  • Sharded blob storage spreads message bodies across multiple backends; throughput grows with each shard.

No filesystem dependencies. No silos. The blob tier scales independently of the metadata tier.


Search where it makes sense for the deployment.

Engine Best for Notes
Internal small to medium bloom-filter index built into Stalwart, 17 languages, no extra service
Meilisearch medium lightweight, single-node, fast indexing
Elasticsearch / OpenSearch large to very large distributed search at scale
PostgreSQL / MySQL reuse existing leverage a relational backend already in the stack

Search is the one tier where the right answer changes with deployment size.


A queue that scales horizontally.

  • Queue is shared across the cluster, not per-node.
  • Any node delivers any message; a node failure strands nothing.
  • Outbound throughput grows by adding outbound nodes; nothing else needs to change.

Outbound MTA can be a dedicated cluster role for high-volume delivery tiers.


FTRL-Proximal: classification in microseconds.

Not a bottleneck, even at very high volume.

  • Online learning algorithm, fixed-size model regardless of vocabulary (hashing trick).
  • No per-token database lookup chain at classification time.
  • Default model: 220 parameters, ~4 MB RAM.
  • Cuckoo hashing reduces collisions in large deployments.
  • Classification cost is pure computation, not I/O bound.

Coordinator-less, or one of four backends.

  • Peer-to-peer over Eclipse Zenoh: no external coordinator required.
  • Or one of: Apache Kafka, Redpanda, NATS, Redis.
  • Used for state synchronisation, blocked-IP gossip, certificate renewals, push notifications.
Zenoh (P2P) Kafka Redpanda NATS Redis

Runs on the modern orchestrators.

  • Kubernetes (Helm chart available).
  • Apache Mesos.
  • Docker Swarm.
  • Plain Docker for evaluation.
  • Proxmox for on-premise virtualisation.

The orchestrator handles node lifecycle and scaling; the coordination layer keeps state in step. Stalwart is happy with either.


How operators actually lay out a cluster.

  • Unified. Every node serves every protocol. Simple deployment, even failover.
  • Service-specific. Dedicated nodes per protocol. Optimised tuning, isolated failures.
  • Weighted. Sized by expected per-protocol load (more IMAP than WebDAV).
  • Protocol pairing. Group complementary protocols (IMAP + Submission, SMTP + queue).
  • Geographic. Multi-region distribution, low latency, data sovereignty.

Most deployments start unified and evolve to weighted or geographic.


Stalwart is ready for extremely large deployments.

FoundationDB for metadata at iCloud scale. Ceph and S3 for blobs at exabyte scale. Distributed queue with no per-node spool. Classification in microseconds. The components are there today; the operator picks which to use.

"It scales because the storage tiers do. The mail server stops being the bottleneck."


layout: center class: text-center


One server. Every protocol. Sane defaults.

JMAP, IMAP, POP3, SMTP, CalDAV, CardDAV, WebDAV: one process.
Spam filter, encryption at rest, automated TLS and DNS: included.
Web admin, CLI, declarative deployments: pick whichever fits.

Get Stalwart.

$ curl --proto '=https' --tlsv1.2 -sSf https://get.stalw.art/install.sh -o install.sh
$ sudo sh install.sh
Website
stalw.art
install, configure, scale
Source (Github)
stalwartlabs/stalwart
AGPL-3.0
Community
Reddit · Discord · Matrix
support.stalw.art

layout: center class: text-center storm

Thank you.

mail.stalw.art
QUIT
221 mail.stalw.art Thanks for listening, see you again soon.

Stalwart Labs ·  hello@stalw.art  ·  stalw.art

<style> .bye { margin: 1.5rem auto 0 auto; max-width: 720px; background: var(--code-bg); border: 1px solid var(--border); border-radius: 12px; overflow: hidden; text-align: left; box-shadow: var(--shadow-1); } .bye__chrome { display: flex; align-items: center; gap: 0.4rem; padding: 0.45rem 0.7rem; background: var(--surface-2); border-bottom: 1px solid var(--border); } .bye__dot { width: 9px; height: 9px; border-radius: 50%; display: inline-block; } .bye__dot--r { background: #ff5f57; } .bye__dot--y { background: #febc2e; } .bye__dot--g { background: #28c840; } .bye__title { margin-left: 0.6rem; font-family: var(--font-mono); font-size: 0.78rem; color: var(--text-muted); } .bye__body { padding: 1rem 1.25rem; font-family: var(--font-mono); font-size: 0.95rem; line-height: 1.7; } .bye__line { display: block; } .bye__line--cmd { color: var(--text-muted); } .bye__line--reply { color: var(--brand); font-weight: 600; } </style>