Skip to content

anondotli/mx

Repository files navigation

anon.li Email Server

A production-ready, secure, and privacy-focused Haraka email server for handling anonymous email forwarding.

Features

  • Anonymous Forwarding: Accepts emails for @anon.li aliases and custom domains, forwarding them to real recipients
  • Reply System: Handles replies via @reply.anon.li tokenized addresses to hide user identities
  • PGP Encryption: Automatically encrypts forwarded emails if the recipient has uploaded a public key
  • Privacy Protection: Removes tracking pixels, cleans HTML, and sanitizes dangerous content
  • SRS Support: Implements Sender Rewriting Scheme to maintain SPF compliance when forwarding
  • DKIM Signing: Signs all outbound mail to ensure deliverability
  • Rate Limiting: Redis-backed rate limiting to prevent abuse
  • Custom Domains: Supports user-verified custom domains with per-domain DKIM keys

Architecture

┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│  External       │     │    Haraka       │     │   Next.js API   │
│  Sender         │────▶│    MTA          │────▶│   (Prisma)      │
└─────────────────┘     └─────────────────┘     └─────────────────┘
                               │                        │
                               ▼                        ▼
                        ┌─────────────────┐     ┌─────────────────┐
                        │    Redis        │     │   PostgreSQL    │
                        │  (Rate Limit)   │     │   (Aliases)     │
                        └─────────────────┘     └─────────────────┘

Installation

Prerequisites

  • Docker and Docker Compose
  • Node.js 20+ (for local development)
  • Redis
  • Access to the Next.js frontend API

Quick Start

  1. Clone and configure:

    cp .env.example .env
    # Edit .env with your MAIL_API_SECRET
  2. Generate DKIM keys:

    ./scripts/generate-dkim.sh anon.li
    ./scripts/generate-dkim.sh reply.anon.li

    The generated keys stay on the host under config/dkim/ and are mounted into the container at runtime. On startup, the entrypoint stages them into a private runtime directory owned by the haraka user, so host-side 0600 permissions remain safe and ARC/DKIM can still read them. They are intentionally not baked into the Docker image.

  3. Add DNS records (output from script):

    default._domainkey.anon.li. IN TXT "v=DKIM1; k=rsa; p=..."
    default._domainkey.reply.anon.li. IN TXT "v=DKIM1; k=rsa; p=..."
    
  4. Place TLS certificates:

    # Place your Let's Encrypt or other TLS certs
    cat privkey.pem cert.pem chain.pem > config/tls/anon.li.pem
  5. Start the server:

    docker compose up -d --build

    The container now validates MAIL_API_SECRET and the TLS bundle at startup, and warns when local DKIM keys are missing so deliverability issues are visible immediately.

Configuration

Environment Variables

Variable Description Required
MAIL_API_SECRET Shared secret for API authentication Yes
FRONTEND_URL URL of Next.js API (default: http://app:3000) No
UPSTASH_REDIS_REST_URL Upstash Redis REST endpoint (rate limiting) No
UPSTASH_REDIS_REST_TOKEN Upstash Redis auth token No
DKIM_REQUIRED_DOMAINS Space-separated local DKIM domains to warn about at startup No
LOCAL_DKIM_DIR Internal runtime directory for staged DKIM keys No

Plugins

Plugin Purpose
tls STARTTLS enforcement
limit-upstash IP-based rate limiting (Redis + in-memory fallback)
mailauth Inbound SPF / DKIM / DMARC validation
rcpt_to.bounce Validates SRS bounce return-paths
rcpt_to.anonli Validates aliases + per-alias rate limiting
rcpt_to.reply Handles reply token addresses
data.loop_detect Rejects mail loops
data.tracking_remove Strips tracking pixels / UTM params
data.spam_check Spam scoring
arc.sign ARC sealing for forwarded mail
dkim.custom Per-domain DKIM signing (local keys or API-fetched)
queue.forward Main forwarding (SRS, PGP, reply rewriting)

DNS Configuration

For anon.li

; MX Record
anon.li.                IN MX   10 mx.anon.li.

; SPF
anon.li.                IN TXT  "v=spf1 mx a:mx.anon.li -all"

; DKIM (generated by script)
default._domainkey.anon.li. IN TXT "v=DKIM1; k=rsa; p=..."

; DMARC
_dmarc.anon.li.         IN TXT  "v=DMARC1; p=quarantine; rua=mailto:dmarc@anon.li"

For Custom Domains

Users must add:

  1. MX record pointing to mx.anon.li
  2. SPF record including include:_spf.anon.li
  3. DKIM record (provided in dashboard)
  4. Verification TXT record

Security Features

  • TLS 1.2+ required for all connections
  • Timing-safe API secret comparison
  • Input validation on all email addresses
  • Rate limiting per IP and globally
  • DKIM/SPF/DMARC for email authentication
  • PGP encryption for enhanced privacy
  • Tracking removal for privacy protection

Monitoring

Logs are output in JSON format for easy parsing:

docker compose logs -f haraka

Production notes:

  • DKIM private keys and TLS certificates are mounted at runtime; keep them out of the image build context.
  • DKIM host mounts are staged into LOCAL_DKIM_DIR on startup so the unprivileged haraka process can read them without loosening host file permissions.
  • ARC signing reuses the same key lookup path as DKIM signing: staged local key first, API fallback second.
  • Docker Compose requests an IPv6-enabled user-defined bridge network for Haraka.
  • Outbound delivery uses Haraka's default dual-stack behavior, which prefers IPv6 when the container has working IPv6 egress.
  • Docker daemon IPv6 settings in /etc/docker/daemon.json are optional for this setup. They are only needed if you want to customize Docker's IPv6 address pools or enable IPv6 on the default bridge network.

Health check endpoint:

nc -z localhost 25 && echo "OK"

Development

# Install dependencies
npm install

# Run locally (requires Haraka global install)
npm install -g Haraka
npm start

# Run tests
npm test

License

GNU Affero General Public License v3.0 (AGPL-3.0-only).

Because anon.li-mx is network-facing server software, the AGPL requires that anyone running a modified version on a publicly accessible server make the corresponding source code available to its users.

About

The source code for our aliasing mail server, powered by Haraka.

Topics

Resources

License

Stars

Watchers

Forks

Contributors