Futuristic SMTP INBOUND-only server for home usage.
  • Go 63.3%
  • Python 36%
  • Shell 0.5%
  • Dockerfile 0.2%
Find a file
loweel eecb237e95
All checks were successful
continuous-integration/drone/push Build is passing
Align documentation with current deployment
2026-06-19 16:06:37 +02:00
.vscode Some improvement 2026-05-10 14:45:42 +02:00
dav Eliminate static analysis debt 2026-06-19 13:40:37 +02:00
imapd Eliminate static analysis debt 2026-06-19 13:40:37 +02:00
smoketest Require DAV auth for health endpoint 2026-06-19 13:13:02 +02:00
smtpd Eliminate static analysis debt 2026-06-19 13:40:37 +02:00
vendor Replace WebCal cleanup with DAV smoke coverage 2026-06-19 13:01:48 +02:00
.drone.yml Publish image to Forgejo registry 2026-06-19 15:57:59 +02:00
.gitignore Ignore Python cache files 2026-05-12 10:28:20 +02:00
backend.go Refactoring + IMAP 2026-05-10 14:23:06 +02:00
config.go Replace WebCal cleanup with DAV smoke coverage 2026-06-19 13:01:48 +02:00
docker-compose.example Align documentation with current deployment 2026-06-19 16:06:37 +02:00
Dockerfile Eliminate static analysis debt 2026-06-19 13:40:37 +02:00
example-run.sh No maildir creation. 2026-05-10 15:55:02 +02:00
go.mod Eliminate static analysis debt 2026-06-19 13:40:37 +02:00
go.sum Replace WebCal cleanup with DAV smoke coverage 2026-06-19 13:01:48 +02:00
graylist.go Eliminate static analysis debt 2026-06-19 13:40:37 +02:00
handler.go Eliminate static analysis debt 2026-06-19 13:40:37 +02:00
LICENSE Update 'LICENSE' 2021-02-02 19:09:02 +00:00
logger.go Refactoring 2026-05-10 13:39:38 +02:00
README.md Align documentation with current deployment 2026-06-19 16:06:37 +02:00
REFACTORING.md Align documentation with current deployment 2026-06-19 16:06:37 +02:00
run.sh Some improvement 2026-05-10 14:45:42 +02:00
session.go Fmt... 2026-05-12 09:00:58 +02:00
SINGLE_DOMAIN_GUIDE.md Align documentation with current deployment 2026-06-19 16:06:37 +02:00
smoketest.py Eliminate static analysis debt 2026-06-19 13:40:37 +02:00
tls.go Replace WebCal cleanup with DAV smoke coverage 2026-06-19 13:01:48 +02:00
version.go Replace WebCal cleanup with DAV smoke coverage 2026-06-19 13:01:48 +02:00
zangtumb.go Replace WebCal cleanup with DAV smoke coverage 2026-06-19 13:01:48 +02:00

ZangTumb

Futuristic SMTP/IMAP/CalDAV/CardDAV catch-all server for home usage. Inspired by Marinetti's RFC (also known as the Manifesto of Futurism).

It serves a single domain in catch-all mode: one mailbox for every recipient at that domain.

Every message sent to your domain will be accepted and stored in a single Maildir.
Spammers waste resources; you receive every message.

REQUIREMENTS

  1. Golang version 1.25 or newer
  2. git
  3. Docker, if you want to run the published container image

INSTALLATION

First, download the code into the folder you want to use with Golang:

git clone https://git.keinpfusch.net/loweel/zangtumb.git
go build -mod=vendor

./zangtumb

Set the environment variables (see below) and run ./zangtumb to start the daemon.

CONTAINER IMAGE

The CI pipeline publishes the latest container image to the Forgejo package registry:

git.keinpfusch.net/loweel/zangtumb:latest

Pull it with:

docker pull git.keinpfusch.net/loweel/zangtumb:latest

The image is built from this repository and pushed by Drone on master.

CONFIGURATION

ZangTumb is configured exclusively via environment variables.
It is designed to be easily containerized.

A reference pseudo-Dockerfile could be:

FROM debian:stable-slim  

## MAIN
ENV DOMAINNAME "yourdomain.tld"
ENV MAILUSER "admin"
ENV MAILPASSWORD "a-secure-password"

## SESSION
ENV MAILFOLDER "/zangmail"
ENV SMTP_LISTEN ":25"
ENV IMAP_LISTEN ":143"

## CERTIFICATES (Optional, auto-generated if missing)
ENV KEYFILE "/certs/mydomain.key"
ENV CERTFILE "/certs/mydomain.crt"

## DAV (Optional CalDAV/CardDAV)
ENV DAV_ENABLED "true"
ENV DAV_LISTEN ":8088"

RUN useradd -ms /bin/bash zangtumb 
RUN mkdir -p /zangmail
COPY . /opt/zangtumb/

RUN chown -R zangtumb:zangtumb /opt/zangtumb
RUN chown -R zangtumb:zangtumb /zangmail

EXPOSE 25 143 8088

USER zangtumb
WORKDIR /opt/zangtumb
ENTRYPOINT ["/opt/zangtumb/zangtumb"]

Everything is configured using environment variables, as follows:

ENV STRING Example Value Meaning
DOMAINNAME "mydomain.tld" The single domain for which mail will be received.
MAILUSER "admin" The single catch-all user. All mail for *@domain will end up here.
MAILPASSWORD "secret" Password used for IMAP and DAV access.
SMTP_LISTEN ":25" SMTP listening port. STARTTLS is mandatory.
IMAP_LISTEN ":143" IMAP listening port used to read mail.
MAILFOLDER "/zangmail" Persistent root storage path.
KEYFILE "/certs/key.pem" TLS private key path. Automatically generated if missing.
CERTFILE "/certs/cert.pem" TLS certificate path. Automatically generated if missing.
GRAYLISTING_ENABLED "true" Enable graylisting protection.
GRAYLISTING_DB_PATH "/tmp/gray.db" Path for the SQLite graylisting database. Must be on local storage, not NFS.
GRAYLISTING_DELAY "30s" Time the sender must wait before the mail is accepted.
GRAYLISTING_EXPIRY "36h" Lifetime of a graylisting record.
DAV_ENABLED "true" Enable the authenticated CalDAV/CardDAV HTTP endpoint.
DAV_LISTEN ":8088" HTTP listening address for CalDAV/CardDAV.
DEBUG "true" Enable verbose logging for SMTP and IMAP protocols.
MAX_MESSAGE_SIZE "10485760" Maximum message size in bytes.

Of course, if you place your certificates into /certs (as in the example), that folder must already exist.

ZangTumb will automatically create the Maildir and DAV storage structure on first startup.

That's it.

CALDAV/CARDDAV

ZangTumb can optionally expose authenticated CalDAV and CardDAV endpoints. This replaces the old idea of storing calendar data in an IMAP folder.

Enable DAV with:

DAV_ENABLED=true
DAV_LISTEN=:8088

Access uses the same credentials as IMAP:

username: MAILUSER
password: MAILPASSWORD

Discovery endpoints:

/.well-known/caldav
/.well-known/carddav

Calendar and contact data live inside the persistent MAILFOLDER, outside the IMAP Maildir:

MAILFOLDER/MAILUSER/dav/calendars/default/calendar.ics
MAILFOLDER/MAILUSER/dav/contacts/default/contacts.vcf

There is no special IMAP Calendar folder. IMAP remains mail-only; calendar and address book writes happen through DAV.

Security notes

The DAV endpoint uses HTTP Basic Authentication with MAILUSER and MAILPASSWORD on every route, including / and /health. If DAV_LISTEN is exposed beyond localhost or a trusted network, put it behind HTTPS.

DAV request bodies are size-limited and resource names are validated before use. Resource IDs are not used as filesystem paths.

FAQ

In v2.0, TLS is mandatory and certificates are automatically generated if missing.

  • Why is it now a Catch-All server?

  • Because managing multiple mailboxes is for people with too much free time. You own your domain.
    One domain, one user, maximum speed.

  • Why don't you use OpenSMTPD?

  • Because making this server took less effort than containerizing OpenSMTPD properly.

  • Why don't you use Postfix/Sendmail/Qmail/Courier?

  • I host four mailboxes in total. Why should I deploy all that complexity?
    Complexity != security.

  • !ZangTumb forces StartTLS. This is against the RFC!!!!

  • Unfortunately, English cannot properly translate the correct Italian answer, which would roughly be: "Esticazzi?"

  • This Golang code is not idiomatic. And there is no graphene, no quantum computing, no UI/UX, and no horizontally scalable Internet of Things powered by Artificial Intelligence and Big Data.

  • Please, bring me a Frappuccino.

  • Why you expect the sender server has a client certificate!!! You evil!!!!

  • Is perfectly reasonable. In real life, the equivalent would be that only real couriers and national post service can put paper in your mailbox. Reasonable and legit, IMHO_