OCaml 98.7%
Standard ML 0.3%
Dune 0.2%
Other 0.8%
19 1 0

Clone this repository

https://tangled.org/anil.recoil.org/ocaml-imap
git@git.recoil.org:anil.recoil.org/ocaml-imap

For self-hosted knots, clone URLs may differ based on your setup.

README.md

imapd#

An IMAP4rev2 server implemented in OCaml.

Implements RFC 9051 (IMAP4rev2) with support for implicit TLS per RFC 8314.

Features#

  • IMAP4rev2 (RFC 9051) with IMAP4rev1 compatibility
  • Fork-per-connection privilege separation (like UW-IMAP)
  • Implicit TLS on port 993 (RFC 8314)
  • STARTTLS upgrade for cleartext connections
  • PAM authentication using system accounts
  • Maildir storage with traditional ~/Maildir layout
  • In-memory storage for development and testing

Supported Extensions#

Extension RFC Description
IDLE RFC 2177 Real-time notifications
NAMESPACE RFC 2342 Mailbox namespaces
ID RFC 2971 Server identification
UIDPLUS RFC 4315 UID responses for COPY/APPEND
ENABLE RFC 5161 Capability negotiation
MOVE RFC 6851 Atomic move operation
LITERAL+ RFC 7888 Non-synchronizing literals

Installation#

Prerequisites#

  • OCaml 5.0+
  • opam
  • PAM development headers (libpam0g-dev on Debian/Ubuntu)

Building#

opam install . --deps-only
dune build

Running Tests#

dune test

Usage#

Development Server#

# In-memory storage on port 10143
imapd -s memory -p 10143
# Fork-per-connection with implicit TLS
# Uses ~/Maildir for each user
sudo imapd --fork -s maildir --tls \
  --cert /etc/ssl/certs/mail.crt \
  --key /etc/ssl/private/mail.key \
  -p 993

Single-Process with STARTTLS#

# Cleartext with STARTTLS upgrade
imapd -s maildir --maildir-path /var/mail \
  --cert server.crt --key server.key \
  -p 143

Operating Modes#

Single-Process (default)#

All connections handled in one process. Efficient but all sessions share the same privileges. Suitable for development or trusted environments.

Fork-per-Connection (--fork)#

Each connection forks a child process. After successful authentication, the child drops privileges to the authenticated user via setuid. This provides strong isolation between users.

  • Requires running as root
  • Only works with Maildir storage
  • STARTTLS not supported (use implicit TLS)

Storage Backends#

Memory#

In-memory storage for development and testing. Data is not persisted.

imapd -s memory

Maildir#

Production storage using the Maildir format.

With shared base path:

imapd -s maildir --maildir-path /var/mail
# Mail stored at /var/mail/<username>/

With home directories (fork mode default):

sudo imapd --fork -s maildir
# Mail stored at ~<username>/Maildir/

Command-Line Options#

Option Description
-p, --port Port to listen on (default: 143)
-h, --host Host address to bind to (default: 127.0.0.1)
-s, --storage Storage backend: memory or maildir
--maildir-path Base path for Maildir storage
--tls Enable implicit TLS (requires --cert and --key)
--cert TLS certificate file (PEM format)
--key TLS private key file (PEM format)
--fork Fork per connection with privilege separation

Architecture#

imapd/
├── lib/
│   ├── imap_types/     # Core IMAP types (RFC 9051)
│   ├── imap_parser/    # Menhir parser + Faraday serializer
│   ├── imap_auth/      # PAM authentication
│   ├── imap_storage/   # Memory and Maildir backends
│   └── imap_server/    # Connection handler and state machine
├── bin/
│   └── main.ml         # CLI entry point
└── test/               # Alcotest test suite

Connection State Machine#

┌─────────────────────┐
│ Not Authenticated   │ ← Initial state
├─────────────────────┤
│ CAPABILITY, NOOP    │
│ STARTTLS, LOGIN     │
│ LOGOUT              │
└─────────┬───────────┘
          │ LOGIN success
          ▼
┌─────────────────────┐
│ Authenticated       │
├─────────────────────┤
│ SELECT, EXAMINE     │
│ CREATE, DELETE      │
│ LIST, STATUS        │
│ APPEND, IDLE        │
└─────────┬───────────┘
          │ SELECT success
          ▼
┌─────────────────────┐
│ Selected            │
├─────────────────────┤
│ FETCH, STORE        │
│ SEARCH, COPY, MOVE  │
│ EXPUNGE, CLOSE      │
└─────────────────────┘

Security#

  • Privilege separation: Fork mode drops to authenticated user via setuid
  • Path traversal protection: Username and mailbox names are validated
  • DoS mitigation: Maximum line length enforced (64KB)
  • TLS: Implicit TLS recommended for production

Testing with a Client#

# Start development server
imapd -s memory -p 10143 &

# Connect with OpenSSL (cleartext for testing)
telnet localhost 10143

# Or with TLS
openssl s_client -connect localhost:993

Example session:

* OK [CAPABILITY IMAP4rev2 ...] IMAP4rev2 Service Ready
a001 LOGIN username password
a001 OK [CAPABILITY ...] LOGIN completed
a002 SELECT INBOX
* FLAGS (\Seen \Answered \Flagged \Deleted \Draft)
* 0 EXISTS
* OK [UIDVALIDITY 1234567890] UIDs valid
a002 OK [READ-WRITE] SELECT completed
a003 LOGOUT
* BYE IMAP4rev2 Server logging out
a003 OK LOGOUT completed

License#

ISC License. See LICENSE.md for details.

Contributing#

Report bugs at https://tangled.org/@anil.recoil.org/ocaml-imap/issues