---
name: stalwart-mail
description: Stalwart recipe for open-forge. All-in-one secure mail and collaboration server (SMTP, IMAP, JMAP, CalDAV, CardDAV, WebDAV) written in Rust. Covers Linux/macOS installer script and Docker single-container installs.
---

# Stalwart

All-in-one secure mail and collaboration server written in Rust. Upstream: <https://github.com/stalwartlabs/mail-server>. Site: <https://stalw.art>. Docs index: <https://stalw.art/docs/install/get-started>.

Stalwart bundles a full email stack in a single binary: SMTP (with built-in DMARC, DKIM, SPF, ARC, DANE, MTA-STS and automated DKIM key rotation), IMAP4rev2, JMAP, POP3, ManageSieve, CalDAV, CardDAV, and WebDAV. Authentication backends include OIDC, LDAP, SQL, and built-in. Storage backends include local filesystem, S3-compatible object storage, PostgreSQL, MySQL, SQLite, FoundationDB, and Redis. A first-run web wizard handles domain setup, TLS provisioning, and initial admin account creation.

| | |
|---|---|
| **License** | AGPL-3.0 |
| **Stars** | ~6 K |
| **GitHub** | <https://github.com/stalwartlabs/mail-server> |
| **Site** | <https://stalw.art> |

## Compatible install methods

| Method | Upstream docs | First-party? | When to use |
|---|---|---|---|
| Linux/macOS installer script | <https://stalw.art/docs/install/get-started> | ✅ | Recommended production on a dedicated host. Interactive; installs binary + systemd unit. |
| Docker (single container) | <https://stalw.art/docs/install/platform/docker> | ✅ | Easiest path for automated or containerised deployments. All ports in one container. |

## Inputs to collect

Phase-keyed prompts. Ask at the phase where each is needed.

| Phase | Prompt | Format | Applicability |
|---|---|---|---|
| preflight | "Which install method?" | Options: `Installer script` / `Docker` | Drives which method section loads. |
| infra | "What is the public IP of the server?" | Free-text | Both methods. Needed for DNS records and reverse DNS (PTR). |
| network | "What mail domain will Stalwart serve? (e.g. `example.com`)" | Free-text | Both methods. Used as the MX, SPF, DKIM, DMARC domain. |
| network | "Confirm your cloud provider / ISP has port 25/465/587 unblocked (or you have an SMTP relay). Proceed?" | Confirm | Both methods. Unblocked outbound SMTP is a hard prerequisite. |
| network | "Does the server's reverse DNS (PTR record) already point to `mail.<domain>` or `<domain>`?" | Confirm / note | Both methods. PTR mismatch causes rejection by many receiving servers. |
| software | "Admin email address? (used for TLS certificate registration and admin account)" | Free-text | Both methods. |
| software | "Choose a storage backend" | Options: `Local filesystem` / `SQLite` / `PostgreSQL` / `MySQL` / `S3-compatible` / `FoundationDB` / `Redis` | Both methods. |
| software | "Choose an authentication backend" | Options: `Built-in` / `OIDC` / `LDAP` / `SQL` | Both methods. |

After each prompt, write the value into the state file under `inputs.*`.

## Software-layer concerns

### Key ports

| Port | Protocol | Purpose |
|---|---|---|
| 25 | TCP | SMTP (inbound from other mail servers) |
| 465 | TCP | SMTP submission (TLS) |
| 587 | TCP | SMTP submission (STARTTLS) |
| 143 | TCP | IMAP |
| 993 | TCP | IMAP over TLS |
| 4190 | TCP | ManageSieve |
| 443 | TCP | HTTPS — admin UI, JMAP, IMAP over HTTPS |
| 8080 | TCP | Alternative HTTP admin UI / JMAP |

### Config file

**Path:** `/opt/stalwart/etc/config.toml` (TOML format)

The first-run wizard writes this file. Edit it directly for post-install configuration changes.

### Data directory

**Path:** `/opt/stalwart/data/`

Stores mail data, databases (if using local backends), and generated DKIM keys.

### Admin UI

Accessible at `https://<domain>:8080/admin` after first-run wizard completes.

### Docker install

```bash
docker run -d \
  -p 443:443 \
  -p 8080:8080 \
  -p 25:25 \
  -p 587:587 \
  -p 465:465 \
  -p 143:143 \
  -p 993:993 \
  -p 4190:4190 \
  -v /opt/stalwart:/opt/stalwart \
  --name stalwart \
  stalwartlabs/mail-server:latest
```

After first start, open `https://<domain>:8080/admin` to complete the first-run wizard (domain, TLS, initial admin user).

### Installer script (Linux/macOS)

```bash
curl -fsSL https://get.stalw.art | bash
```

The script is **interactive** — it prompts for domain, TLS, and admin credentials. A systemd unit (`stalwart.service`) is created automatically.

### Required DNS records

The first-run wizard displays the exact records to add:

| Record type | Name | Value |
|---|---|---|
| MX | `@` / `<domain>` | `mail.<domain>` (or your host) |
| TXT (SPF) | `@` / `<domain>` | `v=spf1 mx ~all` (or as shown by wizard) |
| TXT (DMARC) | `_dmarc.<domain>` | `v=DMARC1; p=none; rua=mailto:...` (as shown) |
| TXT (DKIM) | `<selector>._domainkey.<domain>` | Auto-generated by Stalwart; shown in admin UI |
| PTR (rDNS) | `<outbound IP>` | `mail.<domain>` — set at your cloud provider / ISP |

## Upgrade procedure

**Installer script:**

```bash
systemctl stop stalwart
curl -fsSL https://get.stalw.art | bash
systemctl start stalwart
```

**Docker:**

```bash
docker pull stalwartlabs/mail-server:latest
docker stop stalwart
docker rm stalwart
docker run -d \
  -p 443:443 -p 8080:8080 \
  -p 25:25 -p 587:587 -p 465:465 \
  -p 143:143 -p 993:993 -p 4190:4190 \
  -v /opt/stalwart:/opt/stalwart \
  --name stalwart \
  stalwartlabs/mail-server:latest
```

Configuration and data in `/opt/stalwart/` persist across container recreates.

## Gotchas

- **Outbound SMTP ports are blocked by default on most cloud providers.** AWS, GCP, and Hetzner block ports 25/465/587 on new instances. You must request unblocking through the provider's support process, or configure Stalwart to relay outbound mail through a transactional email service (e.g. Resend, SendGrid, Mailgun). Residential ISPs almost universally block these ports.
- **Reverse DNS (PTR) is mandatory for deliverability.** The PTR record for your server's outbound IP must resolve to your mail domain. Without it, many receiving mail servers will reject or spam-filter your messages. Set PTR at your cloud provider's control panel — not in your DNS registrar.
- **DNS records must exist before mail flows.** MX, SPF, DKIM, and DMARC records are required for both inbound delivery and outbound acceptance. Stalwart's first-run wizard shows exactly which records to add; add them before accepting live mail.
- **The installer script is interactive.** Running `curl ... | bash` non-interactively requires pre-answered prompts. For automated or unattended deployments, Docker is the simpler path.
- **Ports below 1024 require elevated privileges.** Stalwart must either run as root, have `CAP_NET_BIND_SERVICE` granted via `setcap cap_net_bind_service+ep /path/to/stalwart`, or sit behind a port-forwarding proxy that maps privileged ports to unprivileged ones.
- **DKIM keys are auto-rotated.** Stalwart rotates DKIM signing keys automatically. When a rotation happens, the new TXT record must be published in DNS. The admin UI shows the current required records; check it after any rotation event.

## Links

- Site: <https://stalw.art>
- Docs (get started): <https://stalw.art/docs/install/get-started>
- Docker install docs: <https://stalw.art/docs/install/platform/docker>
- GitHub: <https://github.com/stalwartlabs/mail-server>
- Docker Hub image: <https://hub.docker.com/r/stalwartlabs/mail-server>
