Lightweight self-hosted mail service — one-click deploy, ready to use
SMTP Receiver • REST API • Web Viewer • IMAP Bridge
All emails shown in the screenshot are for testing purposes only and have no real-world significance.
ManyMail is a complete self-hosted mail solution with three core services:
| Service | Stack | Port | Description |
|---|---|---|---|
| mail-service | FastAPI + aiosmtpd | :25 :8080 |
SMTP receiver + DuckMail-compatible REST API |
| mail-viewer | Flask + bleach | :5000 |
Web mail viewer with search, reply & compose |
| imap-bridge | Node.js + imapflow | :3939 |
IMAP bridge for Gmail / Outlook / QQ etc. |
Internet Your Server
──────── ───────────
┌──────────────────────────────────────────────┐
│ │
Incoming ──────┤► mail-service ┌───────────────┐ │
Email │ (FastAPI+aiosmtpd) │ MongoDB 7 │ │
(SMTP :25) │ ┌──────────────┐ │ ┌─────────┐ │ │
│ │ SMTP Handler │────┤► │ accounts│ │ │
│ │ REST API │◄───┤ │ messages│ │ │
│ └──────┬───────┘ │ │ domains │ │ │
│ │ :8080 └───┴─────────┘─┘ │
│ │ │
│ ▼ │
Browser ────────┤► mail-viewer imap-bridge │
(HTTP :5000) │ (Flask) (Node.js) │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Inbox View │ │ Gmail │ │
│ │ Search │◄───┤ Outlook │ │
│ │ Reply / Send │ │ QQ / 163 │ │
│ │ HTML Sanitize│ │ Yahoo / GMX │ │
│ └──────────────┘ └──────────────┘ │
│ :3939 │
└──────────────────────────────────────────────┘
git clone https://github.com/margbug01/ManyMail.git
cd ManyMail
cp .env.example .envEdit .env with your actual values:
# Mail Service
JWT_SECRET=your-strong-jwt-secret
API_KEY=your-api-key
SMTP_HOSTNAME=mail.yourdomain.com
DOMAINS=yourdomain.com
# Mail Viewer
ACCESS_PASSWORD=your-viewer-password
SECRET_KEY=random-flask-secret
UNIFIED_PASSWORD=shared-mailbox-passworddocker compose up -d# Check all services
docker compose ps
# View logs
docker compose logs -f
# Health check
curl http://127.0.0.1:8080/healthAdd these DNS records for your domain:
; MX record — tells other mail servers where to deliver
yourdomain.com. IN MX 10 mail.yourdomain.com.
; A record — points to your server IP
mail.yourdomain.com. IN A <your-server-ip>
; SPF record — declares which IPs may send for your domain
yourdomain.com. IN TXT "v=spf1 ip4:<your-server-ip> -all"
; DKIM record — email signature verification (generate key pair first)
default._domainkey.yourdomain.com. IN TXT "v=DKIM1; k=rsa; p=<your-public-key>"
; DMARC record — policy for failed SPF/DKIM checks
_dmarc.yourdomain.com. IN TXT "v=DMARC1; p=quarantine; rua=mailto:dmarc@yourdomain.com"
STARTTLS: ManyMail supports STARTTLS. Mount your TLS certificate and key via
docker-compose.ymland setSMTP_TLS_CERT/SMTP_TLS_KEYin.env. See.env.examplefor details.
Base URL:
http://127.0.0.1:8080Auth:
Authorization: Bearer <token>(except/health,/token,/accounts)
POST /accounts # Create mailbox account
POST /token # Login, returns JWTGET /messages # List inbox (paginated: ?offset=0&limit=30)
GET /messages/{id} # Message detail
GET /messages/search?q= # Full-text search
PATCH /messages/{id} # Mark read / delete
GET /sent # Sent messagesGET /health # Health check (no auth required)
GET /domains # Active domain listExample: Create account & read inbox
# Create account
curl -X POST http://127.0.0.1:8080/accounts \
-H "Content-Type: application/json" \
-d '{"address": "user@yourdomain.com", "password": "secret123"}'
# Get token
TOKEN=$(curl -s -X POST http://127.0.0.1:8080/token \
-H "Content-Type: application/json" \
-d '{"address": "user@yourdomain.com", "password": "secret123"}' \
| jq -r '.token')
# List messages
curl http://127.0.0.1:8080/messages \
-H "Authorization: Bearer $TOKEN"ManyMail/
│
├── mail-service/ # SMTP + REST API
│ ├── app.py # FastAPI main app
│ ├── Dockerfile # Python 3.11-slim
│ └── requirements.txt # fastapi, aiosmtpd, pymongo, jwt, bcrypt
│
├── mail-viewer/ # Web Mail Viewer
│ ├── app.py # Flask main app
│ ├── Dockerfile # Python 3.11-slim + gunicorn
│ ├── requirements.txt # flask, bleach, tinycss2
│ ├── templates/
│ │ ├── index.html # Inbox UI
│ │ └── login.html # Login page
│ └── imap-mail-app/ # IMAP Bridge (Node.js)
│ ├── server.js # Express REST API
│ ├── client.js # ImapFlow wrapper
│ ├── config.js # Provider presets
│ └── package.json # imapflow, mailparser
│
├── docker-compose.yml # All 4 services orchestration
├── .env.example # Environment variable template
├── deploy.sh # Deployment script
├── test_smtp.py # SMTP tests
└── test_external_smtp.py # External SMTP tests
| Layer | Feature |
|---|---|
| Auth | JWT tokens (24h expiry) + API Key for admin endpoints |
| Password | bcrypt hashing |
| Rate Limit | Per-IP throttling on both API and SMTP |
| SMTP | IP blacklist / greylist, recipient limits, size limits |
| Email Render | HTML sanitization (bleach + CSSSanitizer), iframe sandbox |
| Network | Server-side image proxy (prevents IP leakage) |
| Storage | Auto-cleanup via MongoDB TTL index (default 3 days) |
| Web | Login-protected viewer, HttpOnly session cookies |
Python 3.11 FastAPI • Flask |
Node.js 20 Express • ImapFlow |
MongoDB 7 pymongo |
Docker Compose |
| Component | Dependencies |
|---|---|
| mail-service | fastapi uvicorn aiosmtpd pymongo PyJWT bcrypt |
| mail-viewer | flask gunicorn requests bleach tinycss2 |
| imap-bridge | express imapflow mailparser dotenv |