Lightweight IMAP4rev1 encrypted server purpose-built for Apple Notes to edit and sync notes across macOS and iOS devices.
- Apple Notes compatible — Full IMAP4rev1 support for the command subset Apple Notes uses
- Auto-provisioned accounts — First login creates the account automatically
- End-to-end encrypted storage — Per-user SQLCipher databases + AES-256-GCM credential files
- TLS-only — Direct TLS on port 993, minimum TLS 1.2
- Zero dependencies beyond Ruby — No external services, just a single process + SQLite
# Development (generates a self-signed TLS cert automatically)
bundle install
DATA_DIR=data ruby server.rb
# Docker
docker build -t notes-imap-server .
docker run -p 993:9993 -v notes_data:/data notes-imap-server
# Deploy to Fly.io
fly deploy| Environment Variable | Default | Description |
|---|---|---|
IMAP_PORT |
9993 |
IMAP listener port |
DATA_DIR |
/data |
Root directory for user data and TLS certs |
IMAP_DOMAIN |
— | Domain name for TLS certificate SAN |
LOG_LEVEL |
INFO |
Log verbosity: DEBUG, INFO, WARN, ERROR |
HEALTH_PORT |
8080 |
HTTP health check port |
FLY_TLS_TERMINATED |
false |
Set true when Fly Proxy terminates TLS (handlers = ["tls"]) and forwards plaintext to the app |
When deploying with Fly service ports configured with handlers = ["tls"], Fly terminates TLS at the edge and forwards plaintext TCP to your machine.
Set FLY_TLS_TERMINATED=true (already set in fly.toml) so IMAP and SMTP listeners run in backend plaintext mode. If this is not set, the app expects direct TLS and Fly connections can fail during handshake, causing account verification errors in Apple Notes.
See docs/architecture.md for detailed architecture documentation with diagrams.
lib/imap/
├── server.rb # TLS listener + thread pool
├── connection.rb # Per-client state machine
├── command_router.rb # Declarative command dispatch
├── parser.rb # IMAP protocol parser
├── response.rb # Response formatters
└── commands/ # One file per command group
├── base.rb # Shared utilities
├── any_state.rb # CAPABILITY, NOOP, LOGOUT, ID, ENABLE
├── login.rb # LOGIN
├── mailbox.rb # SELECT, LIST, CREATE, DELETE, ...
├── message.rb # FETCH, STORE, SEARCH
├── append.rb # APPEND
└── expunge.rb # EXPUNGE, CLOSE, CHECK, COPY
# All tests
bundle exec rspec
# Unit tests only
bundle exec rspec spec/lib/
# Integration tests only (starts real server instances)
bundle exec rspec spec/integration/
# Specific test file
bundle exec rspec spec/integration/notes_flow_spec.rbInspect notes stored in the database for any user — useful for debugging.
bin/inspect_notes -e user@example.com -p password # Pretty format
bin/inspect_notes -e user@example.com -p password --raw # Raw HTML
bin/inspect_notes -e user@example.com -p password -m Notes # Specific mailboxSee docs/inspect_notes.md for full documentation.