Rewrite from Python to Go for single-binary cross-platform builds

Replaces imapdown.py with a multi-file Go implementation using
github.com/emersion/go-imap/v2. All features preserved: SSL/STARTTLS,
incremental UID-based downloads, attachment extraction to zip,
modified UTF-7 folder name decoding, and full-mode safety checks.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-25 17:54:41 +00:00
parent 85db1ddba6
commit eb63d8cbc1
11 changed files with 1230 additions and 485 deletions
+143 -52
View File
@@ -1,52 +1,78 @@
# IMAP Downloader
A simple Python script to download all emails from an IMAP server into individual EML files, preserving the folder structure.
Download all emails from an IMAP server into individual EML files, preserving the folder structure.
Single self-contained binary written in Go - fast, cross-platform, no dependencies.
## Quickstart
```bash
# Build the binary
make build
# Download all emails (creates a folder named after your email address)
./imapdown -server imap.gmail.com -email you@gmail.com -user you@gmail.com -password "your-password" -ssl
# Subsequent runs only download new emails
./imapdown -server imap.gmail.com -email you@gmail.com -user you@gmail.com -password "your-password" -ssl
```
## Features
- Downloads emails as standard `.eml` files
- Downloads emails as standard `.eml` files (open in any email client)
- Preserves IMAP folder hierarchy locally
- Extracts attachments into zip files alongside each email
- Supports SSL and STARTTLS connections
- Supports SSL/TLS and STARTTLS connections
- Incremental updates using UID tracking (only download new emails)
- Multi-account support (separate folders per email address)
- Automatic state tracking - never re-downloads the same email
- Configurable download limit for testing/debugging
- Works with Gmail, Outlook, FastMail, and any IMAP server
## Requirements
- Python 3.6+
- No external dependencies (uses only standard library)
- Go 1.21+ (for building from source)
- OR use pre-compiled binaries (no requirements)
## Installation
Download from releases page (coming soon) or build from source:
```bash
# Clone or download the script
# Clone repository
git clone <repo-url>
cd imapdown
# Create virtual environment (optional but recommended)
python3 -m venv .venv
source .venv/bin/activate
# Build the binary
make build
# Or cross-compile for all platforms
make build-all
```
## Usage
### Basic Usage
By default, the script only downloads new emails since the last run (incremental mode). On first run, it downloads everything.
By default, only new emails since the last run are downloaded (incremental mode). On first run, everything is downloaded.
```bash
# Download emails using SSL (most common)
./imapdown.py --server imap.example.com --email me@example.com --user me@example.com --password "secret" --ssl
# Generic IMAP server with SSL (most common)
./imapdown -server imap.example.com -email me@example.com -user me@example.com -password "secret" -ssl
# Using STARTTLS
./imapdown.py --server imap.example.com --email me@example.com --user me@example.com --password "secret" --starttls
# Gmail (requires app-specific password if 2FA enabled)
./imapdown -server imap.gmail.com -email you@gmail.com -user you@gmail.com -password "app-password" -ssl
# Custom port
./imapdown.py --server imap.example.com --email me@example.com --user me@example.com --password "secret" --ssl --port 12993
# Outlook/Office 365
./imapdown -server outlook.office365.com -email you@outlook.com -user you@outlook.com -password "password" -ssl
# Custom storage directory
./imapdown.py --server imap.example.com --email me@example.com --user me@example.com --password "secret" --ssl --store /path/to/backup
./imapdown -server imap.example.com -email me@example.com -user me@example.com -password "secret" -ssl -output /path/to/backup
# Using STARTTLS instead of SSL
./imapdown -server imap.example.com -email me@example.com -user me@example.com -password "secret" -starttls
# Custom port
./imapdown -server imap.example.com -email me@example.com -user me@example.com -password "secret" -ssl -port 12993
```
### Full Download
@@ -54,14 +80,13 @@ By default, the script only downloads new emails since the last run (incremental
To force a complete download of all emails (ignoring previous state):
```bash
./imapdown.py --server imap.example.com --email me@example.com --user me@example.com --password "secret" --ssl --full
./imapdown -server imap.example.com -email me@example.com -user me@example.com -password "secret" -ssl -full
```
**Note:** As a safety measure, `--full` will refuse to run if the download folder already contains emails. This prevents accidental duplicates. To re-download everything, first delete the folder:
**Note:** As a safety measure, `-full` will refuse to run if the download folder already contains emails. This prevents accidental duplicates. To re-download everything, first delete the folder:
```bash
rm -rf download/me@example.com/
./imapdown.py --server imap.example.com --email me@example.com --user me@example.com --password "secret" --ssl --full
rm -rf me@example.com/
```
### Debugging/Testing
@@ -69,44 +94,55 @@ rm -rf download/me@example.com/
Limit the number of emails downloaded:
```bash
./imapdown.py --server imap.example.com --email me@example.com --user me@example.com --password "secret" --ssl --limit 10
./imapdown -server imap.example.com -email me@example.com -user me@example.com -password "secret" -ssl -limit 10
```
## Command Line Arguments
| Argument | Required | Description |
|----------|----------|-------------|
| `--server` | Yes | IMAP server hostname |
| `--email` | Yes | Email address (used for folder organization) |
| `--user` | Yes | Username for authentication |
| `--password` | Yes | Password for authentication |
| `--ssl` | No | Use implicit SSL/TLS (default port 993) |
| `--starttls` | No | Use STARTTLS (default port 143) |
| `--port` | No | Custom port (overrides defaults) |
| `--limit` | No | Maximum number of emails to download |
| `--full` | No | Download all emails (default: only new since last run) |
| `--store` | No | Directory to store downloaded emails (default: ./download) |
| Argument | Flag | Required | Description |
|----------|------|----------|-------------|
| Server | `-server` | Yes | IMAP server hostname |
| Email | `-email` | Yes | Email address (used for folder organization) |
| User | `-user` | Yes | Username for authentication |
| Password | `-password` | Yes | Password for authentication |
| SSL | `-ssl` | No | Use implicit SSL/TLS (default port 993) |
| STARTTLS | `-starttls` | No | Use STARTTLS (default port 143) |
| Port | `-port` | No | Custom port (overrides defaults) |
| Limit | `-limit` | No | Maximum number of emails to download |
| Full | `-full` | No | Download all emails (default: only new since last run) |
| Output | `-output` | No | Directory to store downloaded emails (default: ./{email}) |
Note: `--ssl` and `--starttls` are mutually exclusive.
**Notes:**
- `-ssl` and `-starttls` are mutually exclusive
## Output Structure
The default output structure (when `--store` is not specified):
**Without `-output` flag** (default: `./{email_address}/`):
```
./download/
├── user@example.com/
│ ├── .imapdown_state.json # Tracks last downloaded UID per folder
│ ├── INBOX/
│ ├── 123_20240115_Meeting_notes.eml
│ ├── 124_20240116_Report.eml
│ │ └── 124_20240116_Report.zip # Attachments (if any)
── Sent/
│ │ └── 456_20240114_RE_Question.eml
└── Archive/
│ └── 789_20240101_Old_email.eml
└── another@example.com/
└── ...
./user@example.com/
├── .imapdown_state.json # Tracks last downloaded UID per folder
├── INBOX/
│ ├── 123_20240115_Meeting_notes.eml
│ ├── 124_20240116_Report.eml
── 124_20240116_Report.zip # Attachments (if any)
├── Sent/
── 456_20240114_RE_Question.eml
└── Archive/
└── 789_20240101_Old_email.eml
```
**With `-output /path/to/backup`** (emails go directly into specified directory):
```
/path/to/backup/
├── .imapdown_state.json
├── INBOX/
│ ├── 123_20240115_Meeting_notes.eml
│ ├── 124_20240116_Report.eml
│ └── 124_20240116_Report.zip
├── Sent/
│ └── 456_20240114_RE_Question.eml
└── Archive/
└── 789_20240101_Old_email.eml
```
### File Naming
@@ -123,7 +159,7 @@ When an email contains attachments, they are extracted and saved in a zip file w
## State Tracking
The script maintains a `.imapdown_state.json` file in each email account's folder. This file tracks the highest downloaded UID for each IMAP folder, enabling efficient incremental updates with `--update`.
A `.imapdown_state.json` file is maintained in the download folder. This file tracks the highest downloaded UID for each IMAP folder, enabling efficient incremental updates.
Example state file:
```json
@@ -134,6 +170,61 @@ Example state file:
}
```
## Building from Source
```bash
# Build for current platform
make build
# Cross-compile for all platforms
make build-all
# Produces: imapdown-linux-amd64, imapdown-linux-arm64,
# imapdown-darwin-amd64, imapdown-darwin-arm64,
# imapdown-windows-amd64.exe
# Install to $GOPATH/bin
make install
# Clean build artifacts
make clean
# Or use Go directly
go build -ldflags="-s -w" -o imapdown
```
## Troubleshooting
### Gmail Authentication
Gmail requires an app-specific password if you have 2-factor authentication enabled:
1. Go to Google Account Settings → Security → 2-Step Verification → App passwords
2. Generate a new app password for "Mail"
3. Use this password instead of your regular password
### Connection Issues
- **SSL errors**: Make sure you're using the correct port (993 for SSL, 143 for STARTTLS)
- **Authentication failed**: Verify username and password are correct
- **Timeout**: Some servers require STARTTLS instead of SSL - try `-starttls` flag
### First Run Not Downloading
If the first run doesn't download anything:
1. Check the folder actually contains emails on the server
2. Try with `-limit 10` to test with a small batch first
3. Verify your credentials work by logging into webmail
### Re-downloading Everything
To start fresh and re-download all emails:
```bash
# Delete the email folder (and state file)
rm -rf ./your-email@example.com/
# Run with -full flag
./imapdown -server imap.example.com -email your-email@example.com -user your-email@example.com -password "password" -ssl -full
```
## License
MIT