chore: Release cull-gmail v0.0.11
This commit is contained in:
47
CHANGELOG.md
47
CHANGELOG.md
@@ -5,22 +5,56 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.0.11] - 2025-10-20
|
||||
|
||||
Summary: Added[7], Changed[7], Chore[12], Continuous Integration[5], Documentation[24], Fixed[7], Testing[12]
|
||||
|
||||
### Added
|
||||
|
||||
- ✨ feat(test): add junit report
|
||||
- ✨ feat(ci): introduce nextest test runner
|
||||
- ✨ feat(retention): implement retention policy configuration
|
||||
- ✨ feat(error): add invalid message age error
|
||||
- ✨ feat(retention): enhance message age with parsing and validation
|
||||
- ✨ feat(retention): introduce message age specification
|
||||
- ✨ feat(retention): enhance retention policy configuration
|
||||
|
||||
### Fixed
|
||||
|
||||
- 🐛 fix(rule_processor): correct spelling of "behaviour"
|
||||
- ✅ fix(message-list): improve idioms (avoid redundant clone, extend labels, safer message extraction)
|
||||
- ✅ fix(clippy): move tests module to file end to satisfy items_after_test_module lint
|
||||
- 🐛 fix(retention): fix debug string formatting in retention struct
|
||||
- 🐛 fix(cli): correct error mapping in add_cli
|
||||
- 🐛 fix(rules): handle message age creation error
|
||||
- 🐛 fix(build): correct readme generation script
|
||||
|
||||
### Changed
|
||||
|
||||
- ♻️ refactor: remove redundant credential module
|
||||
- ♻️ refactor(message-list): introduce GmailService abstraction and refactor to use it; fix borrows and lifetimes
|
||||
- ♻️ refactor(message-list): extract helper to append messages from ListMessagesResponse and add unit test
|
||||
- ♻️ refactor(rule_processor): extract process_label and add internal ops trait for unit testing
|
||||
- ♻️ refactor(rule_processor): add TRASH_LABEL, correct Gmail scopes, early returns, and improve idioms
|
||||
- refactor(rules): replace unwrap() with explicit error handling and propagate errors safely
|
||||
- refactor(rules): apply idiomatic patterns and resolve clippy warnings
|
||||
|
||||
## [0.0.10] - 2025-10-16
|
||||
|
||||
Summary: Added[11], Changed[15], Chore[11], Fixed[3]
|
||||
Summary: Added[11], Changed[15], Chore[12], Fixed[3]
|
||||
|
||||
### Added
|
||||
|
||||
- ✨ feat(cli): add default subcommand for rule execution
|
||||
- ✨ feat(config): implement config builder pattern for ClientConfig
|
||||
- ✨ feat(cli): load configurations from toml file
|
||||
- ✨ feat(client_config): add config root parsing with regex
|
||||
- ✨ feat(utils): add test utils module
|
||||
- ✨ feat(deps): add lazy-regex crate
|
||||
- ✨ feat(dependencies): add lazy-regex dependency
|
||||
- ✨ feat(config): add ConfigRoot enum for flexible path handling
|
||||
- ✨ feat(core): add client config
|
||||
- ✨ feat(config): introduce client configuration
|
||||
- ✨ feat(cli): load configurations from toml file
|
||||
- ✨ feat(client_config): add config root parsing with regex
|
||||
- ✨ feat(cli): add config file support
|
||||
|
||||
### Fixed
|
||||
@@ -32,12 +66,12 @@ Summary: Added[11], Changed[15], Chore[11], Fixed[3]
|
||||
### Changed
|
||||
|
||||
- ♻️ refactor(cli): extract action execution into a function
|
||||
- ♻️ refactor(cli): extract rule execution to separate function
|
||||
- ♻️ refactor(cli): rename get_config to get_rules
|
||||
- ♻️ refactor(cli): extract rule execution to separate function
|
||||
- ♻️ refactor(config): improve ConfigRoot to handle different root types
|
||||
- ♻️ refactor(utils): improve config directory creation
|
||||
- ♻️ refactor(cli): use ClientConfig struct for gmail client
|
||||
- ♻️ refactor(gmail): use client config for gmail client
|
||||
- ♻️ refactor(utils): improve config directory creation
|
||||
- ♻️ refactor(rules): remove credentials config
|
||||
- ♻️ refactor(cli): remove config from run args
|
||||
- ♻️ refactor(eol_rule): improve labels handling
|
||||
@@ -440,7 +474,8 @@ Summary: Added[4], Build[3], Chore[21], Continuous Integration[4], Documentation
|
||||
- ✨ feat(vscode): add custom dictionary entry for ltex
|
||||
- ✨ feat(project): add initial Cargo.toml for cull-gmail tool
|
||||
|
||||
[Unreleased]: https://github.com/jerus-org/cull-gmail/compare/v0.0.9...HEAD
|
||||
[Unreleased]: https://github.com/jerus-org/cull-gmail/compare/v0.0.10...HEAD
|
||||
[0.0.10]: https://github.com/jerus-org/cull-gmail/compare/v0.0.9...v0.0.10
|
||||
[0.0.9]: https://github.com/jerus-org/cull-gmail/compare/v0.0.8...v0.0.9
|
||||
[0.0.8]: https://github.com/jerus-org/cull-gmail/compare/v0.0.7...v0.0.8
|
||||
[0.0.7]: https://github.com/jerus-org/cull-gmail/compare/v0.0.6...v0.0.7
|
||||
|
||||
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -370,7 +370,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cull-gmail"
|
||||
version = "0.0.10"
|
||||
version = "0.0.11"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "cull-gmail"
|
||||
description = "Cull emails from a gmail account using the gmail API"
|
||||
version = "0.0.10"
|
||||
version = "0.0.11"
|
||||
authors = ["Jeremiah Russell <jrussell@jerus.ie>"]
|
||||
edition = "2024"
|
||||
rust-version = "1.88"
|
||||
|
||||
4
PRLOG.md
4
PRLOG.md
@@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
## [0.0.11] - 2025-10-20
|
||||
|
||||
### Added
|
||||
|
||||
@@ -255,7 +255,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
[#84]: https://github.com/jerus-org/cull-gmail/pull/84
|
||||
[#85]: https://github.com/jerus-org/cull-gmail/pull/85
|
||||
[#86]: https://github.com/jerus-org/cull-gmail/pull/86
|
||||
[Unreleased]: https://github.com/jerus-org/cull-gmail/compare/v0.0.10...HEAD
|
||||
[0.0.11]: https://github.com/jerus-org/cull-gmail/compare/v0.0.10...v0.0.11
|
||||
[0.0.10]: https://github.com/jerus-org/cull-gmail/compare/v0.0.9...v0.0.10
|
||||
[0.0.9]: https://github.com/jerus-org/cull-gmail/compare/v0.0.8...v0.0.9
|
||||
[0.0.8]: https://github.com/jerus-org/cull-gmail/compare/v0.0.7...v0.0.8
|
||||
|
||||
945
README.md
945
README.md
@@ -31,46 +31,945 @@ The `cull-gmail` provides a software library and command line program to enable
|
||||
|
||||
## Main Features
|
||||
|
||||
- login to get authorization
|
||||
- backup the mailbox
|
||||
- filtered lists of the contents
|
||||
- move email matching a filtered list to trash
|
||||
## cull-gmail Library Documentation
|
||||
- list labels and messages to aid planning rules
|
||||
- configure the rules list
|
||||
- run the rules list
|
||||
- run the rules list be default
|
||||
- configure api client by file or environment variables
|
||||
|
||||
### Running the optional Gmail integration test
|
||||
|
||||
The `cull-gmail` library provides types to enable the culling of emails using the Gmail API including the following steps:
|
||||
- login to get authorization
|
||||
- backup the mailbox
|
||||
- filtered lists of the contents
|
||||
- move email matching a filtered list to trash
|
||||
An optional, ignored integration test exercises the Gmail API end-to-end (networked). It is ignored by default and will not run in CI.
|
||||
|
||||
### Installation
|
||||
Steps to run locally:
|
||||
|
||||
Add the library to your program's `Cargo.toml` using `cargo add`:
|
||||
1. Ensure you have valid OAuth client credentials configured for the library (see `ClientConfig::builder()` usage in docs).
|
||||
2. Run the test explicitly with the ignored flag:
|
||||
|
||||
```bash
|
||||
$ cargo add cull-gmail
|
||||
cargo test --test gmail_message_list_integration -- --ignored
|
||||
```
|
||||
|
||||
Or by configuring the dependencies manually in `Cargo.toml`:
|
||||
Notes:
|
||||
- The test performs a lightweight listing (max 10 messages) and should be safe, but it still uses your Gmail account.
|
||||
- Do not run this in CI; it is intended only for local verification.
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
cull-gmail = "0.0.10"
|
||||
```
|
||||
# cull-gmail CLI Documentation
|
||||
|
||||
## cull-gmail CLI
|
||||
A command-line program for managing Gmail messages using the Gmail API. The tool provides subcommands for label querying, message querying, rule configuration, and rule execution to trash/delete messages with built-in safety features like dry-run mode.
|
||||
|
||||
A command line program to cull emails from Gmail using the Gmail API. The tool has sub-commands to for authorization, planning and executing the move of select email to the Gmail trash folder from which they will be automatically deleted after thirty days.
|
||||
## Installation
|
||||
|
||||
### Installation
|
||||
|
||||
Install cull-gmail using Cargo:
|
||||
### From Crates.io
|
||||
|
||||
```bash
|
||||
cargo install cull-gmail
|
||||
```
|
||||
|
||||
### From Source
|
||||
|
||||
```bash
|
||||
git clone https://github.com/jerus-org/cull-gmail.git
|
||||
cd cull-gmail
|
||||
cargo install --path .
|
||||
```
|
||||
|
||||
### Verify Installation
|
||||
|
||||
```bash
|
||||
cull-gmail --version
|
||||
```
|
||||
|
||||
## Authentication Setup
|
||||
|
||||
### 1. Google Cloud Console Setup
|
||||
|
||||
1. Visit the [Google Cloud Console](https://console.cloud.google.com/)
|
||||
2. Create a new project or select an existing one
|
||||
3. Enable the Gmail API:
|
||||
- Go to "APIs & Services" > "Library"
|
||||
- Search for "Gmail API" and enable it
|
||||
4. Create OAuth2 credentials:
|
||||
- Go to "APIs & Services" > "Credentials"
|
||||
- Click "Create Credentials" > "OAuth client ID"
|
||||
- Choose "Desktop application"
|
||||
- Download the JSON file
|
||||
|
||||
### 2. Configure cull-gmail
|
||||
|
||||
1. Create the configuration directory:
|
||||
```bash
|
||||
mkdir -p ~/.cull-gmail
|
||||
```
|
||||
|
||||
2. Copy your OAuth2 credential file:
|
||||
```bash
|
||||
cp ~/Downloads/client_secret_*.json ~/.cull-gmail/client_secret.json
|
||||
```
|
||||
|
||||
3. Create configuration file `~/.cull-gmail/cull-gmail.toml`:
|
||||
```toml
|
||||
credential_file = "client_secret.json"
|
||||
config_root = "~/.cull-gmail"
|
||||
rules = "rules.toml"
|
||||
execute = false # Start in dry-run mode
|
||||
```
|
||||
|
||||
### 3. First Run Authentication
|
||||
|
||||
Run any command to trigger the OAuth flow:
|
||||
|
||||
```bash
|
||||
cull-gmail labels
|
||||
```
|
||||
|
||||
This will:
|
||||
1. Open your browser for Google authentication
|
||||
2. Prompt you to grant Gmail access
|
||||
3. Save tokens to `~/.cull-gmail/gmail1/`
|
||||
|
||||
## Configuration
|
||||
|
||||
### Configuration File
|
||||
|
||||
**Location**: `~/.cull-gmail/cull-gmail.toml`
|
||||
|
||||
```toml
|
||||
# OAuth2 credential file (relative to config_root)
|
||||
credential_file = "client_secret.json"
|
||||
|
||||
# Configuration directory
|
||||
config_root = "~/.cull-gmail"
|
||||
|
||||
# Rules file
|
||||
rules = "rules.toml"
|
||||
|
||||
# Default execution mode (false = dry-run, true = execute)
|
||||
execute = false
|
||||
|
||||
# Alternative: Direct OAuth2 configuration
|
||||
# client_id = "your-client-id.apps.googleusercontent.com"
|
||||
# client_secret = "your-client-secret"
|
||||
# token_uri = "https://oauth2.googleapis.com/token"
|
||||
# auth_uri = "https://accounts.google.com/o/oauth2/auth"
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
Override any configuration setting:
|
||||
|
||||
```bash
|
||||
export APP_CREDENTIAL_FILE="client_secret.json"
|
||||
export APP_EXECUTE="true"
|
||||
export APP_CLIENT_ID="your-client-id"
|
||||
export APP_CLIENT_SECRET="your-client-secret"
|
||||
export APP_CONFIG_ROOT="/custom/config/path"
|
||||
```
|
||||
|
||||
## Command Structure
|
||||
|
||||
```bash
|
||||
cull-gmail [OPTIONS] [COMMAND]
|
||||
```
|
||||
|
||||
### Global Options
|
||||
|
||||
- `-v, --verbose...`: Increase logging verbosity (can be used multiple times)
|
||||
- `-q, --quiet...`: Decrease logging verbosity
|
||||
- `-h, --help`: Show help
|
||||
- `-V, --version`: Show version
|
||||
|
||||
### Commands
|
||||
|
||||
- `labels`: List available Gmail labels
|
||||
- `messages`: Query and operate on messages
|
||||
- `rules`: Configure and run retention rules
|
||||
|
||||
## Command Reference
|
||||
|
||||
### Labels Command
|
||||
|
||||
List all labels in your Gmail account:
|
||||
|
||||
```bash
|
||||
cull-gmail labels
|
||||
```
|
||||
|
||||
**Example Output**:
|
||||
```
|
||||
INBOX: INBOX
|
||||
IMPORTANT: IMPORTANT
|
||||
CHAT: CHAT
|
||||
SENT: SENT
|
||||
DRAFT: DRAFT
|
||||
promotions: Label_1234567890
|
||||
old-emails: Label_0987654321
|
||||
```
|
||||
|
||||
### Messages Command
|
||||
|
||||
Query and operate on Gmail messages.
|
||||
|
||||
#### Syntax
|
||||
|
||||
```bash
|
||||
cull-gmail messages [OPTIONS] <ACTION>
|
||||
```
|
||||
|
||||
#### Options
|
||||
|
||||
- `-l, --labels <LABELS>`: Filter by labels (can be used multiple times)
|
||||
- `-m, --max-results <MAX_RESULTS>`: Maximum results per page [default: 200]
|
||||
- `-p, --pages <PAGES>`: Maximum number of pages (0=all) [default: 1]
|
||||
- `-Q, --query <QUERY>`: Gmail query string
|
||||
|
||||
#### Actions
|
||||
|
||||
- `list`: Display message information
|
||||
- `trash`: Move messages to trash
|
||||
- `delete`: Permanently delete messages
|
||||
|
||||
#### Examples
|
||||
|
||||
**List recent messages**:
|
||||
```bash
|
||||
cull-gmail messages -m 10 list
|
||||
```
|
||||
|
||||
**List promotional emails older than 6 months**:
|
||||
```bash
|
||||
cull-gmail messages -Q "label:promotions older_than:6m" list
|
||||
```
|
||||
|
||||
**Move old promotional emails to trash**:
|
||||
```bash
|
||||
cull-gmail messages -Q "label:promotions older_than:1y" trash
|
||||
```
|
||||
|
||||
**Permanently delete very old messages**:
|
||||
```bash
|
||||
cull-gmail messages -Q "older_than:5y -label:important" delete
|
||||
```
|
||||
|
||||
**Query with multiple labels**:
|
||||
```bash
|
||||
cull-gmail messages -l "promotions" -l "newsletters" -Q "older_than:3m" list
|
||||
```
|
||||
|
||||
**Process all pages (not just first page)**:
|
||||
```bash
|
||||
cull-gmail messages -p 0 -Q "older_than:2y" list
|
||||
```
|
||||
|
||||
### Rules Command
|
||||
|
||||
Manage retention rules for automated email lifecycle management.
|
||||
|
||||
#### Syntax
|
||||
|
||||
```bash
|
||||
cull-gmail rules <SUBCOMMAND>
|
||||
```
|
||||
|
||||
#### Subcommands
|
||||
|
||||
- `config`: Configure retention rules
|
||||
- `run`: Execute configured rules
|
||||
|
||||
### Rules Config Command
|
||||
|
||||
Configure retention rules:
|
||||
|
||||
```bash
|
||||
cull-gmail rules config <ACTION>
|
||||
```
|
||||
|
||||
#### Config Actions
|
||||
|
||||
- `rules`: Manage rule definitions
|
||||
- `label`: Add/remove labels from rules
|
||||
- `action`: Set action (trash/delete) on rules
|
||||
|
||||
**Example Rules Configuration**:
|
||||
|
||||
Create/edit `~/.cull-gmail/rules.toml`:
|
||||
|
||||
```toml
|
||||
[rules."1"]
|
||||
id = 1
|
||||
retention = { age = "y:1", generate_label = true }
|
||||
labels = ["old-emails"]
|
||||
action = "Trash"
|
||||
|
||||
[rules."2"]
|
||||
id = 2
|
||||
retention = { age = "m:6", generate_label = true }
|
||||
labels = ["promotions", "newsletters"]
|
||||
action = "Trash"
|
||||
|
||||
[rules."3"]
|
||||
id = 3
|
||||
retention = { age = "y:5", generate_label = true }
|
||||
labels = ["archive"]
|
||||
action = "Delete"
|
||||
```
|
||||
|
||||
### Rules Run Command
|
||||
|
||||
Execute configured rules:
|
||||
|
||||
```bash
|
||||
cull-gmail rules run [OPTIONS]
|
||||
```
|
||||
|
||||
#### Options
|
||||
|
||||
- `-e, --execute`: Actually perform actions (without this, runs in dry-run mode)
|
||||
- `-t, --skip-trash`: Skip rules with "trash" action
|
||||
- `-d, --skip-delete`: Skip rules with "delete" action
|
||||
|
||||
#### Examples
|
||||
|
||||
**Dry-run all rules** (safe, no changes made):
|
||||
```bash
|
||||
cull-gmail rules run
|
||||
```
|
||||
|
||||
**Execute all rules**:
|
||||
```bash
|
||||
cull-gmail rules run --execute
|
||||
```
|
||||
|
||||
**Execute only delete rules**:
|
||||
```bash
|
||||
cull-gmail rules run --execute --skip-trash
|
||||
```
|
||||
|
||||
**Execute only trash rules**:
|
||||
```bash
|
||||
cull-gmail rules run --execute --skip-delete
|
||||
```
|
||||
|
||||
## Gmail Query Syntax
|
||||
|
||||
The `-Q, --query` option supports Gmail's powerful search syntax:
|
||||
|
||||
### Date Queries
|
||||
|
||||
```bash
|
||||
# Relative dates
|
||||
-Q "older_than:1y" # Older than 1 year
|
||||
-Q "newer_than:30d" # Newer than 30 days
|
||||
-Q "older_than:6m" # Older than 6 months
|
||||
|
||||
# Absolute dates
|
||||
-Q "after:2023/1/1" # After January 1, 2023
|
||||
-Q "before:2023/12/31" # Before December 31, 2023
|
||||
```
|
||||
|
||||
### Label Queries
|
||||
|
||||
```bash
|
||||
# Has label
|
||||
-Q "label:promotions"
|
||||
-Q "label:important"
|
||||
|
||||
# Does NOT have label (note the minus sign)
|
||||
-Q "-label:important"
|
||||
-Q "-label:spam"
|
||||
```
|
||||
|
||||
### Content Queries
|
||||
|
||||
```bash
|
||||
# Subject line
|
||||
-Q "subject:newsletter"
|
||||
-Q "subject:(unsubscribe OR newsletter)"
|
||||
|
||||
# From/To
|
||||
-Q "from:noreply@example.com"
|
||||
-Q "to:me@example.com"
|
||||
|
||||
# Message content
|
||||
-Q "unsubscribe"
|
||||
-Q "has:attachment"
|
||||
```
|
||||
|
||||
### Status Queries
|
||||
|
||||
```bash
|
||||
# Read status
|
||||
-Q "is:unread"
|
||||
-Q "is:read"
|
||||
|
||||
# Star status
|
||||
-Q "is:starred"
|
||||
-Q "-is:starred"
|
||||
|
||||
# Size
|
||||
-Q "size:larger_than:10M"
|
||||
-Q "size:smaller_than:1M"
|
||||
```
|
||||
|
||||
### Combined Queries
|
||||
|
||||
```bash
|
||||
# Complex combinations
|
||||
-Q "label:promotions older_than:6m -is:starred"
|
||||
-Q "from:newsletters@example.com older_than:1y has:attachment"
|
||||
-Q "subject:newsletter OR subject:promo older_than:3m"
|
||||
```
|
||||
|
||||
## Common Workflows
|
||||
|
||||
### 1. Clean Up Promotional Emails
|
||||
|
||||
```bash
|
||||
# Step 1: Preview what will be affected
|
||||
cull-gmail messages -Q "label:promotions older_than:6m" list
|
||||
|
||||
# Step 2: Move to trash (can be recovered for 30 days)
|
||||
cull-gmail messages -Q "label:promotions older_than:6m" trash
|
||||
```
|
||||
|
||||
### 2. Archive Old Conversations
|
||||
|
||||
```bash
|
||||
# Archive conversations older than 2 years (excluding starred)
|
||||
cull-gmail messages -Q "older_than:2y -is:starred -label:important" trash
|
||||
```
|
||||
|
||||
### 3. Delete Very Old Messages
|
||||
|
||||
```bash
|
||||
# Permanently delete messages older than 5 years (be careful!)
|
||||
cull-gmail messages -Q "older_than:5y -is:starred -label:important" delete
|
||||
```
|
||||
|
||||
### 4. Rule-Based Automation
|
||||
|
||||
```bash
|
||||
# Set up rules in ~/.cull-gmail/rules.toml, then:
|
||||
|
||||
# Preview what rules will do
|
||||
cull-gmail rules run
|
||||
|
||||
# Execute rules
|
||||
cull-gmail rules run --execute
|
||||
```
|
||||
|
||||
### 5. Scheduled Cleanup
|
||||
|
||||
Add to your crontab for weekly cleanup:
|
||||
|
||||
```bash
|
||||
# Edit crontab
|
||||
crontab -e
|
||||
|
||||
# Add this line (runs every Sunday at 2 AM)
|
||||
0 2 * * 0 /home/user/.cargo/bin/cull-gmail rules run --execute >> /var/log/cull-gmail.log 2>&1
|
||||
```
|
||||
|
||||
## Safety Features
|
||||
|
||||
### Dry-Run Mode
|
||||
|
||||
- **Default behaviour**: All operations are dry-run unless explicitly executed
|
||||
- **Messages**: Use `list` action to preview what would be affected
|
||||
- **Rules**: Run without `--execute` flag to see what would happen
|
||||
|
||||
### Confirmation and Logging
|
||||
|
||||
- All operations are logged with detailed information
|
||||
- Use `-v` for verbose logging to see exactly what's happening
|
||||
- Check log output before running destructive operations
|
||||
|
||||
### Recoverable Operations
|
||||
|
||||
- **Trash**: Messages moved to trash can be recovered for 30 days
|
||||
- **Delete**: Permanent deletion - cannot be undone
|
||||
|
||||
## Logging and Debugging
|
||||
|
||||
### Environment Variables
|
||||
|
||||
```bash
|
||||
# Set log level
|
||||
export RUST_LOG=cull_gmail=debug
|
||||
|
||||
# Enable all logging
|
||||
export RUST_LOG=debug
|
||||
```
|
||||
|
||||
### Verbosity Levels
|
||||
|
||||
```bash
|
||||
# Quiet (errors only)
|
||||
cull-gmail -q messages list
|
||||
|
||||
# Normal (default)
|
||||
cull-gmail messages list
|
||||
|
||||
# Verbose (info level)
|
||||
cull-gmail -v messages list
|
||||
|
||||
# Very verbose (debug level)
|
||||
cull-gmail -vv messages list
|
||||
|
||||
# Maximum verbosity (trace level)
|
||||
cull-gmail -vvv messages list
|
||||
```
|
||||
|
||||
### Log Information
|
||||
|
||||
- **Error**: Critical issues
|
||||
- **Warn**: Non-fatal issues, dry-run notifications
|
||||
- **Info**: General operation info, message subjects, counts
|
||||
- **Debug**: Detailed API calls, query strings
|
||||
- **Trace**: Very detailed debugging information
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Authentication Issues
|
||||
|
||||
**Problem**: "Authentication failed" or "Invalid credentials"
|
||||
|
||||
**Solutions**:
|
||||
1. Verify OAuth2 credential file exists and is valid JSON
|
||||
2. Check OAuth client is configured as "Desktop Application"
|
||||
3. Clear token cache: `rm -rf ~/.cull-gmail/gmail1`
|
||||
4. Re-run authentication: `cull-gmail labels`
|
||||
|
||||
**Problem**: "Access denied" or "Insufficient permissions"
|
||||
|
||||
**Solutions**:
|
||||
1. Verify Gmail API is enabled in Google Cloud Console
|
||||
2. Check OAuth scopes include Gmail access
|
||||
3. Re-authenticate with proper permissions
|
||||
|
||||
### Query Issues
|
||||
|
||||
**Problem**: "No messages found" when you expect results
|
||||
|
||||
**Solutions**:
|
||||
1. Test query in Gmail web interface first
|
||||
2. Check label names: `cull-gmail labels`
|
||||
3. Verify query syntax (no typos)
|
||||
4. Use `-v` flag to see the actual query being sent
|
||||
|
||||
**Problem**: Query returns unexpected results
|
||||
|
||||
**Solutions**:
|
||||
1. Use `messages list` to preview before `trash`/`delete`
|
||||
2. Check for operator precedence in complex queries
|
||||
3. Test simpler queries first, then combine
|
||||
|
||||
### Performance Issues
|
||||
|
||||
**Problem**: Operations are slow or timeout
|
||||
|
||||
**Solutions**:
|
||||
1. Reduce page size: `-m 100`
|
||||
2. Limit pages: `-p 5` instead of `-p 0`
|
||||
3. Use more specific queries to reduce result sets
|
||||
4. Check Gmail API quotas in Google Cloud Console
|
||||
|
||||
### Configuration Issues
|
||||
|
||||
**Problem**: "Configuration not found" or "Config parse error"
|
||||
|
||||
**Solutions**:
|
||||
1. Verify config file path: `~/.cull-gmail/cull-gmail.toml`
|
||||
2. Check TOML syntax
|
||||
3. Ensure OAuth2 credential file path is correct
|
||||
4. Use absolute paths if relative paths fail
|
||||
|
||||
## Exit Codes
|
||||
|
||||
- **0**: Success
|
||||
- **101**: Error (check stderr for details)
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic Message Management
|
||||
|
||||
```bash
|
||||
# List all labels
|
||||
cull-gmail labels
|
||||
|
||||
# List first 50 messages
|
||||
cull-gmail messages -m 50 list
|
||||
|
||||
# List promotional emails from last year
|
||||
cull-gmail messages -Q "label:promotions after:2023/1/1" list
|
||||
```
|
||||
|
||||
### Batch Operations
|
||||
|
||||
```bash
|
||||
# Move old promotional emails to trash
|
||||
cull-gmail messages -Q "label:promotions older_than:1y" trash
|
||||
|
||||
# Permanently delete very old messages (careful!)
|
||||
cull-gmail messages -Q "older_than:5y -is:starred" delete
|
||||
```
|
||||
|
||||
### Rule-Based Management
|
||||
|
||||
```bash
|
||||
# Preview all rules
|
||||
cull-gmail rules run
|
||||
|
||||
# Execute only trash rules
|
||||
cull-gmail rules run --execute --skip-delete
|
||||
|
||||
# Execute all rules
|
||||
cull-gmail rules run --execute
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
||||
- [Library Documentation](lib.md) - Rust API reference and programming examples
|
||||
- [API Documentation](https://docs.rs/cull-gmail) - Generated API reference
|
||||
- [Repository](https://github.com/jerus-org/cull-gmail) - Source code, examples, and issue tracking
|
||||
- [Gmail API Documentation](https://developers.google.com/gmail/api) - Google's official API docs
|
||||
- [Gmail Search Operators](https://support.google.com/mail/answer/7190?hl=en) - Complete Gmail query syntax
|
||||
# cull-gmail Library Documentation
|
||||
|
||||
The `cull-gmail` library provides a Rust API for managing Gmail messages through the Gmail API. It enables programmatic email culling operations including authentication, message querying, filtering, and batch operations (trash/delete).
|
||||
|
||||
## Installation
|
||||
|
||||
Add the library to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
cull-gmail = "0.0.11"
|
||||
tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] }
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
Here's a minimal example to get started:
|
||||
|
||||
```rust path=null start=null
|
||||
use cull_gmail::{ClientConfig, GmailClient, Result};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
// Load configuration from file or environment
|
||||
let config = ClientConfig::builder()
|
||||
.with_credential_file("credential.json")
|
||||
.build();
|
||||
|
||||
// Create Gmail client and authenticate
|
||||
let mut client = GmailClient::new_with_config(config).await?;
|
||||
|
||||
// List first 10 messages
|
||||
client.set_max_results(10);
|
||||
client.get_messages(1).await?;
|
||||
client.log_messages().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
## Core Types
|
||||
|
||||
### GmailClient
|
||||
|
||||
The main client for interacting with Gmail API:
|
||||
|
||||
```rust path=null start=null
|
||||
use cull_gmail::{GmailClient, MessageList};
|
||||
|
||||
// Create client with configuration
|
||||
let mut client = GmailClient::new_with_config(config).await?;
|
||||
|
||||
// Query messages with Gmail search syntax
|
||||
client.set_query("older_than:1y label:promotions");
|
||||
client.add_labels(&["INBOX".to_string()])?;
|
||||
client.set_max_results(200);
|
||||
|
||||
// Get messages (0 = all pages, 1 = first page only)
|
||||
client.get_messages(0).await?;
|
||||
|
||||
// Access message data
|
||||
let messages = client.messages();
|
||||
let message_ids = client.message_ids();
|
||||
```
|
||||
|
||||
### ClientConfig
|
||||
|
||||
Handles authentication and configuration:
|
||||
|
||||
```rust path=null start=null
|
||||
use cull_gmail::ClientConfig;
|
||||
|
||||
// From credential file
|
||||
let config = ClientConfig::builder()
|
||||
.with_credential_file("path/to/credential.json")
|
||||
.with_config_path(".cull-gmail")
|
||||
.build();
|
||||
|
||||
// From individual OAuth2 parameters
|
||||
let config = ClientConfig::builder()
|
||||
.with_client_id("your-client-id")
|
||||
.with_client_secret("your-client-secret")
|
||||
.with_auth_uri("https://accounts.google.com/o/oauth2/auth")
|
||||
.with_token_uri("https://oauth2.googleapis.com/token")
|
||||
.add_redirect_uri("http://localhost:8080")
|
||||
.build();
|
||||
```
|
||||
|
||||
### Rules and Retention Policies
|
||||
|
||||
Define automated message lifecycle rules:
|
||||
|
||||
```rust path=null start=null
|
||||
use cull_gmail::{Rules, Retention, MessageAge, EolAction};
|
||||
|
||||
// Create a rule set
|
||||
let mut rules = Rules::new();
|
||||
|
||||
// Add retention rules
|
||||
rules.add_rule(
|
||||
Retention::new(MessageAge::Years(1), true),
|
||||
Some(&"old-emails".to_string()),
|
||||
false // false = trash, true = delete
|
||||
);
|
||||
|
||||
rules.add_rule(
|
||||
Retention::new(MessageAge::Months(6), true),
|
||||
Some(&"promotions".to_string()),
|
||||
false
|
||||
);
|
||||
|
||||
// Save rules to file
|
||||
rules.save()?;
|
||||
|
||||
// Load existing rules
|
||||
let loaded_rules = Rules::load()?;
|
||||
```
|
||||
|
||||
### Message Operations
|
||||
|
||||
Batch operations on messages:
|
||||
|
||||
```rust path=null start=null
|
||||
use cull_gmail::{RuleProcessor, EolAction};
|
||||
|
||||
// Set up rule and dry-run mode
|
||||
client.set_execute(false); // Dry run - no actual changes
|
||||
let rule = rules.get_rule(1).unwrap();
|
||||
client.set_rule(rule);
|
||||
|
||||
// Find messages matching rule for a label
|
||||
client.find_rule_and_messages_for_label("promotions").await?;
|
||||
|
||||
// Check what action would be performed
|
||||
if let Some(action) = client.action() {
|
||||
match action {
|
||||
EolAction::Trash => println!("Would move {} messages to trash", client.messages().len()),
|
||||
EolAction::Delete => println!("Would delete {} messages permanently", client.messages().len()),
|
||||
}
|
||||
}
|
||||
|
||||
// Execute for real
|
||||
client.set_execute(true);
|
||||
match client.action() {
|
||||
Some(EolAction::Trash) => client.batch_trash().await?,
|
||||
Some(EolAction::Delete) => client.batch_delete().await?,
|
||||
None => println!("No action specified"),
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### OAuth2 Setup
|
||||
|
||||
1. Create OAuth2 credentials in [Google Cloud Console](https://console.cloud.google.com/)
|
||||
2. Download the credential JSON file
|
||||
3. Configure the client:
|
||||
|
||||
```rust path=null start=null
|
||||
let config = ClientConfig::builder()
|
||||
.with_credential_file("path/to/credential.json")
|
||||
.build();
|
||||
```
|
||||
|
||||
### Configuration File
|
||||
|
||||
The library supports TOML configuration files (default: `~/.cull-gmail/cull-gmail.toml`):
|
||||
|
||||
```toml
|
||||
credentials = "credential.json"
|
||||
config_root = "~/.cull-gmail"
|
||||
rules = "rules.toml"
|
||||
execute = false
|
||||
|
||||
# Alternative: direct OAuth2 parameters
|
||||
# client_id = "your-client-id"
|
||||
# client_secret = "your-client-secret"
|
||||
# token_uri = "https://oauth2.googleapis.com/token"
|
||||
# auth_uri = "https://accounts.google.com/o/oauth2/auth"
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
Override configuration with environment variables:
|
||||
|
||||
```bash
|
||||
export APP_CREDENTIALS="/path/to/credential.json"
|
||||
export APP_EXECUTE="true"
|
||||
export APP_CLIENT_ID="your-client-id"
|
||||
export APP_CLIENT_SECRET="your-client-secret"
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
The library uses a comprehensive error type:
|
||||
|
||||
```rust path=null start=null
|
||||
use cull_gmail::{Error, Result};
|
||||
|
||||
match client.get_messages(1).await {
|
||||
Ok(_) => println!("Success!"),
|
||||
Err(Error::NoLabelsFound) => println!("No labels found in mailbox"),
|
||||
Err(Error::LabelNotFoundInMailbox(label)) => println!("Label '{}' not found", label),
|
||||
Err(Error::GoogleGmail1(e)) => println!("Gmail API error: {}", e),
|
||||
Err(e) => println!("Other error: {}", e),
|
||||
}
|
||||
```
|
||||
|
||||
Common error types:
|
||||
- `NoLabelsFound`: Mailbox has no labels
|
||||
- `LabelNotFoundInMailbox(String)`: Specific label not found
|
||||
- `RuleNotFound(usize)`: Rule ID doesn't exist
|
||||
- `GoogleGmail1(Box<google_gmail1::Error>)`: Gmail API errors
|
||||
- `StdIO(std::io::Error)`: File I/O errors
|
||||
- `Config(config::ConfigError)`: Configuration errors
|
||||
|
||||
## Async Runtime
|
||||
|
||||
The library requires an async runtime (Tokio recommended):
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] }
|
||||
```
|
||||
|
||||
```rust path=null start=null
|
||||
#[tokio::main]
|
||||
async fn main() -> cull_gmail::Result<()> {
|
||||
// Your code here
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
## Gmail Query Syntax
|
||||
|
||||
The library supports Gmail's search syntax for message queries:
|
||||
|
||||
```rust path=null start=null
|
||||
// Date-based queries
|
||||
client.set_query("older_than:1y"); // Older than 1 year
|
||||
client.set_query("newer_than:30d"); // Newer than 30 days
|
||||
client.set_query("after:2023/1/1"); // After specific date
|
||||
|
||||
// Label-based queries
|
||||
client.set_query("label:promotions"); // Has promotions label
|
||||
client.set_query("-label:important"); // Does NOT have important label
|
||||
|
||||
// Content queries
|
||||
client.set_query("subject:newsletter"); // Subject contains "newsletter"
|
||||
client.set_query("from:noreply@example.com"); // From specific sender
|
||||
|
||||
// Combined queries
|
||||
client.set_query("label:promotions older_than:6m -is:starred");
|
||||
```
|
||||
|
||||
## Performance & Limits
|
||||
|
||||
### Pagination
|
||||
|
||||
- Default page size: 200 messages
|
||||
- Use `client.set_max_results(n)` to adjust
|
||||
- Use `client.get_messages(0)` to get all pages
|
||||
- Use `client.get_messages(n)` to limit to n pages
|
||||
|
||||
### Rate Limits
|
||||
|
||||
- The library uses the official `google-gmail1` crate
|
||||
- Built-in retry logic for transient errors
|
||||
- Respects Gmail API quotas and limits
|
||||
|
||||
### Batch Operations
|
||||
|
||||
- Batch delete/trash operations are more efficient than individual calls
|
||||
- Operations are atomic - either all succeed or all fail
|
||||
|
||||
## Logging
|
||||
|
||||
The library uses the `log` crate for logging:
|
||||
|
||||
```rust path=null start=null
|
||||
use env_logger;
|
||||
|
||||
// Initialize logging
|
||||
env_logger::init();
|
||||
|
||||
# Set log level via environment variable
|
||||
# RUST_LOG=cull_gmail=debug cargo run
|
||||
```
|
||||
|
||||
Log levels:
|
||||
- `error`: Critical errors
|
||||
- `warn`: Warnings (e.g., missing labels, dry-run mode)
|
||||
- `info`: General information (e.g., message subjects, action results)
|
||||
- `debug`: Detailed operation info
|
||||
- `trace`: Very detailed debugging info
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### OAuth2 Token Storage
|
||||
- Tokens are stored in `~/.cull-gmail/gmail1` by default
|
||||
- Tokens are automatically refreshed when expired
|
||||
- Revoke access in [Google Account settings](https://myaccount.google.com/permissions)
|
||||
|
||||
### Required Scopes
|
||||
The library requires the `https://mail.google.com/` scope for full Gmail access.
|
||||
|
||||
### OAuth2 File Security
|
||||
- Store OAuth2 credential files securely (not in version control)
|
||||
- Use restrictive file permissions (600)
|
||||
- Consider using environment variables in production
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Authentication Issues
|
||||
1. Verify OAuth2 credential file path and JSON format
|
||||
2. Check OAuth2 client is configured for "Desktop Application"
|
||||
3. Ensure redirect URI matches configuration
|
||||
4. Clear token cache: `rm -rf ~/.cull-gmail/gmail1`
|
||||
|
||||
### No Messages Found
|
||||
1. Verify label names exist: `client.show_label()`
|
||||
2. Test query syntax in Gmail web interface
|
||||
3. Check for typos in label names or query strings
|
||||
|
||||
### Rate Limiting
|
||||
1. Reduce page size: `client.set_max_results(100)`
|
||||
2. Add delays between operations
|
||||
3. Check [Gmail API quotas](https://developers.google.com/gmail/api/reference/quota)
|
||||
|
||||
## See Also
|
||||
|
||||
- [CLI Documentation](main.md) - Complete guide to the command-line interface
|
||||
- [Examples Directory](../examples/) - Additional code examples and sample configurations
|
||||
- [API Documentation](https://docs.rs/cull-gmail) - Generated API reference
|
||||
- [Repository](https://github.com/jerus-org/cull-gmail) - Source code and issue tracking
|
||||
|
||||
## License
|
||||
|
||||
By contributing to cull-gmail, you agree that your contributions will be licensed under the MIT License. This means:
|
||||
|
||||
@@ -8,7 +8,7 @@ Add the library to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
cull-gmail = "0.0.10"
|
||||
cull-gmail = "0.0.11"
|
||||
tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] }
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user