KISS Mail
A dead-simple email server. SMTP, IMAP, and POP3 in one container.
Quick Start (Docker)
# Run with Docker (recommended)
# Access web admin
That's it. The server starts and creates an admin account automatically.
One-Line Deploy (Any VPS)
|
Build from Source (Optional)
Usage
# Start the server
# Create a user
# List users
# Change a password
# Delete a user
# Show stats
Connect Your Email Client
| Setting | Value |
|---|---|
| Server | localhost |
| SMTP | 2525 (or 25 as root) |
| IMAP | 1143 (or 143 as root) |
| POP3 | 1100 (or 110 as root) |
| Username | your_username |
| Password | your_password |
| Security | None |
Environment Variables
| Variable | Default | Description |
|---|---|---|
| KISS_MAIL_DATA | ./mail_data | Data directory |
| KISS_MAIL_DOMAIN | (hostname) | Email domain |
| SMTP_PORT | 2525 | SMTP port |
| IMAP_PORT | 1143 | IMAP port |
| POP3_PORT | 1100 | POP3 port |
Docker (Recommended)
Docker is the preferred deployment method for KISS Mail.
Security
Our containers are built on Docker Hardened Images (Alpine-based):
- Zero known CVEs - Continuously scanned and patched
- Minimal attack surface - Alpine Linux base (~5MB)
- SBOM included - Full software bill of materials
- Non-root user - Runs as unprivileged user
- Cryptographically signed - Verifiable authenticity
Pull from Registry
# Pull the official hardened image
# Run container
# Create admin user
# View logs
Build Locally (Optional)
# Using Docker Hardened Images (requires Docker Hub login for dhi.io)
# Or using standard Alpine (no login required)
Docker Compose
# Start all services
# With ClamAV antivirus
# View logs
# Stop
Container Environment Variables
| Variable | Default | Description |
|---|---|---|
KISS_MAIL_DOMAIN |
localhost | Mail domain |
KISS_MAIL_DATA_DIR |
/data | Data directory |
KISS_MAIL_WEB_BIND |
127.0.0.1 | Web admin bind address |
KISS_MAIL_API_BIND |
127.0.0.1 | API bind address |
KISS_MAIL_API_KEY |
- | API key for remote access |
KISS_MAIL_ENCRYPTION |
true | Enable email encryption |
Kubernetes
Using Kustomize
# Deploy
# Check status
# Port forward for local access
Using Helm
# Install
# With ingress
# With external LoadBalancer
# Upgrade
# Uninstall
Cloud Deployment
All cloud deployments use Docker containers pulled from ghcr.io/pegasusheavy/kiss-mail:latest.
One-Click Install (Any VPS)
SSH into your server and run:
|
This installs Docker, pulls the container image, and starts KISS Mail automatically.
Works on Ubuntu, Debian, CentOS, Rocky Linux, Amazon Linux, Fedora, and more.
Cloud Provider Comparison
All providers deploy the same Docker container:
| Provider | Cost | Deploy Command |
|---|---|---|
| Hetzner | €3/mo | cd deploy/hetzner && terraform apply |
| Vultr | $5/mo | cd deploy/vultr && terraform apply |
| Linode | $5/mo | cd deploy/linode && terraform apply |
| Digital Ocean | $6/mo | cd deploy/digitalocean && terraform apply |
| AWS | $6-10/mo | cd deploy/aws && terraform apply |
| GCP | $5-10/mo | cd deploy/gcp && terraform apply |
| Azure | $10-15/mo | cd deploy/azure && terraform apply |
| Any Cloud | Variable | Use deploy/generic/cloud-init.yml |
Quick Deploy (Terraform)
# Choose your provider
# Configure
# Edit terraform.tfvars
# Deploy (pulls Docker container automatically)
Generic Cloud-Init
For any cloud provider (OVH, Scaleway, Oracle, UpCloud, etc.):
- Copy
deploy/generic/cloud-init.yml - Edit the config section with your domain
- Create VM with Ubuntu 22.04 and paste as user-data
- Wait 2-5 minutes (installs Docker and pulls container)
What Gets Deployed
All deployment methods create the same setup:
- Docker installed and configured
- KISS Mail container running with auto-restart
- Nginx reverse proxy for web admin
- Firewall rules for mail ports
- Data persisted in
/opt/kiss-mail/data
DNS Configuration
After deploying, configure these DNS records:
A mail.yourdomain.com YOUR_SERVER_IP
MX yourdomain.com 10 mail.yourdomain.com
TXT yourdomain.com "v=spf1 ip4:YOUR_SERVER_IP -all"
Enable HTTPS
SSH into your server and run:
Upgrade
|
Uninstall
|
# Keep data
|
Features
- ✅ SMTP server (send/receive)
- ✅ IMAP server (read emails)
- ✅ POP3 server (download emails)
- ✅ Zero-Knowledge Encryption (ProtonMail-style)
- ✅ Web Admin Dashboard (Tailwind CSS)
- ✅ Remote CLI & REST API
- ✅ SSO authentication (1Password, Google, Microsoft, Okta, Auth0)
- ✅ LDAP authentication (Active Directory, OpenLDAP)
- ✅ Groups / distribution lists
- ✅ AI spam detection (Bayesian classifier + rules)
- ✅ Anti-virus scanning (built-in + ClamAV)
- ✅ User management
- ✅ Zero configuration
- ✅ Single binary
Email Encryption
KISS Mail automatically encrypts emails at rest using ProtonMail-style zero-knowledge encryption.
How It Works
┌─────────────────────────────────────────────────────────────────┐
│ User Registration │
│ Password → Argon2 → Key Encryption Key (KEK) │
│ Generate X25519 keypair │
│ Private key encrypted with KEK → stored │
│ Public key → stored (unencrypted) │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ Email Encryption │
│ 1. Generate random symmetric key (per email) │
│ 2. Encrypt email body with ChaCha20-Poly1305 │
│ 3. Encrypt symmetric key with recipient's public key │
│ 4. Store: encrypted_key + nonce + ciphertext │
└─────────────────────────────────────────────────────────────────┘
Security Properties
| Property | Description |
|---|---|
| Zero-Knowledge | Server cannot read your emails |
| Per-User Keys | X25519 key pair for each user |
| Password-Protected | Private key encrypted with Argon2 |
| Per-Email Keys | Unique symmetric key per email |
| Modern Crypto | ChaCha20-Poly1305 authenticated encryption |
Configuration
| Variable | Default | Description |
|---|---|---|
KISS_MAIL_ENCRYPTION |
true | Enable/disable encryption |
Startup Banner
Security:
Anti-spam ✓ Rules + AI (1234 patterns learned)
Anti-virus ✓ Built-in
Encryption ✓ X25519-ChaCha20-Poly1305 (5 keys)
Key Management
- Keys are automatically generated when a user is created
- Private keys are encrypted with the user's password
- Password changes re-encrypt the private key
- Keys are stored in
keys.jsonin the data directory
AI Spam Detection
KISS Mail uses a hybrid spam detection system:
How It Works
-
Bayesian Classifier - Self-learning AI that:
- Learns from spam/ham patterns
- Extracts 50+ features (URLs, caps, urgency words, etc.)
- Persists learned data to disk
- Seeds with common spam patterns on first run
-
Rule-based Scoring - Traditional heuristics:
- Rate limiting
- Keyword detection
- Header analysis
- Suspicious URL patterns
-
Combined Decision - Weighted average of AI + rules (60%/40% default)
What You'll See
Security:
Anti-spam ✓ Rules + AI (847 patterns learned)
Anti-virus ✓ ClamAV 1.0.0
Self-Learning
The classifier improves over time as it sees more emails. Patterns are saved to mail_data/spam_classifier.json.
Groups / Distribution Lists
Create email groups to send messages to multiple users at once.
Quick Start
# Create a group (auto-generates email: developers@yourdomain.com)
# Or specify a custom email
# Add members
# List groups
# View group details
How It Works
When an email is sent to a group address (e.g., developers@yourdomain.com), it's automatically expanded and delivered to all group members.
Group Features
| Feature | Description |
|---|---|
| Distribution lists | Emails to group go to all members |
| Visibility levels | Public, Internal, Private, Hidden |
| Roles | Owner, Manager, Member |
| Settings | External senders, moderation, reply-to |
CLI Commands
Data Storage
Groups are persisted to mail_data/groups.json.
LDAP Integration
Authenticate users against LDAP directories (Active Directory, OpenLDAP, etc.).
Quick Setup
# Set LDAP server URL to enable
# Optional: Service account for user searches
# Start server
Test LDAP Connection
# Test connection
# Test authentication
# Search for user
Configuration Options
| Variable | Description | Default |
|---|---|---|
LDAP_URL |
LDAP server URL | (disabled) |
LDAP_BASE_DN |
Base DN for searches | dc=example,dc=com |
LDAP_BIND_DN |
Service account DN | (anonymous) |
LDAP_BIND_PASSWORD |
Service account password | (none) |
LDAP_USER_FILTER |
User search filter | (&(objectClass=inetOrgPerson)(uid={username})) |
LDAP_USER_DN_TEMPLATE |
User DN template | uid={username},ou=users,dc=example,dc=com |
LDAP_USE_TLS |
Use TLS (ldaps://) | false |
LDAP_FALLBACK_LOCAL |
Fall back to local auth | true |
Active Directory Example
How It Works
- User attempts to login via IMAP/POP3
- If LDAP is configured, authenticate against LDAP first
- On success, auto-create local mailbox if needed
- If LDAP fails and fallback is enabled, try local auth
- Local mailboxes store emails, LDAP provides authentication
Startup Banner
Directory:
LDAP ✓ ldap://ldap.example.com:389 (TLS)
SSO Integration
Authenticate users via Single Sign-On providers using OAuth2/OIDC.
Supported Providers
| Provider | Setup |
|---|---|
| 1Password | ONEPASSWORD_CLIENT_ID, ONEPASSWORD_CLIENT_SECRET |
GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET |
|
| Microsoft | MICROSOFT_CLIENT_ID, MICROSOFT_CLIENT_SECRET, MICROSOFT_TENANT_ID |
| Okta | OKTA_CLIENT_ID, OKTA_CLIENT_SECRET, OKTA_DOMAIN |
| Auth0 | AUTH0_CLIENT_ID, AUTH0_CLIENT_SECRET, AUTH0_DOMAIN |
| Generic OIDC | SSO_CLIENT_ID, SSO_CLIENT_SECRET, SSO_AUTH_URL, SSO_TOKEN_URL |
Quick Setup (Google Example)
App Passwords
Since email clients (Thunderbird, Outlook, etc.) don't support OAuth2, generate app passwords:
# Generate app password for a user
# Output: abcd-efgh-jkmn-pqrs-tuvw-xyz1
# List app passwords
# Revoke app password
Use the generated password in your mail client instead of your SSO password.
CLI Commands
Startup Banner
Identity:
LDAP ✓ ldap://ldap.example.com:389
SSO ✓ Google + app passwords
Web Admin Dashboard
A simple, beautiful web interface for managing your mail server.
Access
http://localhost:8080/admin
Login with any admin user credentials.
Features
- Dashboard - Server overview, stats, quick actions
- Users - Create, edit, delete users; manage roles and status
- Groups - Create distribution lists, manage members
Screenshots
The interface uses Tailwind CSS for a clean, modern design:
- Clean navigation with active state highlighting
- Responsive tables for users and groups
- Form validation and flash messages
- Session-based authentication
Configuration
| Variable | Default | Description |
|---|---|---|
KISS_MAIL_WEB_ENABLED |
true | Enable web admin |
KISS_MAIL_WEB_PORT |
8080 | Web admin port |
KISS_MAIL_WEB_BIND |
127.0.0.1 | Bind address |
Startup Banner
Servers:
SMTP → localhost:2525
IMAP → localhost:1143
POP3 → localhost:1100
Web → http://localhost:8080/admin
Remote Administration
Manage the server remotely via CLI or REST API.
Enable Remote API
Set an API key to enable remote access:
The API server starts on port 8025 by default:
Servers:
SMTP → localhost:2525
IMAP → localhost:1143
POP3 → localhost:1100
API → localhost:8025
Remote CLI Usage
# Using flags
# Short flags
# Using environment variables
Supported Remote Commands
| Command | Description |
|---|---|
status |
Show server status |
list |
List all users |
add <user> <pass> |
Create user |
del <user> |
Delete user |
info <user> |
Show user details |
groups |
List all groups |
group-add <name> |
Create group |
group-del <name> |
Delete group |
group-add-member <grp> <usr> |
Add user to group |
group-rm-member <grp> <usr> |
Remove user from group |
ldap-test |
Test LDAP connection |
REST API Endpoints
The admin API also provides REST endpoints for programmatic access:
# Authentication
# Status
# Users
# Groups
# App Passwords
# LDAP
# SSO
Example API Calls
# Get status
# Create user
# List groups
Configuration
| Variable | Default | Description |
|---|---|---|
KISS_MAIL_API_KEY |
- | API key (enables API if set) |
KISS_MAIL_API_PORT |
8025 | API server port |
KISS_MAIL_API_BIND |
127.0.0.1 | Bind address |
KISS_MAIL_API_ENABLED |
false | Enable API without key |
ClamAV Integration
KISS Mail automatically detects and uses ClamAV if available. No configuration needed!
Install ClamAV (optional)
# Debian/Ubuntu
# macOS
# The server will auto-detect ClamAV at 127.0.0.1:3310
Configure ClamAV
| Variable | Default | Description |
|---|---|---|
| CLAMAV_ADDRESS | 127.0.0.1:3310 | ClamAV daemon address |
| CLAMAV_ENABLED | true | Enable ClamAV scanning |
# Use custom ClamAV address
CLAMAV_ADDRESS=192.168.1.100:3310
# Disable ClamAV (use built-in only)
CLAMAV_ENABLED=false
When ClamAV is available, you'll see:
Security:
Anti-spam ✓ Enabled
Anti-virus ✓ ClamAV 1.0.0/26789/...
When ClamAV is not available, the built-in scanner is used:
Security:
Anti-spam ✓ Enabled
Anti-virus ✓ Built-in (ClamAV not found)
License
MIT