An asynchronous email fetching service built with Rust. Courrier connects to IMAP servers, downloads emails to .eml files, and provides a web dashboard for monitoring and managing your emails. It may be used for automated mail backups on a server.
- Multi-Account Support: Fetch emails from multiple IMAP accounts across different servers
- Automatic Mailbox Discovery: Automatically discovers and fetches from all mailboxes
- Incremental Fetching: Tracks fetched emails to avoid duplicates
- Web Dashboard: Provides a dashboard for monitoring fetch status and statistics
- Periodic Fetching: Optional automatic fetching at configurable intervals
- Docker Support: Ready-to-use Docker container with volume mounts
- SQLite Database: Lightweight database for tracking fetched emails
- Async Architecture: Built with Tokio for high-performance concurrent operations
cargo install --path .Or clone and build:
git clone <repository-url>
cd mailster
cargo build --releaseYou can either build the image locally or use the pre-built image from GitHub Container Registry.
Option 1: Use Pre-built Image (Recommended)
# Pull the latest image from GitHub Container Registry
docker pull ghcr.io/pascalbehmenburg/courrier:latestOption 2: Build Locally
docker build -t courrier .Create a Config.toml file in the working directory (or mount it at /config/Config.toml in Docker):
# Storage configuration
email_storage_path = "emails" # Path where emails will be stored
# Fetch configuration
fetch_on_startup = true # Automatically fetch emails when server starts
fetch_interval_seconds = 3600 # Optional: Automatically fetch every N seconds (e.g., 3600 = 1 hour)
# Example apple IMAP server configuration
[[servers]]
host = "imap.mail.me.com"
port = 993 # Optional, defaults to 993 if not specified
accounts = [
{ email = "your@mail.com", username = "mailer", password = "your-app-specific-password" },
{ email = "other@mail.com", username = "mailer", password = "your-app-specific-password" }
]
# Example gmail IMAP server configuration
[[servers]]
host = "imap.gmail.com"
port = 993
accounts = [
{ email = "your-email@gmail.com", username = "your-email@gmail.com", password = "your-app-specific-password" }
]See Config.toml.example for a complete example.
Run a one-time fetch operation:
courrier fetchStart the web dashboard (default):
courrier server
# or
courrier server 8080 # Custom portThe dashboard will be available at http://localhost:3000 (or your specified port).
COURRIER_DB_PATH: Path to the SQLite database file (default:courrier.db)
The easiest way to use Courrier is with the pre-built Docker image from GitHub Container Registry:
# Pull the latest image
docker pull ghcr.io/pascalbehmenburg/courrier:latest
# Run the container
docker run -d \
--name courrier \
-p 3000:3000 \
-v /path/to/your/config:/config \
-v /path/to/your/data:/data \
ghcr.io/pascalbehmenburg/courrier:latestNote: If the repository is private, you'll need to authenticate first:
echo $GITHUB_TOKEN | docker login ghcr.io -u USERNAME --password-stdinAlternatively, you can build the image from source:
docker build -t courrier .docker run -d \
--name courrier \
-p 3000:3000 \
-v /path/to/your/config:/config \
-v /path/to/your/data:/data \
courrierVolume Mounts:
/config: Mount yourConfig.tomlfile here/data: Emails and database (courrier.db) will be stored here
Example:
# Create directories
mkdir -p ~/courrier/config ~/courrier/data
# Copy your Config.toml
cp Config.toml ~/courrier/config/
# Run container
docker run -d \
--name courrier \
-p 3000:3000 \
-v ~/courrier/config:/config \
-v ~/courrier/data:/data \
courrierImportant: Make sure your Config.toml has email_storage_path = "/data" (or a subdirectory like /data/emails) when running in Docker.
The easiest way to run Courrier is using Docker Compose with the pre-built image. See docker-compose.example.yml for a complete example.
Using Pre-built Image (Recommended):
Create a docker-compose.yml based on docker-compose.example.yml:
version: '3.8'
services:
courrier:
image: ghcr.io/pascalbehmenburg/courrier:latest
container_name: courrier
ports:
- "3000:3000"
volumes:
- ./config:/config
- ./data:/data
restart: unless-stopped
environment:
- COURRIER_DB_PATH=/data/courrier.dbBuilding Locally:
If you prefer to build the image locally, use:
version: '3.8'
services:
courrier:
build: .
container_name: courrier
ports:
- "3000:3000"
volumes:
- ./config:/config
- ./data:/data
restart: unless-stopped
environment:
- COURRIER_DB_PATH=/data/courrier.dbSee docker-compose.example.yml for a full example.
Run with:
docker-compose up -d- Rust (latest stable)
- Nix (optional, for development environment)
The project includes a Nix flake for a reproducible development environment:
nix developThe web dashboard provides the following REST API endpoints:
GET /- Web dashboard (HTML)GET /api/accounts- List all configured accountsGET /api/stats- Get statistics (total emails, storage, per-account stats)POST /api/fetch- Trigger a manual fetch operationGET /api/fetch/status- Get current fetch operation status
- Configuration Loading: Reads
Config.tomlto get IMAP server and account details - Database Initialization: Creates/opens SQLite database to track fetched emails
- Mailbox Discovery: Connects to each account and lists all available mailboxes
- Incremental Fetching: For each mailbox, fetches only new emails (not in database)
- Email Storage: Saves emails as
.emlfiles organized by account and mailbox - Web Dashboard: Provides real-time monitoring and manual fetch triggers
MIT License - see LICENSE file for details.
Copyright (c) 2025 Pascal Behmenburg
Contributions are welcome! Please feel free to submit a Pull Request.
For issues, questions, or contributions, please open an issue on the repository.