### Example Pagination Usage Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/types.md Demonstrates how to instantiate and use the PaginationOptions interface for database queries. This example shows retrieving results starting from the 41st item up to the 60th. ```typescript const pagination: PaginationOptions = { limit: 20, offset: 40 }; // Retrieves results 41-60 ``` -------------------------------- ### Integration Examples Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/cli-commands.md Provides examples of integrating Fruitmail CLI with other command-line tools for tasks like counting unread emails or exporting data. ```bash # Get unread count fruitmail unread --quiet | wc -l ``` ```bash # Export recent emails as JSON for processing fruitmail recent 7 --json > emails.json ``` ```bash # List emails with CSV for spreadsheet import fruitmail search --sender "@vendor.com" --days 90 --csv > vendor_emails.csv ``` -------------------------------- ### Example: Open Email by Lookup Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/mail-actions.md Demonstrates opening an email using a numeric ID and another example using multiple hints like message ID, mailbox hints, and subject. ```typescript import { openEmailByLookup } from './mail-actions.js'; // Open by row ID await openEmailByLookup({ numericIdCandidates: [94695] }); // Open with multiple hints await openEmailByLookup({ messageIdCandidates: ["abc123@mail.com"], mailboxHints: ["Sent Messages"], subject: "Project Update" }); ``` -------------------------------- ### Install Fruitmail with Homebrew Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/README.md Use this command to install Fruitmail if you have Homebrew installed. Ensure you tap the correct repository first. ```bash brew tap gumadeiras/tap brew install fruitmail ``` -------------------------------- ### Pagination Examples Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/cli-commands.md Demonstrates how to control the number of results returned using --offset and --limit flags. ```bash # Get first 20 results fruitmail search --subject "invoice" ``` ```bash # Get next 20 results fruitmail search --subject "invoice" --offset 20 --limit 20 ``` ```bash # Get 100 results as JSON fruitmail search --subject "invoice" --limit 100 --json ``` -------------------------------- ### Example Usage of SQLiteOptions Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/types.md Illustrates how to instantiate SQLiteDatabase with specific options. This example opens a database in read-only mode, requires the file to exist, and sets a custom busy timeout. ```typescript import { SQLiteDatabase } from './sqlite.js'; const db = new SQLiteDatabase('/path/to/Envelope Index', { readonly: true, fileMustExist: true, timeout: 5000 }); ``` -------------------------------- ### Install Fruitmail with Bash Script Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/README.md Install Fruitmail using a curl and bash command. This method has zero dependencies. ```bash curl -sSL https://raw.githubusercontent.com/gumadeiras/fruitmail-cli/master/fruitmail | bash ``` -------------------------------- ### Clone and Build Fruitmail CLI from Source Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/README.md Clone the repository, install dependencies, build the project, and run tests. This is for development purposes. ```bash git clone https://github.com/gumadeiras/fruitmail-cli.git cd fruitmail-cli npm install npm run build npm test ``` -------------------------------- ### Install ClawHub Skill Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/README.md Install the 'apple-mail-search-safe' skill for OpenClaw users via the ClawHub CLI. ```bash clawhub install apple-mail-search-safe ``` -------------------------------- ### Install Fruitmail CLI Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/SKILL.md Install the fruitmail CLI globally using npm. Requires Node.js 22.13 or newer. ```bash npm install -g fruitmail ``` -------------------------------- ### Fruitmail Search Command Example Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/cli-commands.md Demonstrates how to use the 'search' command with subject filtering, result limiting, pagination, and JSON output. ```bash fruitmail search --subject "invoice" --limit 50 --offset 20 --json ``` -------------------------------- ### Install Fruitmail CLI Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/programmatic-usage.md Install the Fruitmail package using npm. Ensure your Node.js version is compatible. ```bash npm install fruitmail ``` -------------------------------- ### Safe Mode Examples Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/cli-commands.md Illustrates safe operation modes, such as using a temporary copy with --copy or specifying an alternate database with --db. ```bash # Use --copy flag to work with a temporary copy (prevents any DB locking issues) fruitmail search --subject "test" --copy ``` ```bash # Specify alternate database fruitmail search --subject "test" --db /backup/Envelope\ Index ``` -------------------------------- ### Example Usage of SQLiteParam Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/types.md Shows how to pass different types of parameters to a prepared SQLite statement's get method. The type of parameter passed (number, string, null) affects how it's interpreted by SQLite. ```typescript const stmt = db.prepare('SELECT * FROM messages WHERE ROWID = ?'); stmt.get([94695]); // number stmt.get(['94695']); // string stmt.get([null]); // null ``` -------------------------------- ### Example MailLookupContext Object Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/mail-actions.md Illustrates the creation of a MailLookupContext object with various identification and search hint parameters. ```typescript const context: MailLookupContext = { numericIdCandidates: [12345], messageIdCandidates: ["abc123@example.com"], mailboxHints: ["Inbox"], subject: "Meeting Notes", sender: "alice@example.com" }; ``` -------------------------------- ### Execute Prepared Statement and Get First Row Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/sqlite-database.md Use the `get()` method to execute a prepared SQL statement and retrieve only the first matching row. This is useful for queries expected to return a single result, like counts or unique identifiers. ```typescript const stmt = db.prepare('SELECT COUNT(*) as count FROM messages'); const result = stmt.get(); console.log(result?.count); // e.g., 12345 ``` -------------------------------- ### JSON Output Examples Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/configuration.md Illustrates the JSON output structure for different Fruitmail commands (search, body, stats) and error responses. Use the --json flag for this format. ```json [ {"id": 94695, "date": "2024-01-15 09:30:00", "sender": "...", "subject": "..."}, ... ] ``` ```json {"id": "94695", "body": "Full email content..."} ``` ```json {"total": 12345, "unread": 67, "deleted": 234, "attachments": 5678} ``` ```json {"error": "Message not found"} ``` -------------------------------- ### Get First 20 Results Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/search-and-filtering.md Retrieves the first 20 search results. This is the default behavior when no limit or offset is specified. ```bash fruitmail search --subject "test" ``` -------------------------------- ### Example Usage of MailLookupContext Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/types.md Demonstrates how to construct and use a MailLookupContext object with the getEmailBodyByLookup function. It shows providing multiple candidate types for lookup. ```typescript import { getEmailBodyByLookup, MailLookupContext } from './mail-actions.js'; const context: MailLookupContext = { numericIdCandidates: [12345], messageIdCandidates: ["abc123@example.com"], mailboxHints: ["Inbox"], subject: "Invoice #2024-001" }; const body = await getEmailBodyByLookup(context); ``` -------------------------------- ### Get Results 101-200 Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/search-and-filtering.md Retrieves a specific range of results (100 results starting from the 101st) by setting both limit and offset. ```bash fruitmail search --subject "test" --limit 100 --offset 100 ``` -------------------------------- ### Example Usage of SQLiteRow Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/types.md Demonstrates how to fetch a row using a prepared statement and access its properties. Note that properties might be undefined if the column does not exist or has no value. ```typescript const stmt = db.prepare('SELECT ROWID, subject FROM messages WHERE unread = ?'); const row: SQLiteRow = stmt.get([0]); console.log(row.ROWID); // number console.log(row.subject); // string or undefined ``` -------------------------------- ### Complex Filter Examples Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/cli-commands.md Shows how to apply multiple filters for precise email searching, including sender, read status, attachments, and date ranges. ```bash # Unread emails from a person with PDFs in last 2 weeks fruitmail search --from-name "John" --unread --attachment-type pdf --days 14 ``` ```bash # All read emails from a company in last 6 months fruitmail search --sender "@acme.com" --read --days 180 ``` ```bash # Recent emails with attachments sent to a team fruitmail search --to "team@company.com" --has-attachment --days 30 ``` -------------------------------- ### Get 100 Results Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/search-and-filtering.md Retrieves a larger batch of 100 results by setting the limit. ```bash fruitmail search --subject "test" --limit 100 ``` -------------------------------- ### Get Next 20 Results Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/search-and-filtering.md Retrieves the next set of 20 results by specifying an offset of 20. ```bash fruitmail search --subject "test" --offset 20 ``` -------------------------------- ### Prepare and Execute SQL Statement Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/sqlite-database.md Prepare an SQL statement with placeholders and execute it using `get()` for a single row or `all()` for all matching rows. The `prepare` method returns a `SQLiteStatement` object. ```typescript const stmt = db.prepare('SELECT * FROM messages WHERE ROWID = ?'); const row = stmt.get([123]); const allRows = stmt.all(); ``` -------------------------------- ### Process JSON Search Results with jq Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/search-and-filtering.md An example of piping JSON search results to `jq` to extract specific fields (email IDs) and then taking the first 5 results. ```bash fruitmail search --subject "invoice" --json | jq '.[] | .id' | head -5 ``` -------------------------------- ### Execute Prepared Statement and Get All Rows Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/sqlite-database.md Use the `all()` method to execute a prepared SQL statement and retrieve all resulting rows. It accepts query parameters as an array or a single value. ```typescript const stmt = db.prepare('SELECT * FROM messages WHERE deleted = ?'); const undeleted = stmt.all([0]); // or with single param: const same = stmt.all(0); ``` -------------------------------- ### Find Bank Statements Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/SKILL.md Example of finding emails with 'statement' in the subject from the last 30 days. Demonstrates combining subject and date filters. ```bash fruitmail search --subject "statement" --days 30 ``` -------------------------------- ### Robust Query with Error Handling Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/programmatic-usage.md This example shows how to implement robust error handling for database queries. It specifically catches and provides user-friendly messages for common errors like permission issues, database not found, or database locking. This function requires the 'fruitmail/dist/db-finder.js' module. ```typescript import { findDbPath } from 'fruitmail/dist/db-finder.js'; async function robustQuery() { try { const dbPath = await findDbPath(); const db = new SQLiteDatabase(dbPath); try { const result = db.prepare('SELECT COUNT(*) as c FROM messages').get(); console.log(result?.c); } finally { db.close(); } } catch (error) { if (error instanceof Error) { if (error.message.includes('Permission denied')) { console.error('Grant Full Disk Access to Terminal in System Settings'); } else if (error.message.includes('Could not find')) { console.error('Mail.app database not found'); } else if (error.message.includes('database is locked')) { console.error('Database is locked. Try using --copy mode'); } else { console.error('Error:', error.message); } } process.exit(1); } } ``` -------------------------------- ### Validate Non-Negative Integer CLI Arguments Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/errors.md Example of CLI output when a non-negative integer option like --limit or --days is provided with invalid input. ```bash fruitmail search --limit "abc" # Error: Invalid --limit: expected a non-negative integer fruitmail search --days -5 # Error: Invalid --days: expected a non-negative integer ``` -------------------------------- ### Permission Denied Error Message Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/db-finder.md Example error message displayed when Full Disk Access is not granted to Terminal or Node.js, preventing access to the Mail database directory. ```text Permission denied accessing /Users/username/Library/Mail. Please grant Terminal 'Full Disk Access' in System Settings. ``` -------------------------------- ### Get Table Columns using PRAGMA table_info() Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/database-schema.md This function retrieves the names of all columns for a specified table in a SQLite database. It's useful for dynamically adapting to different database schema versions. ```typescript function getTableColumns(db: SQLiteDatabase, tableName: string): string[] { const rows = db.prepare(`PRAGMA table_info(${tableName})`).all() as Array<{ name: string }>; return rows.map(row => row.name); } const messageColumns = getTableColumns(db, 'messages'); console.log(messageColumns); // ['ROWID', 'subject', 'sender', 'date_sent', 'read', 'deleted', 'mailbox', ...] ``` -------------------------------- ### Get Email Body with Multiple ID Candidates and Hints Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/programmatic-usage.md Fetches an email body by providing multiple types of identifiers (numeric, message ID) along with mailbox hints, subject, and sender for more specific lookups. ```typescript const body = await getEmailBodyByLookup({ numericIdCandidates: [12345, 12346], messageIdCandidates: ["abc123@example.com"], mailboxHints: ["Inbox"], subject: "Invoice #2024-001", sender: "billing@amazon.com" }); ``` -------------------------------- ### Fruitmail CLI Entry Point Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/api-reference-index.md Illustrates the build process and execution flow for the Fruitmail CLI tool, showing the relationship between the source code, compiled JavaScript, and the executable binary. ```bash bin/fruitmail → dist/index.js (built from src/index.ts) ``` -------------------------------- ### Show Fruitmail CLI Help Information Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/cli-commands.md Access help documentation for the main command or specific subcommands using the --help flag. ```bash fruitmail --help ``` ```bash fruitmail search --help ``` ```bash fruitmail body --help ``` -------------------------------- ### Execute Full Release Process Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/README.md Automates the release process by bumping versions, running tests, packaging artifacts, tagging, pushing to remote, waiting for CI, publishing to npm, and updating Homebrew. ```bash ./scripts/release run 1.1.1 ``` -------------------------------- ### Export large result sets with pagination Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/search-and-filtering.md Demonstrates exporting large result sets by using a limit and looping with an offset. This is an optimization tip for handling thousands of results. ```bash fruitmail unread --limit 1000 --offset 0 fruitmail unread --limit 1000 --offset 1000 ``` -------------------------------- ### Verify and Run Release Tests Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/README.md This script checks for synced release versions across different components and runs the release test gates before proceeding with a release. ```bash ./scripts/release check 1.1.1 ``` -------------------------------- ### Get Messages in Inbox Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/database-schema.md Finds the ROWIDs of messages that belong to the 'Inbox' mailbox, based on its display name. ```sql SELECT m.ROWID FROM messages m LEFT JOIN mailboxes mb ON m.mailbox = mb.ROWID WHERE mb.display_name = 'Inbox'; ``` -------------------------------- ### Run Fruitmail CLI from Source Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/README.md Execute the Fruitmail CLI directly from the source code after building. Useful for testing changes during development. ```bash node bin/fruitmail search --subject "test" ``` -------------------------------- ### prepare() Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/sqlite-database.md Prepares an SQL statement for execution. This method takes an SQL query string and returns a prepared statement object that can be used to execute the query. ```APIDOC ## prepare(sql) ### Description Prepares an SQL statement for execution, allowing for simplified prepared statement execution with automatic parameter normalization. ### Method `prepare` ### Parameters #### Path Parameters - **sql** (string) - Required - SQL query string with optional `?` placeholders for parameters ### Returns - `SQLiteStatement` — prepared statement object with `all()` and `get()` methods ### Example ```typescript const stmt = db.prepare('SELECT * FROM messages WHERE ROWID = ?'); const row = stmt.get([123]); const allRows = stmt.all(); ``` ``` -------------------------------- ### Initialize SQLiteDatabase Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/sqlite-database.md Instantiate SQLiteDatabase with a file path and optional configuration. Use `readonly` to open in read-only mode, `fileMustExist` to ensure the database file exists, and `timeout` for busy timeouts. ```typescript import { SQLiteDatabase } from './sqlite.js'; const db = new SQLiteDatabase('/path/to/Envelope Index', { readonly: true, fileMustExist: true, timeout: 2000 }); ``` -------------------------------- ### Basic Search Command with Global Options Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/configuration.md Perform a search for emails with the subject 'test' and limit the results to 50, outputting in JSON format. This demonstrates the use of global CLI options. ```bash fruitmail search --subject "test" --limit 50 --json ``` -------------------------------- ### Initialize and Query Database as Library Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/00-START-HERE.md Find the database path, initialize a SQLiteDatabase instance, and prepare a query to retrieve unread messages. ```typescript import { findDbPath } from 'fruitmail/dist/db-finder.js'; import { SQLiteDatabase } from 'fruitmail/dist/sqlite.js'; const dbPath = await findDbPath(); const db = new SQLiteDatabase(dbPath); const unread = db.prepare( 'SELECT * FROM messages WHERE read = 0' ).all(); ``` -------------------------------- ### Fruitmail CLI Architecture Overview Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/README.md This diagram illustrates the architecture of the Fruitmail CLI, showing the interaction between the CLI, database finder, mail actions, and the SQLite wrapper, ultimately connecting to the Apple Mail.app SQLite database. ```text ┌─────────────────────────────────────────────────────────────┐ │ fruitmail CLI (index.ts) │ │ - Command definitions (search, body, open, stats, etc.) │ │ - Option parsing and validation │ │ - Output formatting (table, JSON, CSV) │ └────────────┬────────────────────────────┬──────────────────┘ │ │ ┌──────▼────────┐ ┌────────▼───────────┐ │ db-finder.ts │ │ mail-actions.ts │ │ (database │ │ (AppleScript) │ │ discovery) │ │ │ └──────┬────────┘ │ - getEmailBody() │ │ │ - openEmail() │ └───────────┬──────┬┘ │ ┌───▼──────▼────┐ │ │ sqlite.ts │ │ │ (SQLite │ │ │ wrapper) │ │ └───┬───────────┘ │ │ │ ┌────────────────────┴─────────────────────────┘ │ ▼ ~/Library/Mail/V11/MailData/Envelope Index (SQLite database) ``` -------------------------------- ### Error Recovery for Mail Lookup Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/mail-actions.md Example of how to catch and handle specific errors, such as 'Message not found' or general AppleScript errors, when retrieving email content. ```typescript try { const body = await getEmailBodyByLookup({ numericIdCandidates: [999999] }); } catch (error) { if (error.message === 'Message not found') { console.log('Email was deleted or moved'); } else { console.log('AppleScript error:', error.message); } } ``` -------------------------------- ### Get Email Body by Message ID Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/mail-actions.md Retrieves the body of an email using its numeric message ID. This is a legacy function and only supports numeric IDs. ```typescript export async function getEmailBody(messageId: string): Promise ``` -------------------------------- ### Get Unread Emails as JSON Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/SKILL.md Retrieve unread emails and pipe the JSON output to `jq` to extract only the subjects. Useful for scripting and data processing. ```bash fruitmail unread --json | jq '.[] | .subject' ``` -------------------------------- ### Paginate Through Search Results Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/search-and-filtering.md Demonstrates a loop to fetch search results in batches of 20, iterating through different offsets. The --json flag is used for programmatic processing. ```bash for offset in 0 20 40 60; do fruitmail search --subject "report" --offset $offset --limit 20 --json done ``` -------------------------------- ### Get Full Email Body by Numeric ID Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/programmatic-usage.md Fetches the complete body of an email using its numeric ID. Includes error handling for 'Message not found'. ```typescript import { getEmailBodyByLookup } from 'fruitmail/dist/mail-actions.js'; try { const body = await getEmailBodyByLookup({ numericIdCandidates: [94695] }); console.log(body); } catch (error) { if (error.message === 'Message not found') { console.log('Email not found'); } else { console.error('Failed to fetch body:', error.message); } } ``` -------------------------------- ### Get Email Body by Numeric ID Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/mail-actions.md Retrieves the email body using a simple numeric ID. This is a common use case for direct message identification. ```typescript import { getEmailBodyByLookup } from './mail-actions.js'; // Simple numeric ID lookup const body = await getEmailBodyByLookup({ numericIdCandidates: [94695] }); console.log(body); ``` -------------------------------- ### Perform Local Release Preflight Check Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/AGENTS.md Checks for local preflight conditions before a release. ```bash ./scripts/release check ``` -------------------------------- ### Get Email Body by ID (TypeScript) Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/README.md Fetches the email body using a provided numeric ID. This function is part of the mail-actions module and requires the `getEmailBodyByLookup` function. ```typescript import { getEmailBodyByLookup } from 'fruitmail/dist/mail-actions.js'; const body = await getEmailBodyByLookup({ numericIdCandidates: [94695] }); ``` -------------------------------- ### Stage Paths and Commit Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/README.md A script utility for staging specific file paths and creating a commit with a provided message. Useful for granular version control. ```bash ./scripts/committer "message" path... ``` -------------------------------- ### Display Fruitmail CLI Version Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/cli-commands.md Use the --version or -V flag to display the current version of the Fruitmail CLI, as defined in package.json. ```bash fruitmail --version ``` ```bash fruitmail -V ``` -------------------------------- ### Get Column Count for a SQLite Table Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/database-schema.md This SQL query counts the number of columns in a specified table using the PRAGMA table_info function. Replace 'messages' with your target table name. ```sql SELECT COUNT(*) FROM PRAGMA_table_info('messages'); ``` -------------------------------- ### Get Email Body with Mailbox Hints Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/README.md Attempts to retrieve an email body using a numeric ID and provides mailbox hints to help locate the message. This is useful when a direct lookup fails. ```javascript getEmailBodyByLookup({ numericIdCandidates: [id], mailboxHints: ['Inbox'] }) ``` -------------------------------- ### Safe Mode Query with Database Copy Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/programmatic-usage.md This snippet demonstrates how to perform a query safely by copying the database to a temporary file. This prevents accidental corruption of the original database. Ensure you have the necessary file system permissions. ```typescript import { copyFileSync, unlinkSync } from 'node:fs'; import os from 'node:os'; import path from 'node:path'; async function safeQuery(callback) { const dbPath = await findDbPath(); // Copy to temp file const tempPath = path.join(os.tmpdir(), `fruitmail.${Date.now()}.db`); copyFileSync(dbPath, tempPath); try { const db = new SQLiteDatabase(tempPath); return callback(db); } finally { db.close(); unlinkSync(tempPath); // Clean up } } // Usage const result = await safeQuery((db) => { return db.prepare('SELECT COUNT(*) as c FROM messages').get(); }); ``` -------------------------------- ### Get Email Body by ID and Save to File Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/README.md Retrieves the body of a specific email using its numeric ID and saves the content to a text file. Replace '94695' with the actual message ID. ```bash fruitmail body 94695 > message.txt ``` -------------------------------- ### Fruitmail CLI Search Commands Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/00-START-HERE.md Demonstrates default read-only search and safe copy mode for Fruitmail CLI. ```bash fruitmail search --subject "test" # Read-only (default) ``` ```bash fruitmail search --subject "test" --copy # Safe copy mode ``` -------------------------------- ### Get Email Body with Fallback Hints Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/mail-actions.md Retrieves the email body using a combination of IDs and fallback hints like subject, sender, and mailbox. This demonstrates the function's flexibility in locating messages. ```typescript import { getEmailBodyByLookup } from './mail-actions.js'; // With fallback hints const body2 = await getEmailBodyByLookup({ numericIdCandidates: [12345], messageIdCandidates: ["abc123@mail.com"], mailboxHints: ["Inbox"], subject: "Invoice #2024-001", sender: "billing@amazon.com" }); ``` -------------------------------- ### Run Release After Approval Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/AGENTS.md Executes the release process only after explicit approval. ```bash ./scripts/release run ``` -------------------------------- ### Find Database Path and Query Messages in TypeScript Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/INDEX.md This code snippet demonstrates how to find the Fruitmail database path and query unread messages using the SQLiteDatabase class in a TypeScript/Node.js application. Ensure 'fruitmail' is installed and configured. ```typescript import { findDbPath } from 'fruitmail/dist/db-finder.js'; import { SQLiteDatabase } from 'fruitmail/dist/sqlite.js'; const dbPath = await findDbPath(); const db = new SQLiteDatabase(dbPath); const results = db.prepare('SELECT * FROM messages WHERE read = 0').all(); ``` -------------------------------- ### Open SQLite Database Connection Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/programmatic-usage.md Establishes a connection to the SQLite database with specified options. Ensure the database is closed after use. ```typescript import { SQLiteDatabase } from 'fruitmail/dist/sqlite.js'; const db = new SQLiteDatabase(dbPath, { readonly: true, fileMustExist: true, timeout: 2000 }); try { // Use database } finally { db.close(); } ``` -------------------------------- ### Check Available Columns in Messages Table Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/database-schema.md Uses the PRAGMA command to inspect the schema and list all columns for the 'messages' table. ```sql PRAGMA table_info(messages); ``` -------------------------------- ### Safe Mode Database Query with --copy Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/configuration.md Perform queries on a temporary copy of the database to ensure the original remains untouched. This is recommended when Mail.app is active or for added safety. ```bash # Safe mode for production queries fruitmail search --subject "invoice" --copy # Explicitly use read-only on original fruitmail search --subject "invoice" ``` -------------------------------- ### SQLiteDatabase Constructor Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/sqlite-database.md Initializes a new SQLiteDatabase instance. It can be configured with options such as read-only mode, file existence requirement, and busy timeout. ```APIDOC ## new SQLiteDatabase(filePath, options?) ### Description Initializes a new SQLiteDatabase instance, providing a synchronous wrapper around Node.js native DatabaseSync. ### Parameters #### Path Parameters - **filePath** (string) - Required - Absolute path to SQLite database file #### Query Parameters - **options** (SQLiteOptions) - Optional - Configuration options - **readonly** (boolean) - Optional - Open database in read-only mode (Default: false) - **fileMustExist** (boolean) - Optional - Throw if file does not exist (Default: false) - **timeout** (number) - Optional - Busy timeout in milliseconds (Default: 2000) ### Throws - `Error` if `fileMustExist` is true and the file does not exist at the given path. ### Example ```typescript import { SQLiteDatabase } from './sqlite.js'; const db = new SQLiteDatabase('/path/to/Envelope Index', { readonly: true, fileMustExist: true, timeout: 2000 }); ``` ``` -------------------------------- ### Define QueryOptions Interface Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/types.md Defines the structure for global command-line options used in the Fruitmail CLI. All values are strings as parsed from arguments. ```typescript interface QueryOptions { limit: string; offset: string; json?: boolean; csv?: boolean; quiet?: boolean; db?: string; copy?: boolean; } ``` -------------------------------- ### Override Database Path with --db Option Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/configuration.md Specify a custom database file path directly via the --db command-line option. This option has the highest precedence, overriding environment variables and auto-detection. ```bash fruitmail search --subject "test" --db /backup/Envelope\ Index ``` -------------------------------- ### Stage Specific Paths for Commit Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/AGENTS.md Stages only the listed paths for a commit. Use `--body` or `--body-file` for commit bodies. ```bash scripts/committer "" -- ... ``` -------------------------------- ### No Results Found Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/search-and-filtering.md Shows the output when a search yields no results. The default output displays a message, while `--quiet` suppresses all output, and `--json` returns an empty array. ```bash fruitmail search --subject "xyzabc1234" # (default) No results found. fruitmail search --subject "xyzabc1234" --quiet # (no output) fruitmail search --subject "xyzabc1234" --json # [] ``` -------------------------------- ### Search Emails via CLI Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/00-START-HERE.md Use the 'search' command to find emails based on subject and date. ```bash fruitmail search --subject "invoice" --days 30 ``` -------------------------------- ### Basic Search Command Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/search-and-filtering.md The `search` command is the unified interface for querying the Mail database. All filter options are optional and can be combined. ```bash fruitmail search [OPTIONS] ``` -------------------------------- ### Search with Custom Limit Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/configuration.md Retrieve a specific number of search results by setting the --limit option. This is useful for controlling the amount of data returned. ```bash fruitmail search --subject "invoice" --limit 100 ``` -------------------------------- ### Open Email by Lookup Context Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/mail-actions.md Opens an email in Mail.app by providing a context object with various lookup hints. Use this for flexible email identification. ```typescript export async function openEmailByLookup(context: MailLookupContext): Promise ``` -------------------------------- ### Handle Non-Existent Database File Error Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/errors.md Demonstrates the error that occurs when attempting to open a SQLite database with `fileMustExist: true` and the file is not present. ```typescript import { SQLiteDatabase } from './sqlite.js'; const db = new SQLiteDatabase('/invalid/path', { fileMustExist: true }); // Error: Database file does not exist: /invalid/path ``` -------------------------------- ### Check SQLite Table Indexes Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/database-schema.md Use this PRAGMA command to list all indexes associated with a specific table. Understanding indexes is crucial for query performance optimization. Replace 'messages' with your target table name. ```sql PRAGMA index_list(messages); ``` -------------------------------- ### Backup Fruitmail Database Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/configuration.md This script backs up the Fruitmail database by copying the index file to a backup directory. It includes a timestamp in the backup filename for easy identification. ```bash MAIL_DB="$HOME/Library/Mail/V11/MailData/Envelope Index" cp "$MAIL_DB" "$HOME/backup/Mail-$(date +%Y%m%d).db" ``` -------------------------------- ### List Unread Emails using Shortcut Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/search-and-filtering.md Use the 'unread' shortcut command to quickly display all unread emails. This is a shorthand for 'fruitmail search --unread'. ```bash fruitmail unread # Usage examples: fruitmail unread --limit 50 fruitmail unread --json fruitmail unread --quiet | wc -l # Count unread ``` -------------------------------- ### Table Output Format Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/cli-commands.md Displays email search results in a human-readable table format. This is the default output. ```bash ID Date Sender Subject 94695 2024-01-15 09:30:00 alice@example.com Meeting Notes 94694 2024-01-14 14:22:00 bob@example.com Project Update ``` -------------------------------- ### SQL Equivalent for Complex Search Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/search-and-filtering.md This SQL query demonstrates how a complex Fruitmail CLI search, involving multiple criteria like subject, sender, date, read status, and attachments, can be represented. ```sql SELECT ... FROM messages m LEFT JOIN subjects s ON m.subject = s.ROWID LEFT JOIN addresses a ON m.sender = a.ROWID LEFT JOIN recipients r ON m.ROWID = r.message LEFT JOIN addresses ra ON r.address = ra.ROWID LEFT JOIN attachments att ON m.ROWID = att.message WHERE m.deleted = 0 AND s.subject LIKE '%report%' AND a.address LIKE '%@company.com%' AND m.date_sent >= (unix_timestamp - 2592000) AND m.read = 0 AND att.name LIKE '%.pdf%' ORDER BY m.date_sent DESC LIMIT 20 OFFSET 0; ``` -------------------------------- ### Search by Sender using Shortcut Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/search-and-filtering.md Use the 'sender' shortcut command to find emails sent from a specific address or domain. This is a convenient alternative to the 'search --sender' command. ```bash fruitmail sender "@github.com" # Usage examples: fruitmail sender "alice" --limit 100 fruitmail sender "notifications" --csv ``` -------------------------------- ### Export Search Results to JSON via CLI Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/00-START-HERE.md Use the 'search' command with the '--json' flag to export results in JSON format. ```bash fruitmail search --sender "@company.com" --json ``` -------------------------------- ### View Database Statistics Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/SKILL.md Display statistics about the Mail.app database. Useful for understanding database size and health. ```bash fruitmail stats ``` -------------------------------- ### List Attachment Names Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/database-schema.md Lists up to 100 distinct attachment names, filtering for those ending in '.pdf'. ```sql SELECT DISTINCT name FROM attachments WHERE name LIKE '%.pdf' LIMIT 100; ``` -------------------------------- ### Find Database Path Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/programmatic-usage.md Locates the Fruitmail database path. This can be overridden using the MAIL_DB environment variable. ```typescript import { findDbPath } from 'fruitmail/dist/db-finder.js'; const dbPath = await findDbPath(); console.log(`Database location: ${dbPath}`); // Output: /Users/username/Library/Mail/V11/MailData/Envelope Index ``` ```bash export MAIL_DB=/custom/path/to/database # Then in code: const dbPath = await findDbPath(); // Returns /custom/path/to/database ``` -------------------------------- ### Search by Sender Shortcut Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/cli-commands.md Quickly search for emails from a specific sender or domain. Defaults to searching within the last 7 days. ```bash fruitmail sender "" ``` ```bash fruitmail sender "@github.com" ``` -------------------------------- ### Search with Copy Flag Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/README.md Performs a search for emails with the subject 'test' while using the `--copy` flag. This flag creates a temporary copy of the database before querying, which can prevent 'database is locked' errors. ```bash fruitmail search --copy --subject "test" ``` -------------------------------- ### Combine Multiple Search Filters Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/search-and-filtering.md Use multiple flags with the 'search' command to combine filters. All specified conditions must be met for a message to be returned. This is useful for precise message retrieval. ```bash # All three conditions must be true: fruitmail search --subject "invoice" --sender "@amazon.com" --unread # Returns: unread emails from amazon.com with "invoice" in subject # Complex filter: fruitmail search \ --subject "report" \ --sender "@company.com" \ --days 30 \ --unread \ --attachment-type pdf # Returns: unread emails from company.com received in last 30 days # with "report" in subject and PDF attachments ``` -------------------------------- ### Open Email in Mail.app Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/cli-commands.md Opens a specific email in the default Mail.app and brings the application to the foreground. Requires the email's ID. ```bash fruitmail open ``` ```bash fruitmail open 94695 # Opens email in Mail.app ``` -------------------------------- ### List All Tables in SQLite Database Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/database-schema.md Use this SQL query to retrieve a list of all table names within the SQLite database. This is useful for understanding the overall database structure. ```sql SELECT name FROM sqlite_master WHERE type='table' ORDER BY name; ``` -------------------------------- ### Search by Subject Shortcut Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/cli-commands.md Quickly search for emails containing a specific pattern in the subject line. Defaults to searching within the last 7 days. ```bash fruitmail subject "" ``` ```bash fruitmail subject "invoice" ``` -------------------------------- ### Page Through Search Results Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/SKILL.md Retrieve search results for 'invoice' with a limit of 20 and offset of 20, effectively paginating through results. Useful for handling large result sets. ```bash fruitmail search --subject "invoice" --limit 20 --offset 20 ``` -------------------------------- ### Find Apple Mail Database Path Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/db-finder.md Locates the Mail database by scanning standard paths. Requires Full Disk Access. Throws errors if the database is not found or permissions are insufficient. ```typescript export async function findDbPath(): Promise ``` ```typescript import { findDbPath } from './db-finder.js'; try { const dbPath = await findDbPath(); console.log(`Found Mail database at: ${dbPath}`); // Output: /Users/username/Library/Mail/V11/MailData/Envelope Index } catch (error) { console.error(error.message); // Handle permission or not-found errors } ``` -------------------------------- ### Paginate Search Results Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/configuration.md Skip a specified number of results before returning the limited set, enabling pagination. This is useful for retrieving data in chunks. ```bash # Get results 21-40 fruitmail search --subject "invoice" --offset 20 --limit 20 ``` -------------------------------- ### Handle Table or Column Not Found Error Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/errors.md Shows an error resulting from referencing a non-existent table in a SQL query. ```typescript const stmt = db.prepare('SELECT * FROM invalid_table'); // Error: no such table: invalid_table ``` -------------------------------- ### TypeScript Types for Mail Lookup and SQLite Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/programmatic-usage.md Demonstrates importing and using TypeScript types for MailLookupContext and SQLiteOptions. These types help ensure type safety when interacting with Fruitmail's database and mail functionalities. ```typescript import { MailLookupContext } from 'fruitmail/dist/mail-actions.js'; import { SQLiteOptions, SQLiteRow, SQLiteParam } from 'fruitmail/dist/sqlite.js'; const context: MailLookupContext = { numericIdCandidates: [12345], messageIdCandidates: ["abc@example.com"], subject: "Test" }; const options: SQLiteOptions = { readonly: true, fileMustExist: true, timeout: 5000 }; ``` -------------------------------- ### Handle SQL Syntax Error Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/errors.md Illustrates a SQL syntax error that occurs when a malformed query is prepared. ```typescript const stmt = db.prepare('SELECT * FROM messages WHRE unread = ?'); // Error: near "WHRE": syntax error ``` -------------------------------- ### Define Pagination Options Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/types.md Defines the structure for pagination parameters, specifying the number of results to return and the number of results to skip. Use this for controlling database query limits and offsets. ```typescript interface PaginationOptions { limit: number; offset: number; } ``` -------------------------------- ### Handle Mail Database Not Found Error Source: https://github.com/gumadeiras/fruitmail-cli/blob/main/_autodocs/errors.md Catch and inform the user when the Mail database cannot be found, suggesting checks for Full Disk Access permissions. ```typescript import { findDbPath } from './db-finder.js'; try { const dbPath = await findDbPath(); } catch (error) { if (error.message.includes('Could not find Mail database')) { console.error('Mail database not found. Check Full Disk Access permissions.'); } } ```