Skip to content

thelolna15/mailol

Repository files navigation

Next.js React Redis Haraka Docker

πŸ“¬ MaiLoL β€” Self-Hosted Disposable Email Service

MaiLoL is a free, open-source, self-hosted temporary/disposable email service. It allows anyone to create throwaway email addresses instantly β€” no registration required β€” to protect their real inbox from spam, phishing, and unwanted sign-ups.

Inspiration: This project is heavily inspired by mail.tm, an excellent disposable email service. MaiLoL aims to provide a similar experience as a fully self-hosted, open-source alternative that you can deploy on your own infrastructure with your own custom domain.


✨ Features

Core

  • πŸ”’ Instant Account Creation β€” Create a temporary email with a username + password in seconds
  • πŸ“₯ Real-Time Inbox β€” Receive emails in real-time via Server-Sent Events (SSE)
  • πŸ“Ž Attachment Support β€” View and download email attachments (PDF, images, etc.)
  • πŸ” JWT Authentication β€” Stateless, secure token-based authentication
  • πŸ—‘οΈ Message Management β€” Read, view, and delete individual messages
  • πŸ‘₯ Multi-Account Switching β€” Manage multiple email accounts from a single browser session
  • πŸ”” Unread Indicators β€” Visual dot badges for accounts/messages with unread emails

User Experience

  • πŸŒ— Dark/Light Theme β€” Toggle between themes with persistence across sessions
  • πŸ“‹ One-Click Copy β€” Click to copy your email address to clipboard
  • 🎨 Modern UI β€” Glassmorphism, smooth animations (Framer Motion), responsive design
  • πŸ”‘ Password Reveal β€” Blur-masked password display with click-to-reveal
  • πŸ“Š Storage Quota β€” Visual progress bar showing inbox usage

Infrastructure

  • 🐳 Fully Dockerized β€” One-command deployment with docker compose up
  • πŸ“¨ Built-in MTA β€” Haraka SMTP server for receiving inbound emails
  • ⚑ Redis-Powered β€” All data stored in Redis with automatic TTL expiration
  • πŸš€ Standalone Build β€” Optimized Next.js standalone output for minimal Docker images

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        Internet                             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
           β”‚ SMTP (Port 25)                   β”‚ HTTPS (Port 443)
           β–Ό                                  β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”           β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   mailol-mta        β”‚           β”‚   Reverse Proxy         β”‚
β”‚   (Haraka MTA)      β”‚           β”‚   (Nginx / Caddy)       β”‚
β”‚                     β”‚           β”‚                         β”‚
β”‚   Receives inbound  β”‚           β”‚   TLS termination       β”‚
β”‚   emails via SMTP   β”‚           β”‚   β†’ localhost:3000      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜           β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
           β”‚                                  β”‚
           β”‚  Parse & Store                   β”‚  HTTP
           β–Ό                                  β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”           β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   mailol-redis      │◄──────────│   mailol-app            β”‚
β”‚   (Redis 7)         β”‚           β”‚   (Next.js 16)          β”‚
β”‚                     β”‚           β”‚                         β”‚
β”‚   β€’ User accounts   β”‚  Pub/Sub  β”‚   β€’ REST API            β”‚
β”‚   β€’ Messages (JSON) │──────────►│   β€’ SSE real-time       β”‚
β”‚   β€’ Attachments     β”‚           β”‚   β€’ React frontend      β”‚
β”‚   β€’ Inbox indices   β”‚           β”‚   β€’ JWT auth            β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜           β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ“ Project Structure

mailol/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ app/
β”‚   β”‚   β”œβ”€β”€ api/
β”‚   β”‚   β”‚   β”œβ”€β”€ accounts/       # POST /api/accounts β€” Create account
β”‚   β”‚   β”‚   β”‚   └── [id]/       # DELETE /api/accounts/:id β€” Delete account
β”‚   β”‚   β”‚   β”œβ”€β”€ token/          # POST /api/token β€” Login (get JWT)
β”‚   β”‚   β”‚   β”œβ”€β”€ me/             # GET /api/me β€” Current user info
β”‚   β”‚   β”‚   β”œβ”€β”€ messages/       # GET /api/messages β€” List inbox
β”‚   β”‚   β”‚   β”‚   └── [id]/       # GET/DELETE /api/messages/:id
β”‚   β”‚   β”‚   β”‚       └── attachments/
β”‚   β”‚   β”‚   β”‚           └── [index]/ # GET β€” Download attachment
β”‚   β”‚   β”‚   β”œβ”€β”€ domains/        # GET /api/domains β€” Available domains
β”‚   β”‚   β”‚   β”œβ”€β”€ events/         # GET /api/events β€” SSE stream
β”‚   β”‚   β”‚   └── dev/
β”‚   β”‚   β”‚       └── mock/       # GET /api/dev/mock β€” Dev: inject test email
β”‚   β”‚   β”œβ”€β”€ globals.css         # Tailwind + custom design tokens
β”‚   β”‚   β”œβ”€β”€ layout.tsx          # Root layout
β”‚   β”‚   └── page.tsx            # Main page (landing / inbox / viewer)
β”‚   β”‚
β”‚   β”œβ”€β”€ components/
β”‚   β”‚   β”œβ”€β”€ auth/               # CreateAccountModal, LoginModal, DeleteAccountModal
β”‚   β”‚   β”œβ”€β”€ layout/             # AppLayout, Sidebar, TopBar
β”‚   β”‚   β”œβ”€β”€ mail/               # EmailList, EmailViewer
β”‚   β”‚   └── ui/                 # Modal (reusable)
β”‚   β”‚
β”‚   β”œβ”€β”€ lib/
β”‚   β”‚   β”œβ”€β”€ auth.ts             # JWT verification middleware
β”‚   β”‚   β”œβ”€β”€ jwt.ts              # JWT sign/verify helpers
β”‚   β”‚   └── redis.ts            # Redis client (ioredis) singleton
β”‚   β”‚
β”‚   └── store/
β”‚       └── useMailStore.ts     # Zustand global state management
β”‚
β”œβ”€β”€ haraka_plugin/
β”‚   └── mailol_processor.js     # Haraka plugin: parse & store inbound email
β”‚
β”œβ”€β”€ Dockerfile                  # Multi-stage Next.js production build
β”œβ”€β”€ Dockerfile.haraka           # Haraka MTA container
β”œβ”€β”€ docker-compose.yml          # Full stack orchestration
β”œβ”€β”€ .env.example                # Environment variable template
└── .env.production             # Production environment template

πŸš€ Getting Started

Prerequisites

  • Node.js 20+ (for local development)
  • Docker & Docker Compose (for deployment)
  • A domain with MX record pointing to your server (for receiving real emails)

Local Development

# 1. Clone the repository
git clone https://github.com/thelolna15/mailol.git
cd mailol/project

# 2. Install dependencies
npm install

# 3. Set up environment
cp .env.example .env
# Edit .env β€” set your REDIS_URL to a running Redis instance

# 4. Start development server
npm run dev

Open http://localhost:3000 to see the app.

Testing Email Reception (Dev Mode)

Since you likely don't have a local SMTP server during development, use the built-in mock endpoint:

# Inject a test email into any account
curl "http://localhost:3000/api/dev/mock?address=yourname@thelol.me"

This will create a fake email with HTML content and a PDF attachment in the specified inbox.


🐳 Docker Deployment (Production)

1. Prepare Environment

cp .env.production .env
nano .env

⚠️ IMPORTANT: Generate a secure JWT_SECRET before deploying:

openssl rand -hex 32

2. Build & Run

docker compose up -d --build

This spins up three containers:

Container Port Description
mailol-app 3000 Next.js web app & API
mailol-redis β€” Redis data store (internal only)
mailol-mta 25 Haraka SMTP server

3. DNS Configuration

For your domain (e.g., thelol.me), configure these DNS records:

Type Name Value Priority
A @ YOUR_SERVER_IP β€”
A mail YOUR_SERVER_IP β€”
MX @ mail.thelol.me 10

4. Reverse Proxy (HTTPS)

Place Nginx or Caddy in front of port 3000 for TLS termination:

Caddy (recommended β€” automatic HTTPS)
thelol.me {
    reverse_proxy localhost:3000
}
Nginx
server {
    listen 443 ssl http2;
    server_name thelol.me;

    ssl_certificate /etc/letsencrypt/live/thelol.me/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/thelol.me/privkey.pem;

    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_cache_bypass $http_upgrade;
    }
}

5. Verify

# Check all containers are running
docker compose ps

# View logs
docker compose logs -f app
docker compose logs -f mta

# Test SMTP connectivity
telnet YOUR_SERVER_IP 25

πŸ”Œ API Reference

All endpoints (except /api/accounts POST and /api/token POST) require a Bearer token in the Authorization header.

Authentication

Method Endpoint Description Auth
POST /api/accounts Create a new account ❌
POST /api/token Login & get JWT token ❌

Create Account

curl -X POST http://localhost:3000/api/accounts \
  -H "Content-Type: application/json" \
  -d '{"address": "myname@thelol.me", "password": "mypassword"}'

Login

curl -X POST http://localhost:3000/api/token \
  -H "Content-Type: application/json" \
  -d '{"address": "myname@thelol.me", "password": "mypassword"}'

Resources

Method Endpoint Description Auth
GET /api/me Get current account info βœ…
GET /api/messages List inbox messages βœ…
GET /api/messages/:id Get single message with HTML body βœ…
DELETE /api/messages/:id Delete a message βœ…
GET /api/messages/:id/attachments/:index Download attachment βœ…
DELETE /api/accounts/:id Delete account & all data βœ…
GET /api/domains List available domains ❌
GET /api/events?authorization=TOKEN SSE real-time stream βœ… (query)

βš™οΈ Environment Variables

Variable Required Default Description
DOMAIN βœ… thelol.me Email domain for account creation
NEXT_PUBLIC_DOMAIN βœ… thelol.me Domain shown in the frontend UI
REDIS_URL βœ… redis://localhost:6379 Redis connection string
JWT_SECRET βœ… β€” Secret key for signing JWT tokens
JWT_EXPIRY ❌ 3600 Token expiration time in seconds
DEFAULT_QUOTA ❌ 41943040 Max inbox storage per account (bytes)

πŸ›‘οΈ Security Considerations

  • Always change JWT_SECRET in production β€” use openssl rand -hex 32
  • Never expose Redis to the public internet β€” it runs on an internal Docker network
  • Use HTTPS in production β€” configure a reverse proxy with TLS
  • Rate limiting is not yet implemented β€” consider adding Nginx rate limits
  • Email content is sanitized with DOMPurify before rendering
  • Passwords are hashed with bcrypt before storage

πŸ—ΊοΈ Roadmap

  • Rate limiting middleware
  • DKIM / SPF / DMARC configuration guide
  • Outbound email support (compose & send)
  • Custom domain support (multi-domain)
  • Admin dashboard
  • Webhook notifications
  • S3-compatible attachment storage
  • Account expiration policies

πŸ™ Credits & Acknowledgments

  • mail.tm β€” The primary inspiration for this project. MaiLoL's API design, account model, and user experience are heavily influenced by mail.tm's elegant approach to disposable email.
  • Haraka β€” High-performance Node.js SMTP server used as the Mail Transfer Agent.
  • Next.js β€” React framework powering both the frontend and API.
  • Redis β€” In-memory data store for lightning-fast message retrieval.
  • Zustand β€” Lightweight state management for React.
  • Framer Motion β€” Animation library for smooth UI transitions.
  • Tailwind CSS β€” Utility-first CSS framework for the design system.

πŸ“„ License

This project is open-source and available under the MIT License.


Built with ❀️ as an open-source alternative to commercial disposable email services.

About

No description, website, or topics provided.

Resources

License

Stars

1 star

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors